source: src/ControlStruct/ExceptTranslate.cc@ fa4805f

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 fa4805f was ba912706, checked in by Andrew Beach <ajbeach@…>, 8 years ago

Exception translation code (draft) added.

  • Property mode set to 100644
File size: 13.8 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 22 15:57:00 2017
13// Update Count : 0
14//
15
16#include "ExceptTranslate.h"
17#include "Common/PassVisitor.h"
18
19namespace ControlFlow {
20
21 // This (large) section could probably be moved out of the class
22 // and be static helpers instead.
23
24 // Type(Qualifiers &, false, std::list<Attribute *> &)
25
26 // void (*function)()
27 static FunctionType void_func_t(Type::Qualifiers(), false);
28 // void (*function)(int, exception);
29 static FunctionType catch_func_t(Type::Qualifiers(), false);
30 // int (*function)(exception);
31 static FunctionType match_func_t(Type::Qualifiers(), false);
32 // bool (*function)(exception);
33 static FunctionType handle_func_t(Type::Qualifiers(), false);
34
35 static void init_func_types() {
36 static init_complete = false;
37 if (init_complete) {
38 return;
39 }
40 ObjectDecl index_obj(
41 "index_t",
42 Type::StorageClasses(),
43 LinkageSpec::Cforall,
44 /*bitfieldWidth*/ NULL,
45 new BasicType(emptyQualifiers, BasicType::UnsignedInt),
46 /*init*/ NULL
47 );
48 ObjectDecl exception_obj(
49 "exception_t",
50 Type::StorageClasses(),
51 LinkageSpec::Cforall,
52 /*bitfieldWidth*/ NULL,
53 new BasicType(emptyQualifiers, BasicType::UnsignedInt),
54 /*init*/ NULL
55 );
56 ObjectDecl bool_obj(
57 "bool_t",
58 Type::StorageClasses(),
59 LinkageSpec::Cforall,
60 /*bitfieldWidth*/ NULL,
61 new BasicType(emptyQualifiers, BasicType::Bool),
62 /*init*/ NULL
63 );
64
65 catch_func_t.get_parameters().push_back(index_obj.clone());
66 catch_func_t.get_parameters().push_back(exception_obj.clone());
67 match_func_t.get_returnVals().push_back(index_obj.clone());
68 match_func_t.get_parameters().push_back(exception_obj.clone());
69 handle_func_t.get_returnVals().push_back(bool_obj.clone());
70 handle_func_t.get_parameters().push_back(exception_obj.clone());
71
72 init_complete = true;
73 }
74
75 // Buricratic Helpers (Not having to do with the paritular operation.)
76
77 typedef std::list<CatchStmt*> CatchList;
78
79 void split( CatchList& allHandlers, CatchList& terHandlers,
80 CatchList& resHandlers ) {
81 while ( !allHandlers.empty() ) {
82 Statement * stmt = allHandlers.front();
83 allHandlers.pop_front();
84 if (CaseStmt::Terminate == stmt->get_kind()) {
85 terHandlers.push_back(stmt);
86 } else {
87 resHandlers.push_back(stmt);
88 }
89 }
90 }
91
92 template<typename T>
93 void free_all( std::list<T *> &list ) {
94 std::list<T *>::iterator it;
95 for ( it = list.begin() ; it != list.end() ; ++it ) {
96 delete *it;
97 }
98 list.clear();
99 }
100
101 void appendDeclStmt( CompoundStmt * block, Declaration * item ) {
102 block->push_back(new DeclStmt(no_labels, item));
103 }
104
105 Expression * nameOf( FunctionDecl * function ) {
106 return new VariableExpr( function );
107 }
108
109 // ThrowStmt Mutation Helpers
110
111 Statement * create_terminate_throw( ThrowStmt *throwStmt ) {
112 // __throw_terminate( EXPR );
113 ApplicationExpr * call = new ApplicationExpr( /* ... */ );
114 call->get_args.push_back( throwStmt->get_expr() );
115 Statement * result = new ExprStmt( throwStmt->get_labels(), call );
116 throwStmt->set_expr( nullptr );
117 delete throwStmt;
118 return result;
119 }
120 Statement * create_terminate_rethrow( ThrowStmt *throwStmt ) {
121 // __rethrow_terminate();
122 Statement * result = new ExprStmt(
123 throwStmt->get_labels(),
124 new ApplicationExpr( /* ... */ );
125 );
126 delete throwStmt;
127 return result;
128 }
129 Statement * create_resume_throw( ThrowStmt *throwStmt ) {
130 // __throw_resume( EXPR );
131 ApplicationExpr * call = new ApplicationExpr( /* ... */ );
132 call->get_args.push_back( throwStmt->get_expr() );
133 Statement * result = new ExprStmt( throwStmt->get_labels(), call );
134 throwStmt->set_expr( nullptr );
135 delete throwStmt;
136 return result;
137 }
138 Statement * create_resume_rethrow( ThrowStmt *throwStmt ) {
139 // return false;
140 Statement * result = new ReturnStmt(
141 throwStmt->get_labels(),
142 new ConstantExpr(
143 Constant(
144 new BasicType(
145 Type::Qualifiers(),
146 BasicType::Bool
147 ),
148 "0")
149 )
150 );
151 delete throwStmt;
152 return result;
153 }
154
155 // TryStmt Mutation Helpers
156
157 CompoundStmt * take_try_block( TryStmt *tryStmt ) {
158 CompoundStmt * block = tryStmt->get_block();
159 tryStmt->set_block( nullptr );
160 return block;
161 }
162 FunctionDecl * create_try_wrapper( TryStmt *tryStmt ) {
163 CompoundStmt * body = base_try->get_block();
164 base_try->set_block(nullptr);
165
166 return new FunctionDecl("try", Type::StorageClasses(),
167 LinkageSpec::Cforall, void_func_t, body);
168 }
169
170 FunctionDecl * create_terminate_catch( CatchList &handlers ) {
171 std::list<CaseStmt *> handler_wrappers;
172
173 // Index 1..{number of handlers}
174 int index = 0;
175 CatchList::iterator it = handlers.begin();
176 for ( ; it != handlers.end() ; ++it ) {
177 ++index;
178 CatchStmt * handler = *it;
179
180 std::list<Statement *> core;
181 if ( /*the exception is named*/ ) {
182 ObjectDecl * local_except = /* Dynamic case, same */;
183 core->push_back( new DeclStmt( noLabel, local_except ) );
184 }
185 // Append the provided statement to the handler.
186 core->push_back( cur_handler->get_body() );
187 // Append return onto the inner block? case stmt list?
188 CaseStmt * wrapper = new CaseStmt(
189 noLabels,
190 new ConstantExpr( Constant::from_int( index ) ),
191 core
192 );
193 handler_wrappers.push_back(wrapper);
194 }
195 // TODO: Some sort of meaningful error on default perhaps?
196
197 SwitchStmt * handler_lookup = new SwitchStmt(
198 noLabels,
199 /*parameter 0: index*/,
200 handler_wrappers,
201 false
202 );
203 CompoundStmt * body = new CompoundStmt( noLabels );
204 body->push_back( handler_lookup );
205
206 return new FunctionDecl("catch", Type::StorageClasses(),
207 LinkageSpec::Cforall, catch_func_t, body);
208 }
209
210 // Create a single check from a moddified handler.
211 CompoundStmt *create_single_matcher( CatchStmt * modded_handler ) {
212 CompoundStmt * block = new CompoundStmt( noLables );
213
214 appendDeclStmt( block, modded_handler->get_decl() );
215
216 // TODO: This is not the actual check.
217 LogicalExpr * cond = new ConstantExpr( Constant::from_bool( false ) );
218
219 if ( modded_handler->get_cond() ) {
220 cond = new LogicalExpr( cond, modded_handler->get_cond() )q
221 }
222 block->push_back( new IfStmt( noLabels,
223 cond, modded_handler->get_body() );
224
225 modded_handler->set_decl( nullptr );
226 modded_handler->set_cond( nullptr );
227 modded_handler->set_body( nullptr );
228 delete modded_handler;
229 return block;
230 }
231
232 FunctionDecl * create_terminate_match( CatchList &handlers ) {
233 CompoundStmt * body = new CompoundStmt( noLabels );
234
235 // Index 1..{number of handlers}
236 int index = 0;
237 CatchList::iterator it;
238 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
239 ++index;
240 CatchStmt * handler = *it;
241
242 // body should have been taken by create_terminate_catch.
243 // assert( nullptr == handler->get_body() );
244 handler->set_body( new ReturnStmt( noLabels,
245 new ConstantExpr( Constant::from_int( index ) ) ) );
246
247 body->push_back( create_single_matcher( handler ) );
248 }
249
250 return new FunctionDecl("match", Type::StorageClasses(),
251 LinkageSpec::Cforall, match_func_t, body);
252 }
253
254 Statement * create_terminate_caller(
255 FunctionDecl * try_wrapper,
256 FunctionDecl * terminate_catch,
257 FunctionDecl * terminate_match) {
258
259 ApplicationExpr * caller = new ApplicationExpr( /* ... */ );
260 std::list<Expression *>& args = caller.get_args();
261 args.push_back( nameOf( try_wrapper ) );
262 args.push_back( nameOf( terminate_catch ) );
263 args.push_back( nameOf( terminate_match ) );
264
265 return new ExprStmt( noLabels, caller );
266 }
267
268 FunctionDecl * create_resume_handler( CatchList &handlers ) {
269 CompoundStmt * body = new CompountStmt( noLabels );
270
271 CatchList::iterator it;
272 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
273 CatchStmt * handler = *it;
274
275 // Modifiy body.
276 CompoundStmt * handling_code =
277 dynamic_cast<CompoundStmt*>( handler->get_body() );
278 if ( ! handling_code ) {
279 handling_code = new CompoundStmt( noLabels );
280 handling_code->push_back( handler->get_body() );
281 }
282 handling_code->push_back( new ReturnStmt( noLabel,
283 new ConstantExpr( Constant::from_bool( false ) ) ) );
284 handler->set_body( handling_code );
285
286 // Create the handler.
287 body->push_back( create_single_matcher( handler ) );
288 }
289
290 return new FunctionDecl("handle", Type::StorageClasses(),
291 LinkageSpec::Cforall, handle_func_t, body);
292 }
293
294 Statement * create_resume_wrapper(
295 Statement * wraps,
296 FunctionDecl * resume_handler ) {
297 CompoundStmt * body = new CompoundStmt( noLabels );
298
299 // struct node = {current top resume handler, call to resume_handler};
300 // __attribute__((cleanup( ... )));
301 // set top resume handler to node.
302 // The wrapped statement.
303
304 ListInit * node_init;
305 {
306 std::list<Initializer*> field_inits;
307 field_inits.push_back( new SingleInit( /* ... */ ) );
308 field_inits.push_back( new SingleInit( nameOf( resume_handler ) ) );
309 node_init = new ListInit( field_inits );
310 }
311
312 std::list< Attribute * > attributes;
313 {
314 std::list< Expression * > attr_params;
315 attr_params.push_back( nameOf( /* ... deconstructor ... */ ) );
316 attrributes.push_back( new Attribute( "cleanup", attr_params ) );
317 }
318
319 appendDeclStmt( body,
320 /**/ ObjectDecl(
321 "resume_node",
322 Type::StorageClasses(),
323 LinkageSpec::Cforall,
324 nullptr,
325 /* Type* = resume_node */,
326 node_init,
327 attributes
328 )
329 );
330 body->push_back( wraps );
331 return body;
332 }
333
334 FunctionDecl * create_finally_wrapper( TryStmt * tryStmt ) {
335 CompoundStmt * body = tryStmt->get_finally();
336 tryStmt->set_finally( nullptr );
337
338 return new FunctionDecl("finally", Type::StorageClasses(),
339 LinkageSpec::Cforall, void_func_t, body);
340 }
341
342 ObjectDecl * create_finally_hook( FunctionDecl * finally_wrapper ) {
343 // struct _cleanup_hook NAME __attribute__((cleanup( ... )));
344
345 // Make Cleanup Attribute.
346 std::list< Attribute * > attributes;
347 {
348 std::list< Expression * > attr_params;
349 attr_params.push_back( nameOf( finally_wrapper ) );
350 attrributes.push_back( new Attribute( "cleanup", attr_params ) );
351 }
352
353 return ObjectDecl( /* ... */
354 const std::string &name "finally_hook",
355 Type::StorageClasses(),
356 LinkageSpec::Cforall,
357 nullptr,
358 /* ... Type * ... */,
359 nullptr,
360 attributes
361 );
362 }
363
364
365 class ExceptionMutatorCore : public WithScoping {
366 enum Context { NoHandler, TerHandler, ResHandler };
367
368 // Also need to handle goto, break & continue.
369 // They need to be cut off in a ResHandler, until we enter another
370 // loop, switch or the goto stays within the function.
371
372 Context curContext;
373
374 // We might not need this, but a unique base for each try block's
375 // generated functions might be nice.
376 //std::string curFunctionName;
377 //unsigned int try_count = 0;
378
379
380 public:
381 ExceptionMutatorCore() :
382 curContext(NoHandler)
383 {}
384
385 void premutate( CatchStmt *tryStmt );
386 Statement * postmutate( ThrowStmt *throwStmt );
387 Statement * postmutate( TryStmt *tryStmt );
388 };
389
390 Statement * ExceptionMutatorCore::postmutate( ThrowStmt *throwStmt ) {
391 // Ignoring throwStmt->get_target() for now.
392 if ( ThrowStmt::Terminate == throwStmt->get_kind() ) {
393 if ( throwStmt->get_expr() ) {
394 return create_terminate_throw( throwStmt );
395 } else if ( TerHandler == curContext ) {
396 return create_terminate_rethrow( throwStmt );
397 } else {
398 assertf(false, "Invalid throw in %s at %i\n",
399 throwStmt->location.filename,
400 throwStmt->location.linenumber);
401 return nullptr;
402 }
403 } else {
404 if ( throwStmt->get_expr() ) {
405 return create_resume_throw( throwStmt );
406 } else if ( ResHandler == curContext ) {
407 return create_resume_rethrow( throwStmt );
408 } else {
409 assertf(false, "Invalid throwResume in %s at %i\n",
410 throwStmt->location.filename,
411 throwStmt->location.linenumber);
412 return nullptr;
413 }
414 }
415 }
416
417 Statement * ExceptionMutatorCore::postmutate( TryStmt *tryStmt ) {
418 // Generate a prefix for the function names?
419
420 CompoundStmt * block = new CompoundStmt();
421 Statement * inner = take_try_block( tryStmt );
422
423 if ( tryStmt->get_finally() ) {
424 // Define the helper function.
425 FunctionDecl * finally_block =
426 create_finally_wrapper( tryStmt );
427 appendDeclStmt( block, finally_block );
428 // Create and add the finally cleanup hook.
429 appendDeclStmt( block, create_finally_hook( finally_block ) );
430 }
431
432 StatementList termination_handlers;
433 StatementList resumption_handlers;
434 split( tryStmt->get_handlers(),
435 termination_handlers, resumption_handlers );
436
437 if ( resumeption_handlers.size() ) {
438 // Define the helper function.
439 FunctionDecl * resume_handler =
440 create_resume_handler( resumption_handlers );
441 appendDeclStmt( block, resume_handler );
442 // Prepare hooks
443 inner = create_resume_wrapper( inner, resume_handler );
444 }
445
446 if ( termination_handlers.size() ) {
447 // Define the three helper functions.
448 FunctionDecl * try_wrapper = create_try_wrapper( inner );
449 appendDeclStmt( block, try_wrapper );
450 FunctionDecl * terminate_catch =
451 create_terminate_catch( termination_handlers );
452 appendDeclStmt( block, terminate_catch );
453 FunctionDecl * terminate_match =
454 create_terminate_match( termination_handlers );
455 appendDeclStmt( block, terminate_match );
456 // Build the call to the try wrapper.
457 inner = create_terminate_caller(
458 try_wrapper, terminate_catch, terminate_match );
459 }
460
461 // Embed the try block.
462 block->push_back( inner );
463
464 free_all( termination_handlers );
465 free_all( resumption_handlers );
466
467 return block;
468 }
469
470 void ExceptionMutatorCore::premutate( CatchStmt *catchStmt ) {
471 GuardValue( curContext );
472 if ( CatchStmt::Termination == catchStmt->get_kind() ) {
473 curContext = TerHandler;
474 } else {
475 curContext = ResHandler;
476 }
477 }
478
479 void translateEHM( std::list< Declaration *> & translationUnit ) {
480 PassVisitor<ExceptionMutatorCore> translator;
481 for ( Declaration * decl : translationUnit ) {
482 decl->mutate( translator );
483 }
484 }
485}
Note: See TracBrowser for help on using the repository browser.