source: src/ControlStruct/ExceptTranslate.cc@ 03045f18

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 03045f18 was 66ba544, checked in by Andrew Beach <ajbeach@…>, 5 years ago

Dead code elimination in the try block translation.

  • Property mode set to 100644
File size: 21.0 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
[3090127]11// Last Modified By : Andrew Beach
[66ba544]12// Last Modified On : Thr May 21 13:18:00 2020
13// Update Count : 15
[ba912706]14//
15
16#include "ExceptTranslate.h"
[d180746]17
18#include <stddef.h> // for NULL
19#include <cassert> // for assert, assertf
20#include <iterator> // for back_inserter, inserter
21#include <string> // for string, operator==
22
23#include "Common/PassVisitor.h" // for PassVisitor, WithGuards
24#include "Common/SemanticError.h" // for SemanticError
25#include "Common/utility.h" // for CodeLocation
[07de76b]26#include "SynTree/LinkageSpec.h" // for Cforall
[d180746]27#include "SynTree/Attribute.h" // for Attribute
28#include "SynTree/Constant.h" // for Constant
29#include "SynTree/Declaration.h" // for ObjectDecl, FunctionDecl, Struc...
30#include "SynTree/Expression.h" // for UntypedExpr, ConstantExpr, Name...
31#include "SynTree/Initializer.h" // for SingleInit, ListInit
[ba3706f]32#include "SynTree/Label.h" // for Label
[d180746]33#include "SynTree/Mutator.h" // for mutateAll
34#include "SynTree/Statement.h" // for CompoundStmt, CatchStmt, ThrowStmt
35#include "SynTree/Type.h" // for FunctionType, Type, noQualifiers
[7862059]36#include "SynTree/DeclReplacer.h" // for DeclReplacer
[d180746]37#include "SynTree/Visitor.h" // for acceptAll
[ba912706]38
[307a732]39namespace ControlStruct {
[ba912706]40
[948b0c8]41 // Buricratic Helpers (Not having to do with the paritular operation.)
42
43 typedef std::list<CatchStmt*> CatchList;
44
45 void split( CatchList& allHandlers, CatchList& terHandlers,
46 CatchList& resHandlers ) {
47 while ( !allHandlers.empty() ) {
48 CatchStmt * stmt = allHandlers.front();
49 allHandlers.pop_front();
50 if (CatchStmt::Terminate == stmt->get_kind()) {
51 terHandlers.push_back(stmt);
52 } else {
53 resHandlers.push_back(stmt);
54 }
55 }
56 }
57
58 void appendDeclStmt( CompoundStmt * block, Declaration * item ) {
[ba3706f]59 block->push_back(new DeclStmt(item));
[948b0c8]60 }
61
62 Expression * nameOf( DeclarationWithType * decl ) {
63 return new VariableExpr( decl );
64 }
65
[046a890]66 class ThrowMutatorCore : public WithGuards {
67 ObjectDecl * terminate_handler_except;
68 enum Context { NoHandler, TerHandler, ResHandler } cur_context;
69
70 // The helper functions for code/syntree generation.
71 Statement * create_either_throw(
72 ThrowStmt * throwStmt, const char * throwFunc );
73 Statement * create_terminate_rethrow( ThrowStmt * throwStmt );
74 Statement * create_resume_rethrow( ThrowStmt * throwStmt );
75
76 public:
77 ThrowMutatorCore() :
78 terminate_handler_except( nullptr ),
79 cur_context( NoHandler )
80 {}
81
82 void premutate( CatchStmt *catchStmt );
83 Statement * postmutate( ThrowStmt *throwStmt );
84 };
85
86 // ThrowStmt Mutation Helpers
87
88 Statement * ThrowMutatorCore::create_either_throw(
89 ThrowStmt * throwStmt, const char * throwFunc ) {
90 // `throwFunc`( `throwStmt->get_name()` );
91 UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) );
92 call->get_args().push_back( throwStmt->get_expr() );
93 throwStmt->set_expr( nullptr );
94 delete throwStmt;
95 return new ExprStmt( call );
96 }
97
98 Statement * ThrowMutatorCore::create_terminate_rethrow(
99 ThrowStmt *throwStmt ) {
100 // { `terminate_handler_except` = 0p; __rethrow_terminate(); }
101 assert( nullptr == throwStmt->get_expr() );
102 assert( terminate_handler_except );
103
104 CompoundStmt * result = new CompoundStmt();
105 result->labels = throwStmt->labels;
106 result->push_back( new ExprStmt( UntypedExpr::createAssign(
107 nameOf( terminate_handler_except ),
108 new ConstantExpr( Constant::null(
109 //new PointerType(
110 // noQualifiers,
111 terminate_handler_except->get_type()->clone()
112 // )
113 ) )
114 ) ) );
115 result->push_back( new ExprStmt(
116 new UntypedExpr( new NameExpr( "__cfaehm_rethrow_terminate" ) )
117 ) );
118 delete throwStmt;
119 return result;
120 }
121
122 Statement * ThrowMutatorCore::create_resume_rethrow(
123 ThrowStmt *throwStmt ) {
124 // return false;
125 Statement * result = new ReturnStmt(
126 new ConstantExpr( Constant::from_bool( false ) )
127 );
128 result->labels = throwStmt->labels;
129 delete throwStmt;
130 return result;
131 }
132
133 // Visiting/Mutating Functions
134
135 void ThrowMutatorCore::premutate( CatchStmt *catchStmt ) {
136 // Validate the statement's form.
137 ObjectDecl * decl = dynamic_cast<ObjectDecl *>( catchStmt->get_decl() );
138 // Also checking the type would be nice.
139 if ( decl ) {
140 // Pass.
141 } else if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
142 SemanticError(catchStmt->location, "catch must have exception type");
143 } else {
144 SemanticError(catchStmt->location, "catchResume must have exception type");
145 }
146
147 // Track the handler context.
148 GuardValue( cur_context );
149 if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
150 cur_context = TerHandler;
151
152 GuardValue( terminate_handler_except );
153 terminate_handler_except = decl;
154 } else {
155 cur_context = ResHandler;
156 }
157 }
158
159 Statement * ThrowMutatorCore::postmutate( ThrowStmt *throwStmt ) {
160 // Ignoring throwStmt->get_target() for now.
161 if ( ThrowStmt::Terminate == throwStmt->get_kind() ) {
162 if ( throwStmt->get_expr() ) {
163 return create_either_throw( throwStmt, "$throw" );
164 } else if ( TerHandler == cur_context ) {
165 return create_terminate_rethrow( throwStmt );
166 } else {
167 abort("Invalid throw in %s at %i\n",
168 throwStmt->location.filename.c_str(),
169 throwStmt->location.first_line);
170 }
171 } else {
172 if ( throwStmt->get_expr() ) {
173 return create_either_throw( throwStmt, "$throwResume" );
174 } else if ( ResHandler == cur_context ) {
175 return create_resume_rethrow( throwStmt );
176 } else {
177 abort("Invalid throwResume in %s at %i\n",
178 throwStmt->location.filename.c_str(),
179 throwStmt->location.first_line);
180 }
181 }
182 }
183
[66ba544]184 class TryMutatorCore {
[948b0c8]185 // The built in types used in translation.
186 StructDecl * except_decl;
187 StructDecl * node_decl;
188 StructDecl * hook_decl;
189
190 // The many helper functions for code/syntree generation.
191 CompoundStmt * take_try_block( TryStmt * tryStmt );
192 FunctionDecl * create_try_wrapper( CompoundStmt * body );
193 FunctionDecl * create_terminate_catch( CatchList &handlers );
194 CompoundStmt * create_single_matcher(
195 DeclarationWithType * except_obj, CatchStmt * modded_handler );
196 FunctionDecl * create_terminate_match( CatchList &handlers );
197 CompoundStmt * create_terminate_caller( FunctionDecl * try_wrapper,
198 FunctionDecl * terminate_catch, FunctionDecl * terminate_match );
199 FunctionDecl * create_resume_handler( CatchList &handlers );
200 CompoundStmt * create_resume_wrapper(
201 Statement * wraps, FunctionDecl * resume_handler );
202 FunctionDecl * create_finally_wrapper( TryStmt * tryStmt );
203 ObjectDecl * create_finally_hook( FunctionDecl * finally_wrapper );
204
205 // Types used in translation, make sure to use clone.
206 // void (*function)();
207 FunctionType try_func_t;
208 // void (*function)(int, exception);
209 FunctionType catch_func_t;
210 // int (*function)(exception);
211 FunctionType match_func_t;
212 // bool (*function)(exception);
213 FunctionType handle_func_t;
214 // void (*function)(__attribute__((unused)) void *);
215 FunctionType finally_func_t;
216
217 StructInstType * create_except_type() {
218 assert( except_decl );
219 return new StructInstType( noQualifiers, except_decl );
220 }
221 void init_func_types();
222
223 public:
[046a890]224 TryMutatorCore() :
[948b0c8]225 except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr ),
226 try_func_t( noQualifiers, false ),
227 catch_func_t( noQualifiers, false ),
228 match_func_t( noQualifiers, false ),
229 handle_func_t( noQualifiers, false ),
230 finally_func_t( noQualifiers, false )
[cbce272]231 {}
[948b0c8]232
233 void premutate( StructDecl *structDecl );
234 Statement * postmutate( ThrowStmt *throwStmt );
235 Statement * postmutate( TryStmt *tryStmt );
236 };
237
[046a890]238 void TryMutatorCore::init_func_types() {
[cbce272]239 assert( except_decl );
240
[ba912706]241 ObjectDecl index_obj(
[288eede]242 "__handler_index",
[ba912706]243 Type::StorageClasses(),
244 LinkageSpec::Cforall,
245 /*bitfieldWidth*/ NULL,
[ac10576]246 new BasicType( noQualifiers, BasicType::SignedInt ),
[ba912706]247 /*init*/ NULL
[307a732]248 );
[ba912706]249 ObjectDecl exception_obj(
[288eede]250 "__exception_inst",
[ba912706]251 Type::StorageClasses(),
252 LinkageSpec::Cforall,
253 /*bitfieldWidth*/ NULL,
[307a732]254 new PointerType(
[ac10576]255 noQualifiers,
[cbce272]256 new StructInstType( noQualifiers, except_decl )
[307a732]257 ),
[ba912706]258 /*init*/ NULL
[307a732]259 );
[ba912706]260 ObjectDecl bool_obj(
[288eede]261 "__ret_bool",
[ba912706]262 Type::StorageClasses(),
263 LinkageSpec::Cforall,
264 /*bitfieldWidth*/ NULL,
[948b0c8]265 new BasicType( noQualifiers, BasicType::Bool ),
[8f6dfe7]266 /*init*/ NULL,
267 std::list<Attribute *>{ new Attribute( "unused" ) }
[307a732]268 );
269 ObjectDecl voidptr_obj(
270 "__hook",
271 Type::StorageClasses(),
272 LinkageSpec::Cforall,
273 NULL,
274 new PointerType(
[ac10576]275 noQualifiers,
[307a732]276 new VoidType(
[ac10576]277 noQualifiers
[307a732]278 ),
[948b0c8]279 std::list<Attribute *>{ new Attribute( "unused" ) }
[307a732]280 ),
281 NULL
282 );
[ba912706]283
[8f6dfe7]284 ObjectDecl * unused_index_obj = index_obj.clone();
285 unused_index_obj->attributes.push_back( new Attribute( "unused" ) );
286
[307a732]287 catch_func_t.get_parameters().push_back( index_obj.clone() );
288 catch_func_t.get_parameters().push_back( exception_obj.clone() );
[8f6dfe7]289 match_func_t.get_returnVals().push_back( unused_index_obj );
[307a732]290 match_func_t.get_parameters().push_back( exception_obj.clone() );
291 handle_func_t.get_returnVals().push_back( bool_obj.clone() );
292 handle_func_t.get_parameters().push_back( exception_obj.clone() );
293 finally_func_t.get_parameters().push_back( voidptr_obj.clone() );
[ba912706]294 }
295
296 // TryStmt Mutation Helpers
297
[046a890]298 CompoundStmt * TryMutatorCore::take_try_block( TryStmt *tryStmt ) {
[ba912706]299 CompoundStmt * block = tryStmt->get_block();
300 tryStmt->set_block( nullptr );
301 return block;
302 }
[948b0c8]303
[046a890]304 FunctionDecl * TryMutatorCore::create_try_wrapper(
[948b0c8]305 CompoundStmt *body ) {
[ba912706]306
[288eede]307 return new FunctionDecl( "try", Type::StorageClasses(),
[307a732]308 LinkageSpec::Cforall, try_func_t.clone(), body );
[ba912706]309 }
310
[046a890]311 FunctionDecl * TryMutatorCore::create_terminate_catch(
[948b0c8]312 CatchList &handlers ) {
[ba912706]313 std::list<CaseStmt *> handler_wrappers;
314
[288eede]315 FunctionType *func_type = catch_func_t.clone();
316 DeclarationWithType * index_obj = func_type->get_parameters().front();
[86d5ba7c]317 DeclarationWithType * except_obj = func_type->get_parameters().back();
[288eede]318
[ba912706]319 // Index 1..{number of handlers}
320 int index = 0;
321 CatchList::iterator it = handlers.begin();
322 for ( ; it != handlers.end() ; ++it ) {
323 ++index;
324 CatchStmt * handler = *it;
325
[288eede]326 // case `index`:
327 // {
[cbce272]328 // `handler.decl` = { (virtual `decl.type`)`except` };
329 // `handler.body`;
[288eede]330 // }
331 // return;
[ba3706f]332 CompoundStmt * block = new CompoundStmt();
[86d5ba7c]333
[03eedd5]334 // Just copy the exception value. (Post Validation)
[86d5ba7c]335 ObjectDecl * handler_decl =
[03eedd5]336 static_cast<ObjectDecl *>( handler->get_decl() );
[86d5ba7c]337 ObjectDecl * local_except = handler_decl->clone();
[03eedd5]338 local_except->set_init(
[86d5ba7c]339 new ListInit({ new SingleInit(
340 new VirtualCastExpr( nameOf( except_obj ),
341 local_except->get_type()
342 )
[03eedd5]343 ) })
344 );
[ba3706f]345 block->push_back( new DeclStmt( local_except ) );
[86d5ba7c]346
347 // Add the cleanup attribute.
348 local_except->get_attributes().push_back( new Attribute(
349 "cleanup",
[3090127]350 { new NameExpr( "__cfaehm_cleanup_terminate" ) }
[86d5ba7c]351 ) );
352
353 // Update variables in the body to point to this local copy.
354 {
[7862059]355 DeclReplacer::DeclMap mapping;
[86d5ba7c]356 mapping[ handler_decl ] = local_except;
[7862059]357 DeclReplacer::replace( handler->body, mapping );
[86d5ba7c]358 }
359
[7543dec]360 block->push_back( handler->body );
361 handler->body = nullptr;
[288eede]362
[86d5ba7c]363 std::list<Statement *> caseBody
[ba3706f]364 { block, new ReturnStmt( nullptr ) };
[288eede]365 handler_wrappers.push_back( new CaseStmt(
[ba912706]366 new ConstantExpr( Constant::from_int( index ) ),
[288eede]367 caseBody
368 ) );
[ba912706]369 }
370 // TODO: Some sort of meaningful error on default perhaps?
371
[288eede]372 std::list<Statement*> stmt_handlers;
373 while ( !handler_wrappers.empty() ) {
374 stmt_handlers.push_back( handler_wrappers.front() );
375 handler_wrappers.pop_front();
376 }
377
[ba912706]378 SwitchStmt * handler_lookup = new SwitchStmt(
[288eede]379 nameOf( index_obj ),
380 stmt_handlers
[ba912706]381 );
[ba3706f]382 CompoundStmt * body = new CompoundStmt();
[ba912706]383 body->push_back( handler_lookup );
384
385 return new FunctionDecl("catch", Type::StorageClasses(),
[288eede]386 LinkageSpec::Cforall, func_type, body);
[ba912706]387 }
388
389 // Create a single check from a moddified handler.
[288eede]390 // except_obj is referenced, modded_handler will be freed.
[046a890]391 CompoundStmt * TryMutatorCore::create_single_matcher(
[288eede]392 DeclarationWithType * except_obj, CatchStmt * modded_handler ) {
[86d5ba7c]393 // {
394 // `modded_handler.decl`
[cbce272]395 // if ( `decl.name = (virtual `decl.type`)`except`
[86d5ba7c]396 // [&& `modded_handler.cond`] ) {
397 // `modded_handler.body`
398 // }
399 // }
400
[ba3706f]401 CompoundStmt * block = new CompoundStmt();
[cbce272]402
403 // Local Declaration
404 ObjectDecl * local_except =
405 dynamic_cast<ObjectDecl *>( modded_handler->get_decl() );
406 assert( local_except );
[ba3706f]407 block->push_back( new DeclStmt( local_except ) );
[cbce272]408
[86d5ba7c]409 // Check for type match.
410 Expression * cond = UntypedExpr::createAssign( nameOf( local_except ),
411 new VirtualCastExpr( nameOf( except_obj ),
412 local_except->get_type()->clone() ) );
[ba912706]413
[86d5ba7c]414 // Add the check on the conditional if it is provided.
[ba912706]415 if ( modded_handler->get_cond() ) {
[288eede]416 cond = new LogicalExpr( cond, modded_handler->get_cond() );
[ba912706]417 }
[86d5ba7c]418 // Construct the match condition.
[ba3706f]419 block->push_back( new IfStmt(
[288eede]420 cond, modded_handler->get_body(), nullptr ) );
[ba912706]421
422 modded_handler->set_decl( nullptr );
423 modded_handler->set_cond( nullptr );
424 modded_handler->set_body( nullptr );
425 delete modded_handler;
426 return block;
427 }
428
[046a890]429 FunctionDecl * TryMutatorCore::create_terminate_match(
[948b0c8]430 CatchList &handlers ) {
[86d5ba7c]431 // int match(exception * except) {
432 // HANDLER WRAPPERS { return `index`; }
433 // }
434
[ba3706f]435 CompoundStmt * body = new CompoundStmt();
[ba912706]436
[288eede]437 FunctionType * func_type = match_func_t.clone();
438 DeclarationWithType * except_obj = func_type->get_parameters().back();
439
[ba912706]440 // Index 1..{number of handlers}
441 int index = 0;
442 CatchList::iterator it;
443 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
444 ++index;
445 CatchStmt * handler = *it;
446
[288eede]447 // Body should have been taken by create_terminate_catch.
448 assert( nullptr == handler->get_body() );
449
450 // Create new body.
[ba3706f]451 handler->set_body( new ReturnStmt(
[ba912706]452 new ConstantExpr( Constant::from_int( index ) ) ) );
453
[288eede]454 // Create the handler.
455 body->push_back( create_single_matcher( except_obj, handler ) );
456 *it = nullptr;
[ba912706]457 }
458
[ba3706f]459 body->push_back( new ReturnStmt(
[e9145a3]460 new ConstantExpr( Constant::from_int( 0 ) ) ) );
[307a732]461
[ba912706]462 return new FunctionDecl("match", Type::StorageClasses(),
[288eede]463 LinkageSpec::Cforall, func_type, body);
[ba912706]464 }
465
[046a890]466 CompoundStmt * TryMutatorCore::create_terminate_caller(
[ba912706]467 FunctionDecl * try_wrapper,
468 FunctionDecl * terminate_catch,
[948b0c8]469 FunctionDecl * terminate_match ) {
[3090127]470 // { __cfaehm_try_terminate(`try`, `catch`, `match`); }
[ba912706]471
[288eede]472 UntypedExpr * caller = new UntypedExpr( new NameExpr(
[3090127]473 "__cfaehm_try_terminate" ) );
[288eede]474 std::list<Expression *>& args = caller->get_args();
[ba912706]475 args.push_back( nameOf( try_wrapper ) );
476 args.push_back( nameOf( terminate_catch ) );
477 args.push_back( nameOf( terminate_match ) );
478
[ba3706f]479 CompoundStmt * callStmt = new CompoundStmt();
480 callStmt->push_back( new ExprStmt( caller ) );
[288eede]481 return callStmt;
[ba912706]482 }
483
[046a890]484 FunctionDecl * TryMutatorCore::create_resume_handler(
[948b0c8]485 CatchList &handlers ) {
[86d5ba7c]486 // bool handle(exception * except) {
487 // HANDLER WRAPPERS { `hander->body`; return true; }
488 // }
[ba3706f]489 CompoundStmt * body = new CompoundStmt();
[288eede]490
[e9145a3]491 FunctionType * func_type = handle_func_t.clone();
[288eede]492 DeclarationWithType * except_obj = func_type->get_parameters().back();
[ba912706]493
494 CatchList::iterator it;
495 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
496 CatchStmt * handler = *it;
497
498 // Modifiy body.
499 CompoundStmt * handling_code =
500 dynamic_cast<CompoundStmt*>( handler->get_body() );
501 if ( ! handling_code ) {
[ba3706f]502 handling_code = new CompoundStmt();
[ba912706]503 handling_code->push_back( handler->get_body() );
504 }
[ba3706f]505 handling_code->push_back( new ReturnStmt(
[ad0be81]506 new ConstantExpr( Constant::from_bool( true ) ) ) );
[ba912706]507 handler->set_body( handling_code );
508
509 // Create the handler.
[288eede]510 body->push_back( create_single_matcher( except_obj, handler ) );
511 *it = nullptr;
[ba912706]512 }
513
[ba3706f]514 body->push_back( new ReturnStmt(
[e9145a3]515 new ConstantExpr( Constant::from_bool( false ) ) ) );
[ad0be81]516
[ba912706]517 return new FunctionDecl("handle", Type::StorageClasses(),
[288eede]518 LinkageSpec::Cforall, func_type, body);
[ba912706]519 }
520
[046a890]521 CompoundStmt * TryMutatorCore::create_resume_wrapper(
[ba912706]522 Statement * wraps,
523 FunctionDecl * resume_handler ) {
[ba3706f]524 CompoundStmt * body = new CompoundStmt();
[ba912706]525
[288eede]526 // struct __try_resume_node __resume_node
[3090127]527 // __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
[288eede]528 // ** unwinding of the stack here could cause problems **
529 // ** however I don't think that can happen currently **
[3090127]530 // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
[ba912706]531
532 std::list< Attribute * > attributes;
533 {
534 std::list< Expression * > attr_params;
[288eede]535 attr_params.push_back( new NameExpr(
[3090127]536 "__cfaehm_try_resume_cleanup" ) );
[288eede]537 attributes.push_back( new Attribute( "cleanup", attr_params ) );
[ba912706]538 }
539
[288eede]540 ObjectDecl * obj = new ObjectDecl(
541 "__resume_node",
[ba912706]542 Type::StorageClasses(),
543 LinkageSpec::Cforall,
544 nullptr,
[288eede]545 new StructInstType(
546 Type::Qualifiers(),
547 node_decl
548 ),
549 nullptr,
[ba912706]550 attributes
[288eede]551 );
552 appendDeclStmt( body, obj );
553
554 UntypedExpr *setup = new UntypedExpr( new NameExpr(
[3090127]555 "__cfaehm_try_resume_setup" ) );
[307a732]556 setup->get_args().push_back( new AddressExpr( nameOf( obj ) ) );
[288eede]557 setup->get_args().push_back( nameOf( resume_handler ) );
558
[ba3706f]559 body->push_back( new ExprStmt( setup ) );
[288eede]560
[ba912706]561 body->push_back( wraps );
562 return body;
563 }
564
[046a890]565 FunctionDecl * TryMutatorCore::create_finally_wrapper(
[948b0c8]566 TryStmt * tryStmt ) {
[66ba544]567 // void finally() { `finally->block` }
[288eede]568 FinallyStmt * finally = tryStmt->get_finally();
569 CompoundStmt * body = finally->get_block();
570 finally->set_block( nullptr );
571 delete finally;
[ba912706]572 tryStmt->set_finally( nullptr );
573
574 return new FunctionDecl("finally", Type::StorageClasses(),
[307a732]575 LinkageSpec::Cforall, finally_func_t.clone(), body);
[ba912706]576 }
577
[046a890]578 ObjectDecl * TryMutatorCore::create_finally_hook(
[948b0c8]579 FunctionDecl * finally_wrapper ) {
[3090127]580 // struct __cfaehm_cleanup_hook __finally_hook
[046a890]581 // __attribute__((cleanup( `finally_wrapper` )));
[ba912706]582
583 // Make Cleanup Attribute.
584 std::list< Attribute * > attributes;
585 {
586 std::list< Expression * > attr_params;
587 attr_params.push_back( nameOf( finally_wrapper ) );
[288eede]588 attributes.push_back( new Attribute( "cleanup", attr_params ) );
[ba912706]589 }
590
[288eede]591 return new ObjectDecl(
592 "__finally_hook",
[ba912706]593 Type::StorageClasses(),
594 LinkageSpec::Cforall,
595 nullptr,
[288eede]596 new StructInstType(
[ac10576]597 noQualifiers,
[288eede]598 hook_decl
599 ),
[ba912706]600 nullptr,
601 attributes
602 );
603 }
604
[948b0c8]605 // Visiting/Mutating Functions
[046a890]606 void TryMutatorCore::premutate( StructDecl *structDecl ) {
[86d5ba7c]607 if ( !structDecl->has_body() ) {
608 // Skip children?
609 return;
[3090127]610 } else if ( structDecl->get_name() == "__cfaehm_base_exception_t" ) {
[cbce272]611 assert( nullptr == except_decl );
612 except_decl = structDecl;
613 init_func_types();
[3090127]614 } else if ( structDecl->get_name() == "__cfaehm_try_resume_node" ) {
[86d5ba7c]615 assert( nullptr == node_decl );
616 node_decl = structDecl;
[3090127]617 } else if ( structDecl->get_name() == "__cfaehm_cleanup_hook" ) {
[86d5ba7c]618 assert( nullptr == hook_decl );
619 hook_decl = structDecl;
620 }
621 }
622
[046a890]623 Statement * TryMutatorCore::postmutate( ThrowStmt * ) {
624 // All throws should be removed by this point.
625 assert( false );
[ba912706]626 }
627
[046a890]628 Statement * TryMutatorCore::postmutate( TryStmt *tryStmt ) {
[cbce272]629 assert( except_decl );
[288eede]630 assert( node_decl );
631 assert( hook_decl );
632
[ba912706]633 // Generate a prefix for the function names?
634
[ba3706f]635 CompoundStmt * block = new CompoundStmt();
[288eede]636 CompoundStmt * inner = take_try_block( tryStmt );
[ba912706]637
638 if ( tryStmt->get_finally() ) {
639 // Define the helper function.
640 FunctionDecl * finally_block =
641 create_finally_wrapper( tryStmt );
642 appendDeclStmt( block, finally_block );
643 // Create and add the finally cleanup hook.
[948b0c8]644 appendDeclStmt( block, create_finally_hook( finally_block ) );
[ba912706]645 }
646
[288eede]647 CatchList termination_handlers;
648 CatchList resumption_handlers;
649 split( tryStmt->get_catchers(),
[1abc5ab]650 termination_handlers, resumption_handlers );
[ba912706]651
[288eede]652 if ( resumption_handlers.size() ) {
[ba912706]653 // Define the helper function.
654 FunctionDecl * resume_handler =
655 create_resume_handler( resumption_handlers );
656 appendDeclStmt( block, resume_handler );
657 // Prepare hooks
[948b0c8]658 inner = create_resume_wrapper( inner, resume_handler );
[ba912706]659 }
660
661 if ( termination_handlers.size() ) {
662 // Define the three helper functions.
663 FunctionDecl * try_wrapper = create_try_wrapper( inner );
664 appendDeclStmt( block, try_wrapper );
665 FunctionDecl * terminate_catch =
666 create_terminate_catch( termination_handlers );
667 appendDeclStmt( block, terminate_catch );
668 FunctionDecl * terminate_match =
669 create_terminate_match( termination_handlers );
670 appendDeclStmt( block, terminate_match );
671 // Build the call to the try wrapper.
672 inner = create_terminate_caller(
673 try_wrapper, terminate_catch, terminate_match );
674 }
675
676 // Embed the try block.
677 block->push_back( inner );
678
679 return block;
680 }
681
[046a890]682 void translateThrows( std::list< Declaration *> & translationUnit ) {
683 PassVisitor<ThrowMutatorCore> translator;
684 mutateAll( translationUnit, translator );
685 }
686
687 void translateTries( std::list< Declaration *> & translationUnit ) {
688 PassVisitor<TryMutatorCore> translator;
[6fca7ea]689 mutateAll( translationUnit, translator );
[ba912706]690 }
691}
Note: See TracBrowser for help on using the repository browser.