source: src/ControlStruct/ExceptTranslate.cc @ c715e5f

ADTast-experimentalpthread-emulationqualifiedEnum
Last change on this file since c715e5f was 5ee153d, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Translated the Translate Throws pass to the new ast.

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