// // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // ExceptVisitor.cc -- // // Author : Andrew Beach // Created On : Wed Jun 14 16:49:00 2017 // Last Modified By : Andrew Beach // Last Modified On : Thr Jun 22 15:57:00 2017 // Update Count : 0 // #include "ExceptTranslate.h" #include "Common/PassVisitor.h" namespace ControlFlow { // This (large) section could probably be moved out of the class // and be static helpers instead. // Type(Qualifiers &, false, std::list &) // void (*function)() static FunctionType void_func_t(Type::Qualifiers(), false); // void (*function)(int, exception); static FunctionType catch_func_t(Type::Qualifiers(), false); // int (*function)(exception); static FunctionType match_func_t(Type::Qualifiers(), false); // bool (*function)(exception); static FunctionType handle_func_t(Type::Qualifiers(), false); static void init_func_types() { static init_complete = false; if (init_complete) { return; } ObjectDecl index_obj( "index_t", Type::StorageClasses(), LinkageSpec::Cforall, /*bitfieldWidth*/ NULL, new BasicType(emptyQualifiers, BasicType::UnsignedInt), /*init*/ NULL ); ObjectDecl exception_obj( "exception_t", Type::StorageClasses(), LinkageSpec::Cforall, /*bitfieldWidth*/ NULL, new BasicType(emptyQualifiers, BasicType::UnsignedInt), /*init*/ NULL ); ObjectDecl bool_obj( "bool_t", Type::StorageClasses(), LinkageSpec::Cforall, /*bitfieldWidth*/ NULL, new BasicType(emptyQualifiers, BasicType::Bool), /*init*/ NULL ); catch_func_t.get_parameters().push_back(index_obj.clone()); catch_func_t.get_parameters().push_back(exception_obj.clone()); match_func_t.get_returnVals().push_back(index_obj.clone()); match_func_t.get_parameters().push_back(exception_obj.clone()); handle_func_t.get_returnVals().push_back(bool_obj.clone()); handle_func_t.get_parameters().push_back(exception_obj.clone()); init_complete = true; } // Buricratic Helpers (Not having to do with the paritular operation.) typedef std::list CatchList; void split( CatchList& allHandlers, CatchList& terHandlers, CatchList& resHandlers ) { while ( !allHandlers.empty() ) { Statement * stmt = allHandlers.front(); allHandlers.pop_front(); if (CaseStmt::Terminate == stmt->get_kind()) { terHandlers.push_back(stmt); } else { resHandlers.push_back(stmt); } } } template void free_all( std::list &list ) { std::list::iterator it; for ( it = list.begin() ; it != list.end() ; ++it ) { delete *it; } list.clear(); } void appendDeclStmt( CompoundStmt * block, Declaration * item ) { block->push_back(new DeclStmt(no_labels, item)); } Expression * nameOf( FunctionDecl * function ) { return new VariableExpr( function ); } // ThrowStmt Mutation Helpers Statement * create_terminate_throw( ThrowStmt *throwStmt ) { // __throw_terminate( EXPR ); ApplicationExpr * call = new ApplicationExpr( /* ... */ ); call->get_args.push_back( throwStmt->get_expr() ); Statement * result = new ExprStmt( throwStmt->get_labels(), call ); throwStmt->set_expr( nullptr ); delete throwStmt; return result; } Statement * create_terminate_rethrow( ThrowStmt *throwStmt ) { // __rethrow_terminate(); Statement * result = new ExprStmt( throwStmt->get_labels(), new ApplicationExpr( /* ... */ ); ); delete throwStmt; return result; } Statement * create_resume_throw( ThrowStmt *throwStmt ) { // __throw_resume( EXPR ); ApplicationExpr * call = new ApplicationExpr( /* ... */ ); call->get_args.push_back( throwStmt->get_expr() ); Statement * result = new ExprStmt( throwStmt->get_labels(), call ); throwStmt->set_expr( nullptr ); delete throwStmt; return result; } Statement * create_resume_rethrow( ThrowStmt *throwStmt ) { // return false; Statement * result = new ReturnStmt( throwStmt->get_labels(), new ConstantExpr( Constant( new BasicType( Type::Qualifiers(), BasicType::Bool ), "0") ) ); delete throwStmt; return result; } // TryStmt Mutation Helpers CompoundStmt * take_try_block( TryStmt *tryStmt ) { CompoundStmt * block = tryStmt->get_block(); tryStmt->set_block( nullptr ); return block; } FunctionDecl * create_try_wrapper( TryStmt *tryStmt ) { CompoundStmt * body = base_try->get_block(); base_try->set_block(nullptr); return new FunctionDecl("try", Type::StorageClasses(), LinkageSpec::Cforall, void_func_t, body); } FunctionDecl * create_terminate_catch( CatchList &handlers ) { std::list handler_wrappers; // Index 1..{number of handlers} int index = 0; CatchList::iterator it = handlers.begin(); for ( ; it != handlers.end() ; ++it ) { ++index; CatchStmt * handler = *it; std::list core; if ( /*the exception is named*/ ) { ObjectDecl * local_except = /* Dynamic case, same */; core->push_back( new DeclStmt( noLabel, local_except ) ); } // Append the provided statement to the handler. core->push_back( cur_handler->get_body() ); // Append return onto the inner block? case stmt list? CaseStmt * wrapper = new CaseStmt( noLabels, new ConstantExpr( Constant::from_int( index ) ), core ); handler_wrappers.push_back(wrapper); } // TODO: Some sort of meaningful error on default perhaps? SwitchStmt * handler_lookup = new SwitchStmt( noLabels, /*parameter 0: index*/, handler_wrappers, false ); CompoundStmt * body = new CompoundStmt( noLabels ); body->push_back( handler_lookup ); return new FunctionDecl("catch", Type::StorageClasses(), LinkageSpec::Cforall, catch_func_t, body); } // Create a single check from a moddified handler. CompoundStmt *create_single_matcher( CatchStmt * modded_handler ) { CompoundStmt * block = new CompoundStmt( noLables ); appendDeclStmt( block, modded_handler->get_decl() ); // TODO: This is not the actual check. LogicalExpr * cond = new ConstantExpr( Constant::from_bool( false ) ); if ( modded_handler->get_cond() ) { cond = new LogicalExpr( cond, modded_handler->get_cond() )q } block->push_back( new IfStmt( noLabels, cond, modded_handler->get_body() ); modded_handler->set_decl( nullptr ); modded_handler->set_cond( nullptr ); modded_handler->set_body( nullptr ); delete modded_handler; return block; } FunctionDecl * create_terminate_match( CatchList &handlers ) { CompoundStmt * body = new CompoundStmt( noLabels ); // Index 1..{number of handlers} int index = 0; CatchList::iterator it; for ( it = handlers.begin() ; it != handlers.end() ; ++it ) { ++index; CatchStmt * handler = *it; // body should have been taken by create_terminate_catch. // assert( nullptr == handler->get_body() ); handler->set_body( new ReturnStmt( noLabels, new ConstantExpr( Constant::from_int( index ) ) ) ); body->push_back( create_single_matcher( handler ) ); } return new FunctionDecl("match", Type::StorageClasses(), LinkageSpec::Cforall, match_func_t, body); } Statement * create_terminate_caller( FunctionDecl * try_wrapper, FunctionDecl * terminate_catch, FunctionDecl * terminate_match) { ApplicationExpr * caller = new ApplicationExpr( /* ... */ ); std::list& args = caller.get_args(); args.push_back( nameOf( try_wrapper ) ); args.push_back( nameOf( terminate_catch ) ); args.push_back( nameOf( terminate_match ) ); return new ExprStmt( noLabels, caller ); } FunctionDecl * create_resume_handler( CatchList &handlers ) { CompoundStmt * body = new CompountStmt( noLabels ); CatchList::iterator it; for ( it = handlers.begin() ; it != handlers.end() ; ++it ) { CatchStmt * handler = *it; // Modifiy body. CompoundStmt * handling_code = dynamic_cast( handler->get_body() ); if ( ! handling_code ) { handling_code = new CompoundStmt( noLabels ); handling_code->push_back( handler->get_body() ); } handling_code->push_back( new ReturnStmt( noLabel, new ConstantExpr( Constant::from_bool( false ) ) ) ); handler->set_body( handling_code ); // Create the handler. body->push_back( create_single_matcher( handler ) ); } return new FunctionDecl("handle", Type::StorageClasses(), LinkageSpec::Cforall, handle_func_t, body); } Statement * create_resume_wrapper( Statement * wraps, FunctionDecl * resume_handler ) { CompoundStmt * body = new CompoundStmt( noLabels ); // struct node = {current top resume handler, call to resume_handler}; // __attribute__((cleanup( ... ))); // set top resume handler to node. // The wrapped statement. ListInit * node_init; { std::list field_inits; field_inits.push_back( new SingleInit( /* ... */ ) ); field_inits.push_back( new SingleInit( nameOf( resume_handler ) ) ); node_init = new ListInit( field_inits ); } std::list< Attribute * > attributes; { std::list< Expression * > attr_params; attr_params.push_back( nameOf( /* ... deconstructor ... */ ) ); attrributes.push_back( new Attribute( "cleanup", attr_params ) ); } appendDeclStmt( body, /**/ ObjectDecl( "resume_node", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, /* Type* = resume_node */, node_init, attributes ) ); body->push_back( wraps ); return body; } FunctionDecl * create_finally_wrapper( TryStmt * tryStmt ) { CompoundStmt * body = tryStmt->get_finally(); tryStmt->set_finally( nullptr ); return new FunctionDecl("finally", Type::StorageClasses(), LinkageSpec::Cforall, void_func_t, body); } ObjectDecl * create_finally_hook( FunctionDecl * finally_wrapper ) { // struct _cleanup_hook NAME __attribute__((cleanup( ... ))); // Make Cleanup Attribute. std::list< Attribute * > attributes; { std::list< Expression * > attr_params; attr_params.push_back( nameOf( finally_wrapper ) ); attrributes.push_back( new Attribute( "cleanup", attr_params ) ); } return ObjectDecl( /* ... */ const std::string &name "finally_hook", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, /* ... Type * ... */, nullptr, attributes ); } class ExceptionMutatorCore : public WithScoping { enum Context { NoHandler, TerHandler, ResHandler }; // Also need to handle goto, break & continue. // They need to be cut off in a ResHandler, until we enter another // loop, switch or the goto stays within the function. Context curContext; // We might not need this, but a unique base for each try block's // generated functions might be nice. //std::string curFunctionName; //unsigned int try_count = 0; public: ExceptionMutatorCore() : curContext(NoHandler) {} void premutate( CatchStmt *tryStmt ); Statement * postmutate( ThrowStmt *throwStmt ); Statement * postmutate( TryStmt *tryStmt ); }; Statement * ExceptionMutatorCore::postmutate( ThrowStmt *throwStmt ) { // Ignoring throwStmt->get_target() for now. if ( ThrowStmt::Terminate == throwStmt->get_kind() ) { if ( throwStmt->get_expr() ) { return create_terminate_throw( throwStmt ); } else if ( TerHandler == curContext ) { return create_terminate_rethrow( throwStmt ); } else { assertf(false, "Invalid throw in %s at %i\n", throwStmt->location.filename, throwStmt->location.linenumber); return nullptr; } } else { if ( throwStmt->get_expr() ) { return create_resume_throw( throwStmt ); } else if ( ResHandler == curContext ) { return create_resume_rethrow( throwStmt ); } else { assertf(false, "Invalid throwResume in %s at %i\n", throwStmt->location.filename, throwStmt->location.linenumber); return nullptr; } } } Statement * ExceptionMutatorCore::postmutate( TryStmt *tryStmt ) { // Generate a prefix for the function names? CompoundStmt * block = new CompoundStmt(); Statement * inner = take_try_block( tryStmt ); if ( tryStmt->get_finally() ) { // Define the helper function. FunctionDecl * finally_block = create_finally_wrapper( tryStmt ); appendDeclStmt( block, finally_block ); // Create and add the finally cleanup hook. appendDeclStmt( block, create_finally_hook( finally_block ) ); } StatementList termination_handlers; StatementList resumption_handlers; split( tryStmt->get_handlers(), termination_handlers, resumption_handlers ); if ( resumeption_handlers.size() ) { // Define the helper function. FunctionDecl * resume_handler = create_resume_handler( resumption_handlers ); appendDeclStmt( block, resume_handler ); // Prepare hooks inner = create_resume_wrapper( inner, resume_handler ); } if ( termination_handlers.size() ) { // Define the three helper functions. FunctionDecl * try_wrapper = create_try_wrapper( inner ); appendDeclStmt( block, try_wrapper ); FunctionDecl * terminate_catch = create_terminate_catch( termination_handlers ); appendDeclStmt( block, terminate_catch ); FunctionDecl * terminate_match = create_terminate_match( termination_handlers ); appendDeclStmt( block, terminate_match ); // Build the call to the try wrapper. inner = create_terminate_caller( try_wrapper, terminate_catch, terminate_match ); } // Embed the try block. block->push_back( inner ); free_all( termination_handlers ); free_all( resumption_handlers ); return block; } void ExceptionMutatorCore::premutate( CatchStmt *catchStmt ) { GuardValue( curContext ); if ( CatchStmt::Termination == catchStmt->get_kind() ) { curContext = TerHandler; } else { curContext = ResHandler; } } void translateEHM( std::list< Declaration *> & translationUnit ) { PassVisitor translator; for ( Declaration * decl : translationUnit ) { decl->mutate( translator ); } } }