source: src/Virtual/VirtualDtor.cpp@ 11ab0b4a

Last change on this file since 11ab0b4a was 4bae7b4, checked in by caparsons <caparson@…>, 2 years ago

fixed bug where virtual dtor would not work if dtors or ctors of the type had unnamed params

  • Property mode set to 100644
File size: 15.2 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
40 public:
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 {}, // forall
251 {
252 new ObjectDecl(
253 decl->location,
254 "this",
255 ast::deepCopy( ref )
256 ),
257 }, // params
258 {},
259 nullptr, // body
260 { Storage::Static }, // storage
261 Linkage::Cforall, // linkage
262 {}, // attributes
263 { Function::Inline }
264 );
265
266 declsToAddBefore.push_back( ast::deepCopy( setDtorFunction ) );
267
268 setDtorFunction->stmts = setDtorBody;
269
270 // The following generates the following specialized delete routine:
271 // static inline void delete( derived_type * ptr ) {
272 // if ( ptr )
273 // ^(*ptr){};
274 // __CFA_virt_free( *ptr );
275 // }
276 CompoundStmt * deleteFnBody = new CompoundStmt( decl->location );
277
278 // Generates:
279 // if ( ptr )
280 // ^(*ptr){};
281 deleteFnBody->push_back(
282 new IfStmt(
283 decl->location,
284 UntypedExpr::createCall(
285 decl->location,
286 "?!=?",
287 {
288 new NameExpr( decl->location, "ptr" ),
289 ConstantExpr::null( decl->location, new PointerType( ast::deepCopy( instType ) ) )
290 }
291 ),
292 new ExprStmt(
293 decl->location,
294 UntypedExpr::createCall(
295 decl->location,
296 "^?{}",
297 {
298 UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
299 }
300 )
301 )
302 )
303 );
304
305 // Generates:
306 // __CFA_virt_free( *ptr );
307 deleteFnBody->push_back( new ExprStmt(
308 decl->location,
309 UntypedExpr::createCall(
310 decl->location,
311 "__CFA_virt_free",
312 {
313 UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
314 }
315 )
316 )
317 );
318
319 FunctionDecl * deleteFn = new FunctionDecl(
320 decl->location,
321 "delete",
322 {}, // forall
323 {
324 new ObjectDecl(
325 decl->location,
326 "ptr",
327 new PointerType( ast::deepCopy( instType ) )
328 ),
329 }, // params
330 {},
331 nullptr, // body
332 { Storage::Static }, // storage
333 Linkage::Cforall, // linkage
334 {}, // attributes
335 { Function::Inline }
336 );
337
338 declsToAddBefore.push_back( ast::deepCopy( deleteFn ) );
339
340 deleteFn->stmts = deleteFnBody;
341
342 torDecls.addLater( structIter->first, setDtorFunction, deleteFn );
343 }
344
345 public:
346 GenFuncsCreateTables( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls, const StructDecl ** virtualDtor ):
347 structDecls(structDecls), torDecls(torDecls), virtualDtor(virtualDtor) {}
348};
349
350
351// generates the trailing definitions of dtor setting routines for virtual dtors on messages and actors
352// generates the function defns of __CFA_set_dtor
353// separate pass is needed since __CFA_set_dtor needs to be defined after
354// the last dtor defn which is found in prior pass
355struct GenSetDtor : public ast::WithDeclsToAdd<> {
356 unordered_map<const StructDecl *, CtorDtor> & structDecls; // set of decls that inherit from virt dtor
357 CtorDtorTable & torDecls;
358
359 // handles adding the declaration of the dtor init routine after the last dtor detected
360 void postvisit( const FunctionDecl * decl ) {
361 if ( decl->name != "^?{}" || !decl->stmts || decl->params.size() != 1 ) return;
362
363 // the one param should be a reference
364 const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
365 if ( !ref ) return;
366
367 // the reference should be to a struct instance
368 const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
369 if ( !instType ) return;
370
371 FunctionDecl * deleteRtn;
372
373 // returns nullptr if not in table
374 FunctionDecl * maybeAdd = torDecls.getToAddLater( instType->aggr(), mutate( decl ), &deleteRtn );
375 if ( maybeAdd ) {
376 declsToAddAfter.push_back( maybeAdd );
377 declsToAddAfter.push_back( deleteRtn );
378 }
379 }
380
381 public:
382 GenSetDtor( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls ):
383 structDecls(structDecls), torDecls(torDecls) {}
384};
385
386void implementVirtDtors( TranslationUnit & translationUnit ) {
387 // unordered_map to collect all derived types and associated data
388 unordered_map<const StructDecl *, CtorDtor> structDecls;
389 CtorDtorTable torDecls( structDecls );
390
391 const StructDecl * virtualDtorPtr = nullptr;
392 const StructDecl ** virtualDtor = &virtualDtorPtr;
393
394 // first pass collects all structs that inherit from virtual_dtor
395 Pass<CollectStructDecls>::run( translationUnit, structDecls, virtualDtor );
396
397 // second pass locates all dtor/ctor routines that need modifying or need fns inserted before/after
398 Pass<GenFuncsCreateTables>::run( translationUnit, structDecls, torDecls, virtualDtor );
399
400 // The third pass adds the forward decls needed to resolve circular defn problems
401 Pass<GenSetDtor>::run( translationUnit, structDecls, torDecls );
402}
403
404
405} // namespace Virtual
406
407// Local Variables: //
408// tab-width: 4 //
409// mode: c++ //
410// compile-command: "make install" //
411// End: //
412
Note: See TracBrowser for help on using the repository browser.