source: src/ControlStruct/ExceptTranslate.cc@ 6fa409e

new-env
Last change on this file since 6fa409e was 1cdfa82, checked in by Aaron Moss <a3moss@…>, 7 years ago

Merge remote-tracking branch 'origin/master' into with_gc

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