source: src/Virtual/VirtualDtor.cpp @ cad8c88

Last change on this file since cad8c88 was fc1a3e2, checked in by Andrew Beach <ajbeach@…>, 3 months ago

Style update. Focused on indentation and trailing whitespace.

  • Property mode set to 100644
File size: 12.8 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// VirtualDtor.cpp -- generate code needed by the actor system
8//
9// Author           : Colby Parsons
10// Created On       : Tues Mar 14 15:16:42 2023
11// Last Modified By : Colby Parsons
12// Last Modified On : Tues Mar 14 15:16:42 2023
13// Update Count     : 0
14//
15
16#include "AST/Print.hpp"
17#include "AST/Decl.hpp"
18#include "AST/Pass.hpp"
19#include "AST/Type.hpp"
20#include "AST/Stmt.hpp"
21#include "AST/TranslationUnit.hpp"
22#include "AST/Expr.hpp"
23#include <algorithm>
24using namespace ast;
25using namespace std;
26
27namespace Virtual {
28
29struct CtorDtor {
30        FunctionDecl * dtorSetup;  // dtor init routine to add after last dtor for a struct
31        FunctionDecl * deleteFn;
32        FunctionDecl * lastDtor;    // pointer to last occurence of dtor to know where to insert after
33
34        CtorDtor() : dtorSetup(nullptr), deleteFn(nullptr), lastDtor(nullptr) {}
35};
36
37class CtorDtorTable {
38        unordered_map<const StructDecl *, CtorDtor> & structMap;
39
40public:
41        // if dtor is last dtor for this decl return the routine to add afterwards
42        // otherwise return nullptr
43        FunctionDecl * getToAddLater( const StructDecl * decl, FunctionDecl * dtor, FunctionDecl ** retDeleteFn ) {
44                auto iter = structMap.find( decl );
45                if ( iter == structMap.end() || iter->second.lastDtor != dtor ) return nullptr; // check if this is needed
46                *retDeleteFn = iter->second.deleteFn;
47                return iter->second.dtorSetup;
48        }
49
50        // return if the dtorSetup field has been defined for this decl
51        bool inTable( const StructDecl * decl ) {
52                auto iter = structMap.find( decl );
53                return iter->second.dtorSetup != nullptr;
54        }
55
56        void addLater( const StructDecl * decl, FunctionDecl * dtorSetup, FunctionDecl * deleteFn ) {
57                auto iter = structMap.find( decl );
58                iter->second.dtorSetup = dtorSetup;
59                iter->second.deleteFn = deleteFn;
60        }
61
62        void addDtor( const StructDecl * decl, FunctionDecl * dtor ) {
63                auto iter = structMap.find( decl );
64                iter->second.lastDtor = dtor;
65        }
66
67        CtorDtorTable( unordered_map<const StructDecl *, CtorDtor> & structMap ) : structMap(structMap) {}
68};
69
70struct CollectStructDecls : public ast::WithGuards {
71        unordered_map<const StructDecl *, CtorDtor> & structDecls;
72        StructDecl * parentDecl;
73        bool insideStruct = false;
74        bool namedDecl = false;
75
76        const StructDecl ** virtualDtor;
77
78        // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
79        void previsit( const StructDecl * decl ) {
80                if ( !decl->body ) return;
81                if( decl->name == "virtual_dtor" ) {
82                        structDecls.emplace( make_pair( decl, CtorDtor() ) );
83                        *virtualDtor = decl;
84                } else {
85                        GuardValue(insideStruct);
86                        insideStruct = true;
87                        parentDecl = mutate( decl );
88                }
89        }
90
91        // this catches structs of the form:
92        //     struct derived_type { virtual_dtor a; };
93        // since they should be:
94        //     struct derived_type { inline virtual_dtor; };
95        void previsit ( const ObjectDecl * decl ) {
96                if ( insideStruct && ! decl->name.empty() ) {
97                        GuardValue(namedDecl);
98                        namedDecl = true;
99                }
100        }
101
102        // this collects the derived actor and message struct decl ptrs
103        void postvisit( const StructInstType * node ) {
104                if ( ! *virtualDtor ) return;
105                if ( insideStruct && !namedDecl ) {
106                        auto structIter = structDecls.find( node->aggr() );
107                        if ( structIter != structDecls.end() )
108                                structDecls.emplace( make_pair( parentDecl, CtorDtor() ) );
109                }
110        }
111
112  public:
113        CollectStructDecls( unordered_map<const StructDecl *, CtorDtor> & structDecls, const StructDecl ** virtualDtor ):
114                structDecls( structDecls ), virtualDtor(virtualDtor) {}
115};
116
117// generates the forward decl of virtual dtor setting routine and delete routine
118// generates the call to the virtual dtor routine in each appropriate ctor
119// collects data needed for next pass that does the circular defn resolution
120//     for dtor setters and delete fns (via table above)
121struct GenFuncsCreateTables : public ast::WithDeclsToAdd<> {
122        unordered_map<const StructDecl *, CtorDtor> & structDecls;
123        CtorDtorTable & torDecls;
124        const StructDecl ** virtualDtor;
125
126        // collects the dtor info for actors/messages
127        // gens the dtor fwd decl and dtor call in ctor
128        void previsit( const FunctionDecl * decl ) {
129                if ( (decl->name != "?{}" && decl->name != "^?{}") || decl->params.size() == 0
130                        || !decl->stmts || (decl->name == "^?{}" && decl->params.size() != 1)) return;
131
132                // the first param should be a reference
133                const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
134                if ( !ref ) return;
135
136                // the reference should be to a struct instance
137                const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
138                if ( !instType ) return;
139
140                // return if not ctor/dtor for an actor or message
141                auto structIter = structDecls.find( instType->aggr() );
142                if ( structIter == structDecls.end() ) return;
143
144                // If first param not named we need to name it to use it
145                if ( decl->params.at(0)->name == "" )
146                        mutate( decl->params.at(0).get() )->name = "__CFA_Virt_Dtor_param";
147
148                if ( decl->name == "^?{}") {
149                        torDecls.addDtor( structIter->first, mutate( decl ) );
150
151                        CompoundStmt * dtorBody = mutate( decl->stmts.get() );
152                        // Adds the following to the start of any actor/message dtor:
153                        //  __CFA_dtor_shutdown( this );
154                        dtorBody->push_front(
155                                new IfStmt( decl->location,
156                                        new UntypedExpr (
157                                                decl->location,
158                                                new NameExpr( decl->location, "__CFA_dtor_shutdown" ),
159                                                {
160                                                        new NameExpr( decl->location, decl->params.at(0)->name )
161                                                }
162                                        ),
163                                        new ReturnStmt( decl->location, nullptr )
164                                )
165                        );
166                        return;
167                }
168
169                // not dtor by this point so must be ctor
170                CompoundStmt * ctorBody = mutate( decl->stmts.get() );
171                // Adds the following to the end of any actor/message ctor:
172                //  __CFA_set_dtor( this );
173                ctorBody->push_back( new ExprStmt(
174                        decl->location,
175                        new UntypedExpr (
176                                decl->location,
177                                new NameExpr( decl->location, "__CFA_set_dtor" ),
178                                {
179                                        new NameExpr( decl->location, decl->params.at(0)->name )
180                                }
181                        )
182                ));
183
184                if ( torDecls.inTable( structIter->first ) ) return;
185
186                // Generates the following:
187                // void __CFA_set_dtor( Derived_type & this ){
188                //     void (*__my_dtor)( Derived_type & ) = ^?{};
189                //     this.__virtual_dtor = (void (*)( Base_type & ))__my_dtor;
190                //     this.__virtual_obj_start = (void *)(&this);
191                // }
192                CompoundStmt * setDtorBody = new CompoundStmt( decl->location );
193
194                // Function type is: (void (*)(Derived_type &))
195                FunctionType * derivedDtor = new FunctionType();
196                derivedDtor->params.push_back( ast::deepCopy( ref ) );
197
198                // Generates:
199                //      void (*__my_dtor)( Derived_type & ) = ^?{};
200                setDtorBody->push_back( new DeclStmt(
201                        decl->location,
202                        new ObjectDecl(
203                                decl->location,
204                                "__my_dtor",
205                                new PointerType( derivedDtor ),
206                                new SingleInit( decl->location, new NameExpr( decl->location, "^?{}" ) )
207                        )
208                ));
209
210                // Function type is: (void (*)( Base_type & ))
211                FunctionType * baseDtor = new FunctionType();
212                baseDtor->params.push_back( new ReferenceType( new StructInstType( *virtualDtor ) ) );
213
214                // Generates:
215                //     __CFA_set_virt_dtor( this, (void (*)( Base_type & ))__my_dtor )
216                setDtorBody->push_back( new ExprStmt(
217                        decl->location,
218                        new UntypedExpr (
219                                decl->location,
220                                new NameExpr( decl->location, "__CFA_set_virt_dtor" ),
221                                {
222                                        new NameExpr( decl->location, "this" ),
223                                        new CastExpr( decl->location, new NameExpr( decl->location, "__my_dtor" ), new PointerType( baseDtor ), ExplicitCast )
224                                }
225                        )
226                ));
227
228                // Generates:
229                //     __CFA_set_virt_start( (void *)(&this) );
230                setDtorBody->push_back( new ExprStmt(
231                        decl->location,
232                        new UntypedExpr (
233                                decl->location,
234                                new NameExpr( decl->location, "__CFA_set_virt_start" ),
235                                {
236                                        new NameExpr( decl->location, "this" ),
237                                        new CastExpr(
238                                                decl->location,
239                                                new AddressExpr( decl->location, new NameExpr( decl->location, "this" )),
240                                                new PointerType( new ast::VoidType() ), ExplicitCast
241                                                )
242                                }
243                        )
244                ));
245
246                // put it all together into the complete function decl from above
247                FunctionDecl * setDtorFunction = new FunctionDecl(
248                        decl->location,
249                        "__CFA_set_dtor",
250                        {
251                                new ObjectDecl(
252                                        decl->location,
253                                        "this",
254                                        ast::deepCopy( ref )
255                                ),
256                        },                      // params
257                        {},
258                        nullptr,               // body
259                        { Storage::Static },    // storage
260                        Linkage::Cforall,       // linkage
261                        {},                     // attributes
262                        { Function::Inline }
263                );
264
265                declsToAddBefore.push_back( ast::deepCopy( setDtorFunction ) );
266
267                setDtorFunction->stmts = setDtorBody;
268
269                // The following generates the following specialized delete routine:
270                // static inline void delete( derived_type * ptr ) {
271                //     if ( ptr )
272                //         ^(*ptr){};
273                //     __CFA_virt_free( *ptr );
274                // }
275                CompoundStmt * deleteFnBody = new CompoundStmt( decl->location );
276
277                // Generates:
278                //     if ( ptr )
279                //         ^(*ptr){};
280                deleteFnBody->push_back(
281                        new IfStmt(
282                                decl->location,
283                                UntypedExpr::createCall(
284                                        decl->location,
285                                        "?!=?",
286                                        {
287                                                new NameExpr( decl->location, "ptr" ),
288                                                ConstantExpr::null( decl->location, new PointerType( ast::deepCopy( instType ) ) )
289                                        }
290                                ),
291                                new ExprStmt(
292                                        decl->location,
293                                        UntypedExpr::createCall(
294                                                decl->location,
295                                                "^?{}",
296                                                {
297                                                        UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
298                                                }
299                                        )
300                                )
301                        )
302                );
303
304                // Generates:
305                //     __CFA_virt_free( *ptr );
306                deleteFnBody->push_back( new ExprStmt(
307                                decl->location,
308                                UntypedExpr::createCall(
309                                        decl->location,
310                                        "__CFA_virt_free",
311                                        {
312                                                UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
313                                        }
314                                )
315                        )
316                );
317
318                FunctionDecl * deleteFn = new FunctionDecl(
319                        decl->location,
320                        "delete",
321                        {
322                                new ObjectDecl(
323                                        decl->location,
324                                        "ptr",
325                                        new PointerType( ast::deepCopy( instType ) )
326                                ),
327                        },                      // params
328                        {},
329                        nullptr,               // body
330                        { Storage::Static },    // storage
331                        Linkage::Cforall,       // linkage
332                        {},                     // attributes
333                        { Function::Inline }
334                );
335
336                declsToAddBefore.push_back( ast::deepCopy( deleteFn ) );
337
338                deleteFn->stmts = deleteFnBody;
339
340                torDecls.addLater( structIter->first, setDtorFunction, deleteFn );
341        }
342
343  public:
344        GenFuncsCreateTables( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls, const StructDecl ** virtualDtor ):
345        structDecls(structDecls), torDecls(torDecls), virtualDtor(virtualDtor) {}
346};
347
348
349// generates the trailing definitions of dtor setting routines for virtual dtors on messages and actors
350// generates the function defns of __CFA_set_dtor
351// separate pass is needed since  __CFA_set_dtor needs to be defined after
352//   the last dtor defn which is found in prior pass
353struct GenSetDtor : public ast::WithDeclsToAdd<> {
354        unordered_map<const StructDecl *, CtorDtor> & structDecls; // set of decls that inherit from virt dtor
355        CtorDtorTable & torDecls;
356
357        // handles adding the declaration of the dtor init routine after the last dtor detected
358        void postvisit( const FunctionDecl * decl ) {
359                if ( decl->name != "^?{}" || !decl->stmts || decl->params.size() != 1 ) return;
360
361                // the one param should be a reference
362                const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
363                if ( !ref ) return;
364
365                // the reference should be to a struct instance
366                const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
367                if ( !instType ) return;
368
369                FunctionDecl * deleteRtn;
370
371                // returns nullptr if not in table
372                FunctionDecl * maybeAdd = torDecls.getToAddLater( instType->aggr(), mutate( decl ), &deleteRtn );
373                if ( maybeAdd ) {
374                        declsToAddAfter.push_back( maybeAdd );
375                        declsToAddAfter.push_back( deleteRtn );
376                }
377        }
378
379public:
380        GenSetDtor( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls ):
381                structDecls(structDecls), torDecls(torDecls) {}
382};
383
384void implementVirtDtors( TranslationUnit & translationUnit ) {
385        // unordered_map to collect all derived types and associated data
386        unordered_map<const StructDecl *, CtorDtor> structDecls;
387        CtorDtorTable torDecls( structDecls );
388
389        const StructDecl * virtualDtorPtr = nullptr;
390        const StructDecl ** virtualDtor = &virtualDtorPtr;
391
392        // first pass collects all structs that inherit from virtual_dtor
393        Pass<CollectStructDecls>::run( translationUnit, structDecls, virtualDtor );
394
395        // second pass locates all dtor/ctor routines that need modifying or need fns inserted before/after
396        Pass<GenFuncsCreateTables>::run( translationUnit, structDecls, torDecls, virtualDtor );
397
398        // The third pass adds the forward decls needed to resolve circular defn problems
399        Pass<GenSetDtor>::run( translationUnit, structDecls, torDecls );
400}
401
402} // namespace Virtual
403
404// Local Variables: //
405// tab-width: 4 //
406// mode: c++ //
407// compile-command: "make install" //
408// End: //
409
Note: See TracBrowser for help on using the repository browser.