- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ControlStruct/ExceptTranslateNew.cpp
r5f3ba11 r0fba0d4 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Nov 8 11:53:00 2021 11 // Last Modified By : Andrew Beach12 // Last Modified On : Mon Nov 8 16:50:00 202113 // Update Count : 011 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 31 18:49:58 2022 13 // Update Count : 1 14 14 // 15 15 … … 20 20 #include "AST/Stmt.hpp" 21 21 #include "AST/TranslationUnit.hpp" 22 #include "AST/DeclReplacer.hpp"23 22 24 23 namespace ControlStruct { 25 26 namespace {27 28 typedef std::list<ast::CatchStmt*> CatchList;29 30 void split( CatchList& allHandlers, CatchList& terHandlers,31 CatchList& resHandlers ) {32 while ( !allHandlers.empty() ) {33 ast::CatchStmt * stmt = allHandlers.front();34 allHandlers.pop_front();35 if (stmt->kind == ast::ExceptionKind::Terminate) {36 terHandlers.push_back(stmt);37 } else {38 resHandlers.push_back(stmt);39 }40 }41 }42 43 void appendDeclStmt( ast::CompoundStmt * block, ast::DeclWithType * item ) {44 block->push_back(new ast::DeclStmt(block->location, item));45 }46 24 47 25 class TranslateThrowsCore : public ast::WithGuards { … … 148 126 } 149 127 150 151 class TryMutatorCore {152 // The built in types used in translation.153 const ast::StructDecl * except_decl;154 const ast::StructDecl * node_decl;155 const ast::StructDecl * hook_decl;156 157 // The many helper functions for code/syntree generation.158 ast::CompoundStmt * take_try_block( ast::TryStmt * tryStmt );159 ast::FunctionDecl * create_try_wrapper( const ast::CompoundStmt * body );160 ast::FunctionDecl * create_terminate_catch( CatchList &handlers );161 ast::CompoundStmt * create_single_matcher(162 const ast::DeclWithType * except_obj, ast::CatchStmt * modded_handler );163 ast::FunctionDecl * create_terminate_match( CatchList &handlers );164 ast::CompoundStmt * create_terminate_caller( CodeLocation loc, ast::FunctionDecl * try_wrapper,165 ast::FunctionDecl * terminate_catch, ast::FunctionDecl * terminate_match );166 ast::FunctionDecl * create_resume_handler( CatchList &handlers );167 ast::CompoundStmt * create_resume_wrapper(168 const ast::Stmt * wraps, const ast::FunctionDecl * resume_handler );169 ast::FunctionDecl * create_finally_wrapper( ast::TryStmt * tryStmt );170 ast::ObjectDecl * create_finally_hook( ast::FunctionDecl * finally_wrapper );171 ast::Stmt * create_resume_rethrow( const ast::ThrowStmt * throwStmt );172 173 // Types used in translation, make sure to use clone.174 // void (*function)();175 ast::FunctionDecl * try_func_t;176 // void (*function)(int, exception);177 ast::FunctionDecl * catch_func_t;178 // int (*function)(exception);179 ast::FunctionDecl * match_func_t;180 // bool (*function)(exception);181 ast::FunctionDecl * handle_func_t;182 // void (*function)(__attribute__((unused)) void *);183 ast::FunctionDecl * finally_func_t;184 185 ast::StructInstType * create_except_type() {186 assert( except_decl );187 return new ast::StructInstType( except_decl );188 }189 void init_func_types();190 191 public:192 TryMutatorCore() :193 except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr )194 {}195 196 void previsit( const ast::StructDecl *structDecl );197 ast::Stmt * postvisit( const ast::TryStmt *tryStmt );198 ast::Stmt * postvisit( const ast::ThrowStmt *throwStmt );199 };200 201 void TryMutatorCore::init_func_types() {202 assert( except_decl );203 204 ast::ObjectDecl index_obj(205 {},206 "__handler_index",207 new ast::BasicType(ast::BasicType::SignedInt)208 );209 ast::ObjectDecl exception_obj(210 {},211 "__exception_inst",212 new ast::PointerType(213 new ast::StructInstType( except_decl )214 ),215 NULL216 );217 ast::ObjectDecl bool_obj(218 {},219 "__ret_bool",220 new ast::BasicType( ast::BasicType::Bool ),221 nullptr, //init222 ast::Storage::Classes{},223 ast::Linkage::Cforall,224 nullptr, //width225 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }226 );227 ast::ObjectDecl voidptr_obj(228 {},229 "__hook",230 new ast::PointerType(231 new ast::VoidType()232 ),233 nullptr, //init234 ast::Storage::Classes{},235 ast::Linkage::Cforall,236 nullptr, //width237 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }238 );239 240 ast::ObjectDecl unused_index_obj(241 {},242 "__handler_index",243 new ast::BasicType(ast::BasicType::SignedInt),244 nullptr,245 ast::Storage::Classes{},246 ast::Linkage::Cforall,247 nullptr, //width248 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }249 );250 //unused_index_obj->attributes.push_back( new Attribute( "unused" ) );251 252 try_func_t = new ast::FunctionDecl(253 {},254 "try",255 {}, //forall256 {}, //no param257 {}, //no return258 nullptr,259 ast::Storage::Classes{},260 ast::Linkage::Cforall261 );262 263 catch_func_t = new ast::FunctionDecl(264 {},265 "catch",266 {}, //forall267 {ast::deepCopy(&index_obj), ast::deepCopy(&exception_obj)},//param268 {}, //return void269 nullptr,270 ast::Storage::Classes{},271 ast::Linkage::Cforall272 );273 274 match_func_t = new ast::FunctionDecl(275 {},276 "match",277 {}, //forall278 {ast::deepCopy(&exception_obj)},279 {ast::deepCopy(&unused_index_obj)},280 nullptr,281 ast::Storage::Classes{},282 ast::Linkage::Cforall283 );284 285 handle_func_t = new ast::FunctionDecl(286 {},287 "handle",288 {}, //forall289 {ast::deepCopy(&exception_obj)},290 {ast::deepCopy(&bool_obj)},291 nullptr,292 ast::Storage::Classes{},293 ast::Linkage::Cforall294 );295 296 finally_func_t = new ast::FunctionDecl(297 {},298 "finally",299 {}, //forall300 {ast::deepCopy(&voidptr_obj)},301 {}, //return void302 nullptr,303 ast::Storage::Classes{},304 ast::Linkage::Cforall305 );306 307 //catch_func_t.get_parameters().push_back( index_obj.clone() );308 //catch_func_t.get_parameters().push_back( exception_obj.clone() );309 //match_func_t.get_returnVals().push_back( unused_index_obj );310 //match_func_t.get_parameters().push_back( exception_obj.clone() );311 //handle_func_t.get_returnVals().push_back( bool_obj.clone() );312 //handle_func_t.get_parameters().push_back( exception_obj.clone() );313 //finally_func_t.get_parameters().push_back( voidptr_obj.clone() );314 }315 316 // TryStmt Mutation Helpers317 318 /*319 ast::CompoundStmt * TryMutatorCore::take_try_block( ast::TryStmt *tryStmt ) {320 ast::CompoundStmt * block = tryStmt->body;321 tryStmt->body = nullptr;322 return block;323 }324 */325 326 ast::FunctionDecl * TryMutatorCore::create_try_wrapper(327 const ast::CompoundStmt *body ) {328 329 ast::FunctionDecl * ret = ast::deepCopy(try_func_t);330 ret->stmts = body;331 return ret;332 }333 334 ast::FunctionDecl * TryMutatorCore::create_terminate_catch(335 CatchList &handlers ) {336 std::vector<ast::ptr<ast::Stmt>> handler_wrappers;337 338 assert (!handlers.empty());339 const CodeLocation loc = handlers.front()->location;340 341 ast::FunctionDecl * func_t = ast::deepCopy(catch_func_t);342 const ast::DeclWithType * index_obj = func_t->params.front();343 const ast::DeclWithType * except_obj = func_t->params.back();344 345 // Index 1..{number of handlers}346 int index = 0;347 CatchList::iterator it = handlers.begin();348 for ( ; it != handlers.end() ; ++it ) {349 ++index;350 ast::CatchStmt * handler = *it;351 const CodeLocation loc = handler->location;352 353 // case `index`:354 // {355 // `handler.decl` = { (virtual `decl.type`)`except` };356 // `handler.body`;357 // }358 // return;359 ast::CompoundStmt * block = new ast::CompoundStmt(loc);360 361 // Just copy the exception value. (Post Validation)362 const ast::ObjectDecl * handler_decl =363 handler->decl.strict_as<ast::ObjectDecl>();364 ast::ObjectDecl * local_except = ast::deepCopy(handler_decl);365 ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,366 new ast::VariableExpr( loc, except_obj ),367 local_except->get_type()368 );369 vcex->location = handler->location;370 local_except->init = new ast::ListInit(loc, { new ast::SingleInit( loc, vcex ) });371 block->push_back( new ast::DeclStmt( loc, local_except ) );372 373 // Add the cleanup attribute.374 local_except->attributes.push_back( new ast::Attribute(375 "cleanup",376 { new ast::NameExpr( loc, "__cfaehm_cleanup_terminate" ) }377 ) );378 379 ast::DeclReplacer::DeclMap mapping;380 mapping[handler_decl] = local_except;381 const ast::Stmt * mutBody = strict_dynamic_cast<const ast::Stmt *>(382 ast::DeclReplacer::replace(handler->body, mapping));383 384 385 block->push_back( mutBody );386 // handler->body = nullptr;387 388 handler_wrappers.push_back( new ast::CaseStmt(loc,389 ast::ConstantExpr::from_int(loc, index) ,390 { block, new ast::ReturnStmt( loc, nullptr ) }391 ));392 }393 // TODO: Some sort of meaningful error on default perhaps?394 395 /*396 std::list<Statement*> stmt_handlers;397 while ( !handler_wrappers.empty() ) {398 stmt_handlers.push_back( handler_wrappers.front() );399 handler_wrappers.pop_front();400 }401 */402 403 ast::SwitchStmt * handler_lookup = new ast::SwitchStmt(loc,404 new ast::VariableExpr( loc, index_obj ),405 std::move(handler_wrappers)406 );407 ast::CompoundStmt * body = new ast::CompoundStmt(loc,408 {handler_lookup});409 410 func_t->stmts = body;411 return func_t;412 }413 414 // Create a single check from a moddified handler.415 // except_obj is referenced, modded_handler will be freed.416 ast::CompoundStmt * TryMutatorCore::create_single_matcher(417 const ast::DeclWithType * except_obj, ast::CatchStmt * modded_handler ) {418 // {419 // `modded_handler.decl`420 // if ( `decl.name = (virtual `decl.type`)`except`421 // [&& `modded_handler.cond`] ) {422 // `modded_handler.body`423 // }424 // }425 426 const CodeLocation loc = modded_handler->location;427 ast::CompoundStmt * block = new ast::CompoundStmt(loc);428 429 // Local Declaration430 const ast::ObjectDecl * local_except =431 modded_handler->decl.strict_as<ast::ObjectDecl>();432 block->push_back( new ast::DeclStmt( loc, local_except ) );433 434 // Check for type match.435 ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,436 new ast::VariableExpr(loc, except_obj ),437 local_except->get_type()438 );439 ast::Expr * cond = ast::UntypedExpr::createAssign(loc,440 new ast::VariableExpr(loc, local_except ), vcex );441 442 // Add the check on the conditional if it is provided.443 if ( modded_handler->cond ) {444 cond = new ast::LogicalExpr( loc, cond, modded_handler->cond, ast::LogicalFlag::AndExpr );445 }446 // Construct the match condition.447 block->push_back( new ast::IfStmt(loc,448 cond, modded_handler->body, nullptr ) );449 450 // xxx - how does this work in new ast451 //modded_handler->set_decl( nullptr );452 //modded_handler->set_cond( nullptr );453 //modded_handler->set_body( nullptr );454 //delete modded_handler;455 return block;456 }457 458 ast::FunctionDecl * TryMutatorCore::create_terminate_match(459 CatchList &handlers ) {460 // int match(exception * except) {461 // HANDLER WRAPPERS { return `index`; }462 // }463 464 assert (!handlers.empty());465 const CodeLocation loc = handlers.front()->location;466 467 ast::CompoundStmt * body = new ast::CompoundStmt(loc);468 469 ast::FunctionDecl * func_t = ast::deepCopy(match_func_t);470 const ast::DeclWithType * except_obj = func_t->params.back();471 472 // Index 1..{number of handlers}473 int index = 0;474 CatchList::iterator it;475 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {476 ++index;477 ast::CatchStmt * handler = *it;478 479 // Body should have been taken by create_terminate_catch.480 // xxx - just ignore it?481 // assert( nullptr == handler->get_body() );482 483 // Create new body.484 handler->body = new ast::ReturnStmt( handler->location,485 ast::ConstantExpr::from_int( handler->location, index ) );486 487 // Create the handler.488 body->push_back( create_single_matcher( except_obj, handler ) );489 *it = nullptr;490 }491 492 body->push_back( new ast::ReturnStmt(loc,493 ast::ConstantExpr::from_int( loc, 0 ) ));494 495 func_t->stmts = body;496 497 return func_t;498 }499 500 ast::CompoundStmt * TryMutatorCore::create_terminate_caller(501 CodeLocation loc,502 ast::FunctionDecl * try_wrapper,503 ast::FunctionDecl * terminate_catch,504 ast::FunctionDecl * terminate_match ) {505 // { __cfaehm_try_terminate(`try`, `catch`, `match`); }506 507 ast::UntypedExpr * caller = new ast::UntypedExpr(loc, new ast::NameExpr(loc,508 "__cfaehm_try_terminate" ) );509 caller->args.push_back( new ast::VariableExpr(loc, try_wrapper ) );510 caller->args.push_back( new ast::VariableExpr(loc, terminate_catch ) );511 caller->args.push_back( new ast::VariableExpr(loc, terminate_match ) );512 513 ast::CompoundStmt * callStmt = new ast::CompoundStmt(loc);514 callStmt->push_back( new ast::ExprStmt( loc, caller ) );515 return callStmt;516 }517 518 ast::FunctionDecl * TryMutatorCore::create_resume_handler(519 CatchList &handlers ) {520 // bool handle(exception * except) {521 // HANDLER WRAPPERS { `hander->body`; return true; }522 // }523 assert (!handlers.empty());524 const CodeLocation loc = handlers.front()->location;525 ast::CompoundStmt * body = new ast::CompoundStmt(loc);526 527 ast::FunctionDecl * func_t = ast::deepCopy(handle_func_t);528 const ast::DeclWithType * except_obj = func_t->params.back();529 530 CatchList::iterator it;531 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {532 ast::CatchStmt * handler = *it;533 const CodeLocation loc = handler->location;534 // Modifiy body.535 ast::CompoundStmt * handling_code;536 if (handler->body.as<ast::CompoundStmt>()) {537 handling_code =538 strict_dynamic_cast<ast::CompoundStmt*>( handler->body.get_and_mutate() );539 } else {540 handling_code = new ast::CompoundStmt(loc);541 handling_code->push_back( handler->body );542 }543 handling_code->push_back( new ast::ReturnStmt(loc,544 ast::ConstantExpr::from_bool(loc, true ) ) );545 handler->body = handling_code;546 547 // Create the handler.548 body->push_back( create_single_matcher( except_obj, handler ) );549 *it = nullptr;550 }551 552 body->push_back( new ast::ReturnStmt(loc,553 ast::ConstantExpr::from_bool(loc, false ) ) );554 func_t->stmts = body;555 556 return func_t;557 }558 559 ast::CompoundStmt * TryMutatorCore::create_resume_wrapper(560 const ast::Stmt * wraps,561 const ast::FunctionDecl * resume_handler ) {562 const CodeLocation loc = wraps->location;563 ast::CompoundStmt * body = new ast::CompoundStmt(loc);564 565 // struct __try_resume_node __resume_node566 // __attribute__((cleanup( __cfaehm_try_resume_cleanup )));567 // ** unwinding of the stack here could cause problems **568 // ** however I don't think that can happen currently **569 // __cfaehm_try_resume_setup( &__resume_node, resume_handler );570 571 ast::ObjectDecl * obj = new ast::ObjectDecl(572 loc,573 "__resume_node",574 new ast::StructInstType(575 node_decl576 ),577 nullptr,578 ast::Storage::Classes{},579 ast::Linkage::Cforall,580 nullptr,581 {new ast::Attribute("cleanup", {new ast::NameExpr(loc, "__cfaehm_try_resume_cleanup")})}582 );583 appendDeclStmt( body, obj );584 585 ast::UntypedExpr *setup = new ast::UntypedExpr(loc, new ast::NameExpr(loc,586 "__cfaehm_try_resume_setup" ) );587 setup->args.push_back( new ast::AddressExpr( loc, new ast::VariableExpr(loc, obj ) ) );588 setup->args.push_back( new ast::VariableExpr( loc, resume_handler ) );589 590 body->push_back( new ast::ExprStmt(loc, setup ) );591 592 body->push_back( wraps );593 return body;594 }595 596 ast::FunctionDecl * TryMutatorCore::create_finally_wrapper(597 ast::TryStmt * tryStmt ) {598 // void finally() { `finally->block` }599 const ast::FinallyStmt * finally = tryStmt->finally;600 const ast::CompoundStmt * body = finally->body;601 602 ast::FunctionDecl * func_t = ast::deepCopy(finally_func_t);603 func_t->stmts = body;604 605 // finally->set_block( nullptr );606 // delete finally;607 tryStmt->finally = nullptr;608 609 610 return func_t;611 }612 613 ast::ObjectDecl * TryMutatorCore::create_finally_hook(614 ast::FunctionDecl * finally_wrapper ) {615 // struct __cfaehm_cleanup_hook __finally_hook616 // __attribute__((cleanup( `finally_wrapper` )));617 618 const CodeLocation loc = finally_wrapper->location;619 // Make Cleanup Attribute.620 /*621 std::list< ast::Attribute * > attributes;622 {623 std::list< > attr_params;624 attr_params.push_back( nameOf( finally_wrapper ) );625 attributes.push_back( new Attribute( "cleanup", attr_params ) );626 }627 */628 629 return new ast::ObjectDecl(630 loc,631 "__finally_hook",632 new ast::StructInstType(633 hook_decl634 ),635 nullptr,636 ast::Storage::Classes{},637 ast::Linkage::Cforall,638 nullptr,639 {new ast::Attribute("cleanup", {new ast::VariableExpr{loc, finally_wrapper}})}640 );641 }642 643 ast::Stmt * TryMutatorCore::create_resume_rethrow( const ast::ThrowStmt *throwStmt ) {644 // return false;645 const CodeLocation loc = throwStmt->location;646 ast::Stmt * result = new ast::ReturnStmt(loc,647 ast::ConstantExpr::from_bool( loc, false )648 );649 result->labels = throwStmt->labels;650 // delete throwStmt; done by postvisit651 return result;652 }653 654 // Visiting/Mutating Functions655 void TryMutatorCore::previsit( const ast::StructDecl *structDecl ) {656 if ( !structDecl->body ) {657 // Skip children?658 return;659 } else if ( structDecl->name == "__cfaehm_base_exception_t" ) {660 assert( nullptr == except_decl );661 except_decl = structDecl;662 init_func_types();663 } else if ( structDecl->name == "__cfaehm_try_resume_node" ) {664 assert( nullptr == node_decl );665 node_decl = structDecl;666 } else if ( structDecl->name == "__cfaehm_cleanup_hook" ) {667 assert( nullptr == hook_decl );668 hook_decl = structDecl;669 }670 }671 672 ast::Stmt * TryMutatorCore::postvisit( const ast::TryStmt *tryStmt ) {673 assert( except_decl );674 assert( node_decl );675 assert( hook_decl );676 677 const CodeLocation loc = tryStmt->location;678 ast::TryStmt * mutStmt = mutate(tryStmt);679 // Generate a prefix for the function names?680 681 ast::CompoundStmt * block = new ast::CompoundStmt( loc );682 // ast::CompoundStmt * inner = take_try_block( mutStmt );683 // this is never mutated so let node deletion do its job?684 const ast::CompoundStmt * inner = mutStmt->body;685 686 if ( mutStmt->finally ) {687 // Define the helper function.688 ast::FunctionDecl * finally_block =689 create_finally_wrapper( mutStmt );690 appendDeclStmt( block, finally_block );691 // Create and add the finally cleanup hook.692 appendDeclStmt( block, create_finally_hook( finally_block ) );693 }694 695 CatchList termination_handlers;696 CatchList resumption_handlers;697 698 for (auto & handler: mutStmt->handlers) {699 // xxx - should always be unique? mutate as safe const-cast700 assert(handler->unique());701 if (handler->kind == ast::ExceptionKind::Resume) {702 resumption_handlers.push_back(handler.get_and_mutate());703 }704 else {705 termination_handlers.push_back(handler.get_and_mutate());706 }707 }708 // split( mutStmt->handlers,709 // termination_handlers, resumption_handlers );710 711 if ( resumption_handlers.size() ) {712 // Define the helper function.713 ast::FunctionDecl * resume_handler =714 create_resume_handler( resumption_handlers );715 appendDeclStmt( block, resume_handler );716 // Prepare hooks717 inner = create_resume_wrapper( inner, resume_handler );718 }719 720 if ( termination_handlers.size() ) {721 // Define the three helper functions.722 ast::FunctionDecl * try_wrapper = create_try_wrapper( inner );723 appendDeclStmt( block, try_wrapper );724 ast::FunctionDecl * terminate_catch =725 create_terminate_catch( termination_handlers );726 appendDeclStmt( block, terminate_catch );727 ast::FunctionDecl * terminate_match =728 create_terminate_match( termination_handlers );729 appendDeclStmt( block, terminate_match );730 // Build the call to the try wrapper.731 inner = create_terminate_caller(inner->location,732 try_wrapper, terminate_catch, terminate_match );733 }734 735 // Embed the try block.736 block->push_back( inner );737 738 return block;739 }740 741 ast::Stmt * TryMutatorCore::postvisit( const ast::ThrowStmt *throwStmt ) {742 // Only valid `throwResume;` statements should remain. (2/3 checks)743 assert( ast::ExceptionKind::Resume == throwStmt->kind && ! throwStmt->expr );744 return create_resume_rethrow( throwStmt );745 }746 747 } // namespace748 749 128 void translateThrows( ast::TranslationUnit & transUnit ) { 750 129 ast::Pass<TranslateThrowsCore>::run( transUnit ); 751 }752 753 void translateTries( ast::TranslationUnit & transUnit ) {754 ast::Pass<TryMutatorCore>::run(transUnit);755 130 } 756 131
Note:
See TracChangeset
for help on using the changeset viewer.