source: src/ControlStruct/ExceptTranslate.cc@ 25b0fde

ADT ast-experimental
Last change on this file since 25b0fde was 5ee153d, checked in by Andrew Beach <ajbeach@…>, 4 years ago

Translated the Translate Throws pass to the new ast.

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