source: src/ControlStruct/ExceptTranslate.cc@ a4b3525

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 a4b3525 was 1abc5ab, checked in by Rob Schluntz <rschlunt@…>, 8 years ago

changed WithScopes to WithGuards

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