source: src/ControlStruct/ExceptTranslate.cc @ 918b90c

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

That should get default operations working for throws. More tests to come.

  • Property mode set to 100644
File size: 22.2 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// ExceptVisitor.cc --
8//
9// Author           : Andrew Beach
10// Created On       : Wed Jun 14 16:49:00 2017
11// Last Modified By : Andrew Beach
12// Last Modified On : Tue May 19 16:46:00 2020
13// Update Count     : 14
14//
15
16#include "ExceptTranslate.h"
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
26#include "SynTree/LinkageSpec.h"      // for Cforall
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
32#include "SynTree/Label.h"            // for Label
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
36#include "SynTree/DeclReplacer.h"     // for DeclReplacer
37#include "SynTree/Visitor.h"          // for acceptAll
38
39namespace ControlStruct {
40
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 ) {
59                block->push_back(new DeclStmt(item));
60        }
61
62        Expression * nameOf( DeclarationWithType * decl ) {
63                return new VariableExpr( decl );
64        }
65
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
184        class TryMutatorCore : public WithGuards {
185                enum Context { NoHandler, TerHandler, ResHandler };
186
187                // Also need to handle goto, break & continue.
188                // They need to be cut off in a ResHandler, until we enter another
189                // loop, switch or the goto stays within the function.
190
191                Context cur_context;
192
193                // The current (innermost) termination handler exception declaration.
194                ObjectDecl * handler_except_decl;
195
196                // The built in types used in translation.
197                StructDecl * except_decl;
198                StructDecl * node_decl;
199                StructDecl * hook_decl;
200
201                // The many helper functions for code/syntree generation.
202                CompoundStmt * take_try_block( TryStmt * tryStmt );
203                FunctionDecl * create_try_wrapper( CompoundStmt * body );
204                FunctionDecl * create_terminate_catch( CatchList &handlers );
205                CompoundStmt * create_single_matcher(
206                        DeclarationWithType * except_obj, CatchStmt * modded_handler );
207                FunctionDecl * create_terminate_match( CatchList &handlers );
208                CompoundStmt * create_terminate_caller( FunctionDecl * try_wrapper,
209                        FunctionDecl * terminate_catch, FunctionDecl * terminate_match );
210                FunctionDecl * create_resume_handler( CatchList &handlers );
211                CompoundStmt * create_resume_wrapper(
212                        Statement * wraps, FunctionDecl * resume_handler );
213                FunctionDecl * create_finally_wrapper( TryStmt * tryStmt );
214                ObjectDecl * create_finally_hook( FunctionDecl * finally_wrapper );
215
216                // Types used in translation, make sure to use clone.
217                // void (*function)();
218                FunctionType try_func_t;
219                // void (*function)(int, exception);
220                FunctionType catch_func_t;
221                // int (*function)(exception);
222                FunctionType match_func_t;
223                // bool (*function)(exception);
224                FunctionType handle_func_t;
225                // void (*function)(__attribute__((unused)) void *);
226                FunctionType finally_func_t;
227
228                StructInstType * create_except_type() {
229                        assert( except_decl );
230                        return new StructInstType( noQualifiers, except_decl );
231                }
232                void init_func_types();
233
234        public:
235                TryMutatorCore() :
236                        cur_context( NoHandler ),
237                        handler_except_decl( nullptr ),
238                        except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr ),
239                        try_func_t( noQualifiers, false ),
240                        catch_func_t( noQualifiers, false ),
241                        match_func_t( noQualifiers, false ),
242                        handle_func_t( noQualifiers, false ),
243                        finally_func_t( noQualifiers, false )
244                {}
245
246                void premutate( CatchStmt *catchStmt );
247                void premutate( StructDecl *structDecl );
248                Statement * postmutate( ThrowStmt *throwStmt );
249                Statement * postmutate( TryStmt *tryStmt );
250        };
251
252        void TryMutatorCore::init_func_types() {
253                assert( except_decl );
254
255                ObjectDecl index_obj(
256                        "__handler_index",
257                        Type::StorageClasses(),
258                        LinkageSpec::Cforall,
259                        /*bitfieldWidth*/ NULL,
260                        new BasicType( noQualifiers, BasicType::SignedInt ),
261                        /*init*/ NULL
262                        );
263                ObjectDecl exception_obj(
264                        "__exception_inst",
265                        Type::StorageClasses(),
266                        LinkageSpec::Cforall,
267                        /*bitfieldWidth*/ NULL,
268                        new PointerType(
269                                noQualifiers,
270                                new StructInstType( noQualifiers, except_decl )
271                                ),
272                        /*init*/ NULL
273                        );
274                ObjectDecl bool_obj(
275                        "__ret_bool",
276                        Type::StorageClasses(),
277                        LinkageSpec::Cforall,
278                        /*bitfieldWidth*/ NULL,
279                        new BasicType( noQualifiers, BasicType::Bool ),
280                        /*init*/ NULL,
281                        std::list<Attribute *>{ new Attribute( "unused" ) }
282                        );
283                ObjectDecl voidptr_obj(
284                        "__hook",
285                        Type::StorageClasses(),
286                        LinkageSpec::Cforall,
287                        NULL,
288                        new PointerType(
289                                noQualifiers,
290                                new VoidType(
291                                        noQualifiers
292                                        ),
293                                std::list<Attribute *>{ new Attribute( "unused" ) }
294                                ),
295                        NULL
296                        );
297
298                ObjectDecl * unused_index_obj = index_obj.clone();
299                unused_index_obj->attributes.push_back( new Attribute( "unused" ) );
300
301                catch_func_t.get_parameters().push_back( index_obj.clone() );
302                catch_func_t.get_parameters().push_back( exception_obj.clone() );
303                match_func_t.get_returnVals().push_back( unused_index_obj );
304                match_func_t.get_parameters().push_back( exception_obj.clone() );
305                handle_func_t.get_returnVals().push_back( bool_obj.clone() );
306                handle_func_t.get_parameters().push_back( exception_obj.clone() );
307                finally_func_t.get_parameters().push_back( voidptr_obj.clone() );
308        }
309
310        // TryStmt Mutation Helpers
311
312        CompoundStmt * TryMutatorCore::take_try_block( TryStmt *tryStmt ) {
313                CompoundStmt * block = tryStmt->get_block();
314                tryStmt->set_block( nullptr );
315                return block;
316        }
317
318        FunctionDecl * TryMutatorCore::create_try_wrapper(
319                        CompoundStmt *body ) {
320
321                return new FunctionDecl( "try", Type::StorageClasses(),
322                        LinkageSpec::Cforall, try_func_t.clone(), body );
323        }
324
325        FunctionDecl * TryMutatorCore::create_terminate_catch(
326                        CatchList &handlers ) {
327                std::list<CaseStmt *> handler_wrappers;
328
329                FunctionType *func_type = catch_func_t.clone();
330                DeclarationWithType * index_obj = func_type->get_parameters().front();
331                DeclarationWithType * except_obj = func_type->get_parameters().back();
332
333                // Index 1..{number of handlers}
334                int index = 0;
335                CatchList::iterator it = handlers.begin();
336                for ( ; it != handlers.end() ; ++it ) {
337                        ++index;
338                        CatchStmt * handler = *it;
339
340                        // case `index`:
341                        // {
342                        //     `handler.decl` = { (virtual `decl.type`)`except` };
343                        //     `handler.body`;
344                        // }
345                        // return;
346                        CompoundStmt * block = new CompoundStmt();
347
348                        // Just copy the exception value. (Post Validation)
349                        ObjectDecl * handler_decl =
350                                static_cast<ObjectDecl *>( handler->get_decl() );
351                        ObjectDecl * local_except = handler_decl->clone();
352                        local_except->set_init(
353                                new ListInit({ new SingleInit(
354                                        new VirtualCastExpr( nameOf( except_obj ),
355                                                local_except->get_type()
356                                                )
357                                        ) })
358                                );
359                        block->push_back( new DeclStmt( local_except ) );
360
361                        // Add the cleanup attribute.
362                        local_except->get_attributes().push_back( new Attribute(
363                                "cleanup",
364                                { new NameExpr( "__cfaehm_cleanup_terminate" ) }
365                                ) );
366
367                        // Update variables in the body to point to this local copy.
368                        {
369                                DeclReplacer::DeclMap mapping;
370                                mapping[ handler_decl ] = local_except;
371                                DeclReplacer::replace( handler->body, mapping );
372                        }
373
374                        block->push_back( handler->body );
375                        handler->body = nullptr;
376
377                        std::list<Statement *> caseBody
378                                        { block, new ReturnStmt( nullptr ) };
379                        handler_wrappers.push_back( new CaseStmt(
380                                new ConstantExpr( Constant::from_int( index ) ),
381                                caseBody
382                                ) );
383                }
384                // TODO: Some sort of meaningful error on default perhaps?
385
386                std::list<Statement*> stmt_handlers;
387                while ( !handler_wrappers.empty() ) {
388                        stmt_handlers.push_back( handler_wrappers.front() );
389                        handler_wrappers.pop_front();
390                }
391
392                SwitchStmt * handler_lookup = new SwitchStmt(
393                        nameOf( index_obj ),
394                        stmt_handlers
395                        );
396                CompoundStmt * body = new CompoundStmt();
397                body->push_back( handler_lookup );
398
399                return new FunctionDecl("catch", Type::StorageClasses(),
400                        LinkageSpec::Cforall, func_type, body);
401        }
402
403        // Create a single check from a moddified handler.
404        // except_obj is referenced, modded_handler will be freed.
405        CompoundStmt * TryMutatorCore::create_single_matcher(
406                        DeclarationWithType * except_obj, CatchStmt * modded_handler ) {
407                // {
408                //     `modded_handler.decl`
409                //     if ( `decl.name = (virtual `decl.type`)`except`
410                //             [&& `modded_handler.cond`] ) {
411                //         `modded_handler.body`
412                //     }
413                // }
414
415                CompoundStmt * block = new CompoundStmt();
416
417                // Local Declaration
418                ObjectDecl * local_except =
419                        dynamic_cast<ObjectDecl *>( modded_handler->get_decl() );
420                assert( local_except );
421                block->push_back( new DeclStmt( local_except ) );
422
423                // Check for type match.
424                Expression * cond = UntypedExpr::createAssign( nameOf( local_except ),
425                        new VirtualCastExpr( nameOf( except_obj ),
426                                local_except->get_type()->clone() ) );
427
428                // Add the check on the conditional if it is provided.
429                if ( modded_handler->get_cond() ) {
430                        cond = new LogicalExpr( cond, modded_handler->get_cond() );
431                }
432                // Construct the match condition.
433                block->push_back( new IfStmt(
434                        cond, modded_handler->get_body(), nullptr ) );
435
436                modded_handler->set_decl( nullptr );
437                modded_handler->set_cond( nullptr );
438                modded_handler->set_body( nullptr );
439                delete modded_handler;
440                return block;
441        }
442
443        FunctionDecl * TryMutatorCore::create_terminate_match(
444                        CatchList &handlers ) {
445                // int match(exception * except) {
446                //     HANDLER WRAPPERS { return `index`; }
447                // }
448
449                CompoundStmt * body = new CompoundStmt();
450
451                FunctionType * func_type = match_func_t.clone();
452                DeclarationWithType * except_obj = func_type->get_parameters().back();
453
454                // Index 1..{number of handlers}
455                int index = 0;
456                CatchList::iterator it;
457                for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
458                        ++index;
459                        CatchStmt * handler = *it;
460
461                        // Body should have been taken by create_terminate_catch.
462                        assert( nullptr == handler->get_body() );
463
464                        // Create new body.
465                        handler->set_body( new ReturnStmt(
466                                new ConstantExpr( Constant::from_int( index ) ) ) );
467
468                        // Create the handler.
469                        body->push_back( create_single_matcher( except_obj, handler ) );
470                        *it = nullptr;
471                }
472
473                body->push_back( new ReturnStmt(
474                        new ConstantExpr( Constant::from_int( 0 ) ) ) );
475
476                return new FunctionDecl("match", Type::StorageClasses(),
477                        LinkageSpec::Cforall, func_type, body);
478        }
479
480        CompoundStmt * TryMutatorCore::create_terminate_caller(
481                        FunctionDecl * try_wrapper,
482                        FunctionDecl * terminate_catch,
483                        FunctionDecl * terminate_match ) {
484                // { __cfaehm_try_terminate(`try`, `catch`, `match`); }
485
486                UntypedExpr * caller = new UntypedExpr( new NameExpr(
487                        "__cfaehm_try_terminate" ) );
488                std::list<Expression *>& args = caller->get_args();
489                args.push_back( nameOf( try_wrapper ) );
490                args.push_back( nameOf( terminate_catch ) );
491                args.push_back( nameOf( terminate_match ) );
492
493                CompoundStmt * callStmt = new CompoundStmt();
494                callStmt->push_back( new ExprStmt( caller ) );
495                return callStmt;
496        }
497
498        FunctionDecl * TryMutatorCore::create_resume_handler(
499                        CatchList &handlers ) {
500                // bool handle(exception * except) {
501                //     HANDLER WRAPPERS { `hander->body`; return true; }
502                // }
503                CompoundStmt * body = new CompoundStmt();
504
505                FunctionType * func_type = handle_func_t.clone();
506                DeclarationWithType * except_obj = func_type->get_parameters().back();
507
508                CatchList::iterator it;
509                for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
510                        CatchStmt * handler = *it;
511
512                        // Modifiy body.
513                        CompoundStmt * handling_code =
514                                dynamic_cast<CompoundStmt*>( handler->get_body() );
515                        if ( ! handling_code ) {
516                                handling_code = new CompoundStmt();
517                                handling_code->push_back( handler->get_body() );
518                        }
519                        handling_code->push_back( new ReturnStmt(
520                                new ConstantExpr( Constant::from_bool( true ) ) ) );
521                        handler->set_body( handling_code );
522
523                        // Create the handler.
524                        body->push_back( create_single_matcher( except_obj, handler ) );
525                        *it = nullptr;
526                }
527
528                body->push_back( new ReturnStmt(
529                        new ConstantExpr( Constant::from_bool( false ) ) ) );
530
531                return new FunctionDecl("handle", Type::StorageClasses(),
532                        LinkageSpec::Cforall, func_type, body);
533        }
534
535        CompoundStmt * TryMutatorCore::create_resume_wrapper(
536                        Statement * wraps,
537                        FunctionDecl * resume_handler ) {
538                CompoundStmt * body = new CompoundStmt();
539
540                // struct __try_resume_node __resume_node
541                //      __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
542                // ** unwinding of the stack here could cause problems **
543                // ** however I don't think that can happen currently **
544                // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
545
546                std::list< Attribute * > attributes;
547                {
548                        std::list< Expression * > attr_params;
549                        attr_params.push_back( new NameExpr(
550                                "__cfaehm_try_resume_cleanup" ) );
551                        attributes.push_back( new Attribute( "cleanup", attr_params ) );
552                }
553
554                ObjectDecl * obj = new ObjectDecl(
555                        "__resume_node",
556                        Type::StorageClasses(),
557                        LinkageSpec::Cforall,
558                        nullptr,
559                        new StructInstType(
560                                Type::Qualifiers(),
561                                node_decl
562                                ),
563                        nullptr,
564                        attributes
565                        );
566                appendDeclStmt( body, obj );
567
568                UntypedExpr *setup = new UntypedExpr( new NameExpr(
569                        "__cfaehm_try_resume_setup" ) );
570                setup->get_args().push_back( new AddressExpr( nameOf( obj ) ) );
571                setup->get_args().push_back( nameOf( resume_handler ) );
572
573                body->push_back( new ExprStmt( setup ) );
574
575                body->push_back( wraps );
576                return body;
577        }
578
579        FunctionDecl * TryMutatorCore::create_finally_wrapper(
580                        TryStmt * tryStmt ) {
581                // void finally() { <finally code> }
582                FinallyStmt * finally = tryStmt->get_finally();
583                CompoundStmt * body = finally->get_block();
584                finally->set_block( nullptr );
585                delete finally;
586                tryStmt->set_finally( nullptr );
587
588                return new FunctionDecl("finally", Type::StorageClasses(),
589                        LinkageSpec::Cforall, finally_func_t.clone(), body);
590        }
591
592        ObjectDecl * TryMutatorCore::create_finally_hook(
593                        FunctionDecl * finally_wrapper ) {
594                // struct __cfaehm_cleanup_hook __finally_hook
595                //      __attribute__((cleanup( `finally_wrapper` )));
596
597                // Make Cleanup Attribute.
598                std::list< Attribute * > attributes;
599                {
600                        std::list< Expression * > attr_params;
601                        attr_params.push_back( nameOf( finally_wrapper ) );
602                        attributes.push_back( new Attribute( "cleanup", attr_params ) );
603                }
604
605                return new ObjectDecl(
606                        "__finally_hook",
607                        Type::StorageClasses(),
608                        LinkageSpec::Cforall,
609                        nullptr,
610                        new StructInstType(
611                                noQualifiers,
612                                hook_decl
613                                ),
614                        nullptr,
615                        attributes
616                        );
617        }
618
619        // Visiting/Mutating Functions
620        void TryMutatorCore::premutate( CatchStmt *catchStmt ) {
621                // Validate the Statement's form.
622                ObjectDecl * decl = dynamic_cast<ObjectDecl *>( catchStmt->get_decl() );
623                if ( decl && true /* check decl->get_type() */ ) {
624                        // Pass.
625                } else if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
626                        SemanticError(catchStmt->location, "catch must have exception type");
627                } else {
628                        SemanticError(catchStmt->location, "catchResume must have exception type");
629                }
630
631                // Track the handler context.
632                GuardValue( cur_context );
633                if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
634                        cur_context = TerHandler;
635
636                        GuardValue( handler_except_decl );
637                        handler_except_decl = decl;
638                } else {
639                        cur_context = ResHandler;
640                }
641        }
642
643        void TryMutatorCore::premutate( StructDecl *structDecl ) {
644                if ( !structDecl->has_body() ) {
645                        // Skip children?
646                        return;
647                } else if ( structDecl->get_name() == "__cfaehm_base_exception_t" ) {
648                        assert( nullptr == except_decl );
649                        except_decl = structDecl;
650                        init_func_types();
651                } else if ( structDecl->get_name() == "__cfaehm_try_resume_node" ) {
652                        assert( nullptr == node_decl );
653                        node_decl = structDecl;
654                } else if ( structDecl->get_name() == "__cfaehm_cleanup_hook" ) {
655                        assert( nullptr == hook_decl );
656                        hook_decl = structDecl;
657                }
658        }
659
660        Statement * TryMutatorCore::postmutate( ThrowStmt * ) {
661                // All throws should be removed by this point.
662                assert( false );
663        }
664
665        Statement * TryMutatorCore::postmutate( TryStmt *tryStmt ) {
666                assert( except_decl );
667                assert( node_decl );
668                assert( hook_decl );
669
670                // Generate a prefix for the function names?
671
672                CompoundStmt * block = new CompoundStmt();
673                CompoundStmt * inner = take_try_block( tryStmt );
674
675                if ( tryStmt->get_finally() ) {
676                        // Define the helper function.
677                        FunctionDecl * finally_block =
678                                create_finally_wrapper( tryStmt );
679                        appendDeclStmt( block, finally_block );
680                        // Create and add the finally cleanup hook.
681                        appendDeclStmt( block, create_finally_hook( finally_block ) );
682                }
683
684                CatchList termination_handlers;
685                CatchList resumption_handlers;
686                split( tryStmt->get_catchers(),
687                           termination_handlers, resumption_handlers );
688
689                if ( resumption_handlers.size() ) {
690                        // Define the helper function.
691                        FunctionDecl * resume_handler =
692                                create_resume_handler( resumption_handlers );
693                        appendDeclStmt( block, resume_handler );
694                        // Prepare hooks
695                        inner = create_resume_wrapper( inner, resume_handler );
696                }
697
698                if ( termination_handlers.size() ) {
699                        // Define the three helper functions.
700                        FunctionDecl * try_wrapper = create_try_wrapper( inner );
701                        appendDeclStmt( block, try_wrapper );
702                        FunctionDecl * terminate_catch =
703                                create_terminate_catch( termination_handlers );
704                        appendDeclStmt( block, terminate_catch );
705                        FunctionDecl * terminate_match =
706                                create_terminate_match( termination_handlers );
707                        appendDeclStmt( block, terminate_match );
708                        // Build the call to the try wrapper.
709                        inner = create_terminate_caller(
710                                try_wrapper, terminate_catch, terminate_match );
711                }
712
713                // Embed the try block.
714                block->push_back( inner );
715
716                return block;
717        }
718
719        void translateThrows( std::list< Declaration *> & translationUnit ) {
720                PassVisitor<ThrowMutatorCore> translator;
721                mutateAll( translationUnit, translator );
722        }
723
724        void translateTries( std::list< Declaration *> & translationUnit ) {
725                PassVisitor<TryMutatorCore> translator;
726                mutateAll( translationUnit, translator );
727        }
728}
Note: See TracBrowser for help on using the repository browser.