source: src/ControlStruct/ExceptTranslate.cc @ 66ba544

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 66ba544 was 66ba544, checked in by Andrew Beach <ajbeach@…>, 4 years ago

Dead code elimination in the try block translation.

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