source: src/ControlStruct/ExceptTranslate.cc@ 33218c6

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since 33218c6 was ac10576, checked in by Andrew Beach <ajbeach@…>, 8 years ago

Replaced emptyQualifiers with noQualifiers for consistancy with noLabels and noAttributes.

  • Property mode set to 100644
File size: 17.3 KB
RevLine 
[ba912706]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// ExceptVisitor.cc --
8//
9// Author : Andrew Beach
10// Created On : Wed Jun 14 16:49:00 2017
11// Last Modified By : Andrew Beach
[ac10576]12// Last Modified On : Tus Jul 18 10:09:00 2017
13// Update Count : 4
[ba912706]14//
15
16#include "ExceptTranslate.h"
17#include "Common/PassVisitor.h"
[288eede]18#include "SynTree/Statement.h"
19#include "SynTree/Declaration.h"
20#include "SynTree/Expression.h"
21#include "SynTree/Type.h"
22#include "SynTree/Attribute.h"
[ba912706]23
[307a732]24namespace ControlStruct {
[ba912706]25
26 // This (large) section could probably be moved out of the class
27 // and be static helpers instead.
28
29 // Type(Qualifiers &, false, std::list<Attribute *> &)
30
[307a732]31 // void (*function)();
32 static FunctionType try_func_t(Type::Qualifiers(), false);
[ba912706]33 // void (*function)(int, exception);
34 static FunctionType catch_func_t(Type::Qualifiers(), false);
35 // int (*function)(exception);
36 static FunctionType match_func_t(Type::Qualifiers(), false);
37 // bool (*function)(exception);
38 static FunctionType handle_func_t(Type::Qualifiers(), false);
[307a732]39 // void (*function)(__attribute__((unused)) void *);
40 static FunctionType finally_func_t(Type::Qualifiers(), false);
[ba912706]41
42 static void init_func_types() {
[288eede]43 static bool init_complete = false;
[ba912706]44 if (init_complete) {
45 return;
46 }
47 ObjectDecl index_obj(
[288eede]48 "__handler_index",
[ba912706]49 Type::StorageClasses(),
50 LinkageSpec::Cforall,
51 /*bitfieldWidth*/ NULL,
[ac10576]52 new BasicType( noQualifiers, BasicType::SignedInt ),
[ba912706]53 /*init*/ NULL
[307a732]54 );
[ba912706]55 ObjectDecl exception_obj(
[288eede]56 "__exception_inst",
[ba912706]57 Type::StorageClasses(),
58 LinkageSpec::Cforall,
59 /*bitfieldWidth*/ NULL,
[307a732]60 new PointerType(
[ac10576]61 noQualifiers,
62 new BasicType( noQualifiers, BasicType::SignedInt )
[307a732]63 ),
[ba912706]64 /*init*/ NULL
[307a732]65 );
[ba912706]66 ObjectDecl bool_obj(
[288eede]67 "__ret_bool",
[ba912706]68 Type::StorageClasses(),
69 LinkageSpec::Cforall,
70 /*bitfieldWidth*/ NULL,
[ac10576]71 new BasicType(noQualifiers, BasicType::Bool),
[ba912706]72 /*init*/ NULL
[307a732]73 );
74 ObjectDecl voidptr_obj(
75 "__hook",
76 Type::StorageClasses(),
77 LinkageSpec::Cforall,
78 NULL,
79 new PointerType(
[ac10576]80 noQualifiers,
[307a732]81 new VoidType(
[ac10576]82 noQualifiers
[307a732]83 ),
84 std::list<Attribute *>{new Attribute("unused")}
85 ),
86 NULL
87 );
[ba912706]88
[307a732]89 catch_func_t.get_parameters().push_back( index_obj.clone() );
90 catch_func_t.get_parameters().push_back( exception_obj.clone() );
91 match_func_t.get_returnVals().push_back( index_obj.clone() );
92 match_func_t.get_parameters().push_back( exception_obj.clone() );
93 handle_func_t.get_returnVals().push_back( bool_obj.clone() );
94 handle_func_t.get_parameters().push_back( exception_obj.clone() );
95 finally_func_t.get_parameters().push_back( voidptr_obj.clone() );
[ba912706]96
97 init_complete = true;
98 }
99
100 // Buricratic Helpers (Not having to do with the paritular operation.)
101
102 typedef std::list<CatchStmt*> CatchList;
103
104 void split( CatchList& allHandlers, CatchList& terHandlers,
[1abc5ab]105 CatchList& resHandlers ) {
[ba912706]106 while ( !allHandlers.empty() ) {
[288eede]107 CatchStmt * stmt = allHandlers.front();
[ba912706]108 allHandlers.pop_front();
[288eede]109 if (CatchStmt::Terminate == stmt->get_kind()) {
[ba912706]110 terHandlers.push_back(stmt);
111 } else {
112 resHandlers.push_back(stmt);
113 }
114 }
115 }
116
117 template<typename T>
118 void free_all( std::list<T *> &list ) {
[288eede]119 typename std::list<T *>::iterator it;
[ba912706]120 for ( it = list.begin() ; it != list.end() ; ++it ) {
121 delete *it;
122 }
123 list.clear();
124 }
125
126 void appendDeclStmt( CompoundStmt * block, Declaration * item ) {
[288eede]127 block->push_back(new DeclStmt(noLabels, item));
[ba912706]128 }
129
[288eede]130 Expression * nameOf( DeclarationWithType * decl ) {
131 return new VariableExpr( decl );
[ba912706]132 }
133
134 // ThrowStmt Mutation Helpers
135
[307a732]136 Statement * create_given_throw(
137 const char * throwFunc, ThrowStmt * throwStmt ) {
138 // { int NAME = EXPR; throwFunc( &NAME ); }
139 CompoundStmt * result = new CompoundStmt( noLabels );
140 ObjectDecl * local = new ObjectDecl(
141 "__local_exception_copy",
142 Type::StorageClasses(),
143 LinkageSpec::Cforall,
144 NULL,
[ac10576]145 new BasicType( noQualifiers, BasicType::SignedInt ),
[307a732]146 new SingleInit( throwStmt->get_expr() )
147 );
148 appendDeclStmt( result, local );
149 UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) );
150 call->get_args().push_back( new AddressExpr( nameOf( local ) ) );
151 result->push_back( new ExprStmt( throwStmt->get_labels(), call ) );
[ba912706]152 throwStmt->set_expr( nullptr );
153 delete throwStmt;
154 return result;
155 }
[307a732]156
157 Statement * create_terminate_throw( ThrowStmt *throwStmt ) {
158 // { int NAME = EXPR; __throw_terminate( &NAME ); }
[38ac6ec]159 return create_given_throw( "__cfaehm__throw_terminate", throwStmt );
[307a732]160 }
[ba912706]161 Statement * create_terminate_rethrow( ThrowStmt *throwStmt ) {
162 // __rethrow_terminate();
[288eede]163 assert( nullptr == throwStmt->get_expr() );
[ba912706]164 Statement * result = new ExprStmt(
165 throwStmt->get_labels(),
[38ac6ec]166 new UntypedExpr( new NameExpr( "__cfaehm__rethrow_terminate" ) )
[ba912706]167 );
168 delete throwStmt;
169 return result;
170 }
171 Statement * create_resume_throw( ThrowStmt *throwStmt ) {
172 // __throw_resume( EXPR );
[38ac6ec]173 return create_given_throw( "__cfaehm__throw_resume", throwStmt );
[ba912706]174 }
175 Statement * create_resume_rethrow( ThrowStmt *throwStmt ) {
176 // return false;
177 Statement * result = new ReturnStmt(
178 throwStmt->get_labels(),
[288eede]179 new ConstantExpr( Constant::from_bool( false ) )
[ba912706]180 );
181 delete throwStmt;
182 return result;
183 }
184
185 // TryStmt Mutation Helpers
186
187 CompoundStmt * take_try_block( TryStmt *tryStmt ) {
188 CompoundStmt * block = tryStmt->get_block();
189 tryStmt->set_block( nullptr );
190 return block;
191 }
[288eede]192 FunctionDecl * create_try_wrapper( CompoundStmt *body ) {
[ba912706]193
[288eede]194 return new FunctionDecl( "try", Type::StorageClasses(),
[307a732]195 LinkageSpec::Cforall, try_func_t.clone(), body );
[ba912706]196 }
197
198 FunctionDecl * create_terminate_catch( CatchList &handlers ) {
199 std::list<CaseStmt *> handler_wrappers;
200
[288eede]201 FunctionType *func_type = catch_func_t.clone();
202 DeclarationWithType * index_obj = func_type->get_parameters().front();
203 // DeclarationWithType * except_obj = func_type->get_parameters().back();
204
[ba912706]205 // Index 1..{number of handlers}
206 int index = 0;
207 CatchList::iterator it = handlers.begin();
208 for ( ; it != handlers.end() ; ++it ) {
209 ++index;
210 CatchStmt * handler = *it;
211
[288eede]212 // INTEGERconstant Version
213 // case `index`:
214 // {
215 // `handler.body`
216 // }
217 // return;
218 std::list<Statement *> caseBody;
219 caseBody.push_back( handler->get_body() );
220 handler->set_body( nullptr );
221 caseBody.push_back( new ReturnStmt( noLabels, nullptr ) );
222
223 handler_wrappers.push_back( new CaseStmt(
[ba912706]224 noLabels,
225 new ConstantExpr( Constant::from_int( index ) ),
[288eede]226 caseBody
227 ) );
[ba912706]228 }
229 // TODO: Some sort of meaningful error on default perhaps?
230
[288eede]231 std::list<Statement*> stmt_handlers;
232 while ( !handler_wrappers.empty() ) {
233 stmt_handlers.push_back( handler_wrappers.front() );
234 handler_wrappers.pop_front();
235 }
236
[ba912706]237 SwitchStmt * handler_lookup = new SwitchStmt(
238 noLabels,
[288eede]239 nameOf( index_obj ),
240 stmt_handlers
[ba912706]241 );
242 CompoundStmt * body = new CompoundStmt( noLabels );
243 body->push_back( handler_lookup );
244
245 return new FunctionDecl("catch", Type::StorageClasses(),
[288eede]246 LinkageSpec::Cforall, func_type, body);
[ba912706]247 }
248
249 // Create a single check from a moddified handler.
[288eede]250 // except_obj is referenced, modded_handler will be freed.
251 CompoundStmt *create_single_matcher(
252 DeclarationWithType * except_obj, CatchStmt * modded_handler ) {
253 CompoundStmt * block = new CompoundStmt( noLabels );
254
255 // INTEGERconstant Version
256 assert( nullptr == modded_handler->get_decl() );
257 ConstantExpr * number =
258 dynamic_cast<ConstantExpr*>( modded_handler->get_cond() );
259 assert( number );
260 modded_handler->set_cond( nullptr );
[ba912706]261
[288eede]262 Expression * cond;
263 {
264 std::list<Expression *> args;
265 args.push_back( number );
[307a732]266
267 std::list<Expression *> rhs_args;
268 rhs_args.push_back( nameOf( except_obj ) );
269 Expression * rhs = new UntypedExpr(
270 new NameExpr( "*?" ), rhs_args );
271 args.push_back( rhs );
272
[288eede]273 cond = new UntypedExpr( new NameExpr( "?==?" /*???*/), args );
274 }
[ba912706]275
276 if ( modded_handler->get_cond() ) {
[288eede]277 cond = new LogicalExpr( cond, modded_handler->get_cond() );
[ba912706]278 }
279 block->push_back( new IfStmt( noLabels,
[288eede]280 cond, modded_handler->get_body(), nullptr ) );
[ba912706]281
282 modded_handler->set_decl( nullptr );
283 modded_handler->set_cond( nullptr );
284 modded_handler->set_body( nullptr );
285 delete modded_handler;
286 return block;
287 }
288
289 FunctionDecl * create_terminate_match( CatchList &handlers ) {
290 CompoundStmt * body = new CompoundStmt( noLabels );
291
[288eede]292 FunctionType * func_type = match_func_t.clone();
293 DeclarationWithType * except_obj = func_type->get_parameters().back();
294
[ba912706]295 // Index 1..{number of handlers}
296 int index = 0;
297 CatchList::iterator it;
298 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
299 ++index;
300 CatchStmt * handler = *it;
301
[288eede]302 // Body should have been taken by create_terminate_catch.
303 assert( nullptr == handler->get_body() );
304
305 // Create new body.
[ba912706]306 handler->set_body( new ReturnStmt( noLabels,
307 new ConstantExpr( Constant::from_int( index ) ) ) );
308
[288eede]309 // Create the handler.
310 body->push_back( create_single_matcher( except_obj, handler ) );
311 *it = nullptr;
[ba912706]312 }
313
[307a732]314 body->push_back( new ReturnStmt( noLabels, new ConstantExpr(
315 Constant::from_int( 0 ) ) ) );
316
[ba912706]317 return new FunctionDecl("match", Type::StorageClasses(),
[288eede]318 LinkageSpec::Cforall, func_type, body);
[ba912706]319 }
320
[288eede]321 CompoundStmt * create_terminate_caller(
[ba912706]322 FunctionDecl * try_wrapper,
323 FunctionDecl * terminate_catch,
324 FunctionDecl * terminate_match) {
325
[288eede]326 UntypedExpr * caller = new UntypedExpr( new NameExpr(
327 "__cfaehm__try_terminate" ) );
328 std::list<Expression *>& args = caller->get_args();
[ba912706]329 args.push_back( nameOf( try_wrapper ) );
330 args.push_back( nameOf( terminate_catch ) );
331 args.push_back( nameOf( terminate_match ) );
332
[288eede]333 CompoundStmt * callStmt = new CompoundStmt( noLabels );
334 callStmt->push_back( new ExprStmt( noLabels, caller ) );
335 return callStmt;
[ba912706]336 }
337
338 FunctionDecl * create_resume_handler( CatchList &handlers ) {
[288eede]339 CompoundStmt * body = new CompoundStmt( noLabels );
340
341 FunctionType * func_type = match_func_t.clone();
342 DeclarationWithType * except_obj = func_type->get_parameters().back();
[ba912706]343
344 CatchList::iterator it;
345 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
346 CatchStmt * handler = *it;
347
348 // Modifiy body.
349 CompoundStmt * handling_code =
350 dynamic_cast<CompoundStmt*>( handler->get_body() );
351 if ( ! handling_code ) {
352 handling_code = new CompoundStmt( noLabels );
353 handling_code->push_back( handler->get_body() );
354 }
[288eede]355 handling_code->push_back( new ReturnStmt( noLabels,
[ad0be81]356 new ConstantExpr( Constant::from_bool( true ) ) ) );
[ba912706]357 handler->set_body( handling_code );
358
359 // Create the handler.
[288eede]360 body->push_back( create_single_matcher( except_obj, handler ) );
361 *it = nullptr;
[ba912706]362 }
363
[ad0be81]364 body->push_back( new ReturnStmt( noLabels, new ConstantExpr(
365 Constant::from_bool( false ) ) ) );
366
[ba912706]367 return new FunctionDecl("handle", Type::StorageClasses(),
[288eede]368 LinkageSpec::Cforall, func_type, body);
[ba912706]369 }
370
[288eede]371 CompoundStmt * create_resume_wrapper(
372 StructDecl * node_decl,
[ba912706]373 Statement * wraps,
374 FunctionDecl * resume_handler ) {
375 CompoundStmt * body = new CompoundStmt( noLabels );
376
[288eede]377 // struct __try_resume_node __resume_node
378 // __attribute__((cleanup( __cfaehm__try_resume_cleanup )));
379 // ** unwinding of the stack here could cause problems **
380 // ** however I don't think that can happen currently **
381 // __cfaehm__try_resume_setup( &__resume_node, resume_handler );
[ba912706]382
383 std::list< Attribute * > attributes;
384 {
385 std::list< Expression * > attr_params;
[288eede]386 attr_params.push_back( new NameExpr(
387 "__cfaehm__try_resume_cleanup" ) );
388 attributes.push_back( new Attribute( "cleanup", attr_params ) );
[ba912706]389 }
390
[288eede]391 ObjectDecl * obj = new ObjectDecl(
392 "__resume_node",
[ba912706]393 Type::StorageClasses(),
394 LinkageSpec::Cforall,
395 nullptr,
[288eede]396 new StructInstType(
397 Type::Qualifiers(),
398 node_decl
399 ),
400 nullptr,
[ba912706]401 attributes
[288eede]402 );
403 appendDeclStmt( body, obj );
404
405 UntypedExpr *setup = new UntypedExpr( new NameExpr(
406 "__cfaehm__try_resume_setup" ) );
[307a732]407 setup->get_args().push_back( new AddressExpr( nameOf( obj ) ) );
[288eede]408 setup->get_args().push_back( nameOf( resume_handler ) );
409
410 body->push_back( new ExprStmt( noLabels, setup ) );
411
[ba912706]412 body->push_back( wraps );
413 return body;
414 }
415
416 FunctionDecl * create_finally_wrapper( TryStmt * tryStmt ) {
[288eede]417 FinallyStmt * finally = tryStmt->get_finally();
418 CompoundStmt * body = finally->get_block();
419 finally->set_block( nullptr );
420 delete finally;
[ba912706]421 tryStmt->set_finally( nullptr );
422
423 return new FunctionDecl("finally", Type::StorageClasses(),
[307a732]424 LinkageSpec::Cforall, finally_func_t.clone(), body);
[ba912706]425 }
426
[288eede]427 ObjectDecl * create_finally_hook(
428 StructDecl * hook_decl, FunctionDecl * finally_wrapper ) {
429 // struct __cfaehm__cleanup_hook __finally_hook
430 // __attribute__((cleanup( finally_wrapper )));
[ba912706]431
432 // Make Cleanup Attribute.
433 std::list< Attribute * > attributes;
434 {
435 std::list< Expression * > attr_params;
436 attr_params.push_back( nameOf( finally_wrapper ) );
[288eede]437 attributes.push_back( new Attribute( "cleanup", attr_params ) );
[ba912706]438 }
439
[288eede]440 return new ObjectDecl(
441 "__finally_hook",
[ba912706]442 Type::StorageClasses(),
443 LinkageSpec::Cforall,
444 nullptr,
[288eede]445 new StructInstType(
[ac10576]446 noQualifiers,
[288eede]447 hook_decl
448 ),
[ba912706]449 nullptr,
450 attributes
451 );
452 }
453
454
[1abc5ab]455 class ExceptionMutatorCore : public WithGuards {
[ba912706]456 enum Context { NoHandler, TerHandler, ResHandler };
457
458 // Also need to handle goto, break & continue.
459 // They need to be cut off in a ResHandler, until we enter another
460 // loop, switch or the goto stays within the function.
461
[288eede]462 Context cur_context;
[ba912706]463
464 // We might not need this, but a unique base for each try block's
465 // generated functions might be nice.
466 //std::string curFunctionName;
467 //unsigned int try_count = 0;
468
[288eede]469 StructDecl *node_decl;
470 StructDecl *hook_decl;
[ba912706]471
472 public:
473 ExceptionMutatorCore() :
[288eede]474 cur_context(NoHandler),
475 node_decl(nullptr), hook_decl(nullptr)
[ba912706]476 {}
477
[288eede]478 void premutate( CatchStmt *catchStmt );
479 void premutate( StructDecl *structDecl );
[ba912706]480 Statement * postmutate( ThrowStmt *throwStmt );
481 Statement * postmutate( TryStmt *tryStmt );
482 };
483
484 Statement * ExceptionMutatorCore::postmutate( ThrowStmt *throwStmt ) {
485 // Ignoring throwStmt->get_target() for now.
486 if ( ThrowStmt::Terminate == throwStmt->get_kind() ) {
487 if ( throwStmt->get_expr() ) {
488 return create_terminate_throw( throwStmt );
[288eede]489 } else if ( TerHandler == cur_context ) {
[ba912706]490 return create_terminate_rethrow( throwStmt );
491 } else {
492 assertf(false, "Invalid throw in %s at %i\n",
[288eede]493 throwStmt->location.filename.c_str(),
[ba912706]494 throwStmt->location.linenumber);
495 return nullptr;
496 }
497 } else {
498 if ( throwStmt->get_expr() ) {
499 return create_resume_throw( throwStmt );
[288eede]500 } else if ( ResHandler == cur_context ) {
[ba912706]501 return create_resume_rethrow( throwStmt );
502 } else {
503 assertf(false, "Invalid throwResume in %s at %i\n",
[288eede]504 throwStmt->location.filename.c_str(),
[ba912706]505 throwStmt->location.linenumber);
506 return nullptr;
507 }
508 }
509 }
510
511 Statement * ExceptionMutatorCore::postmutate( TryStmt *tryStmt ) {
[288eede]512 assert( node_decl );
513 assert( hook_decl );
514
[ba912706]515 // Generate a prefix for the function names?
516
[288eede]517 CompoundStmt * block = new CompoundStmt( noLabels );
518 CompoundStmt * inner = take_try_block( tryStmt );
[ba912706]519
520 if ( tryStmt->get_finally() ) {
521 // Define the helper function.
522 FunctionDecl * finally_block =
523 create_finally_wrapper( tryStmt );
524 appendDeclStmt( block, finally_block );
525 // Create and add the finally cleanup hook.
[288eede]526 appendDeclStmt( block,
527 create_finally_hook( hook_decl, finally_block ) );
[ba912706]528 }
529
[288eede]530 CatchList termination_handlers;
531 CatchList resumption_handlers;
532 split( tryStmt->get_catchers(),
[1abc5ab]533 termination_handlers, resumption_handlers );
[ba912706]534
[288eede]535 if ( resumption_handlers.size() ) {
[ba912706]536 // Define the helper function.
537 FunctionDecl * resume_handler =
538 create_resume_handler( resumption_handlers );
539 appendDeclStmt( block, resume_handler );
540 // Prepare hooks
[288eede]541 inner = create_resume_wrapper( node_decl, inner, resume_handler );
[ba912706]542 }
543
544 if ( termination_handlers.size() ) {
545 // Define the three helper functions.
546 FunctionDecl * try_wrapper = create_try_wrapper( inner );
547 appendDeclStmt( block, try_wrapper );
548 FunctionDecl * terminate_catch =
549 create_terminate_catch( termination_handlers );
550 appendDeclStmt( block, terminate_catch );
551 FunctionDecl * terminate_match =
552 create_terminate_match( termination_handlers );
553 appendDeclStmt( block, terminate_match );
554 // Build the call to the try wrapper.
555 inner = create_terminate_caller(
556 try_wrapper, terminate_catch, terminate_match );
557 }
558
559 // Embed the try block.
560 block->push_back( inner );
561
[288eede]562 //free_all( termination_handlers );
563 //free_all( resumption_handlers );
[ba912706]564
565 return block;
566 }
567
568 void ExceptionMutatorCore::premutate( CatchStmt *catchStmt ) {
[288eede]569 GuardValue( cur_context );
570 if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
571 cur_context = TerHandler;
[ba912706]572 } else {
[288eede]573 cur_context = ResHandler;
[ba912706]574 }
575 }
576
[288eede]577 void ExceptionMutatorCore::premutate( StructDecl *structDecl ) {
578 if ( !structDecl->has_body() ) {
579 // Skip children?
580 return;
581 } else if ( structDecl->get_name() == "__cfaehm__try_resume_node" ) {
582 assert( nullptr == node_decl );
583 node_decl = structDecl;
584 } else if ( structDecl->get_name() == "__cfaehm__cleanup_hook" ) {
585 assert( nullptr == hook_decl );
586 hook_decl = structDecl;
587 }
588 // Later we might get the exception type as well.
589 }
590
[1abc5ab]591 void translateEHM( std::list< Declaration *> & translationUnit ) {
[288eede]592 init_func_types();
593
[ba912706]594 PassVisitor<ExceptionMutatorCore> translator;
[6fca7ea]595 mutateAll( translationUnit, translator );
[ba912706]596 }
597}
Note: See TracBrowser for help on using the repository browser.