source: src/ControlStruct/ExceptTranslate.cc @ 288eede

aaron-thesisarm-ehcleanup-dtorsdeferred_resndemanglerjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerresolv-newwith_gc
Last change on this file since 288eede was 288eede, checked in by Andrew Beach <ajbeach@…>, 4 years ago

ExceptTranslate? is now compiling.

  • Property mode set to 100644
File size: 16.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 : Thr Jun 29 15:18:00 2017
13// Update Count     : 1
14//
15
16#include "ExceptTranslate.h"
17#include "Common/PassVisitor.h"
18#include "SynTree/Statement.h"
19#include "SynTree/Declaration.h"
20#include "SynTree/Expression.h"
21#include "SynTree/Type.h"
22#include "SynTree/Attribute.h"
23
24namespace ControlFlow {
25
26        // This (large) section could probably be moved out of the class
27        // and be static helpers instead.
28
29        // Type(Qualifiers &, false, std::list<Attribute *> &)
30
31        // void (*function)()
32        static FunctionType void_func_t(Type::Qualifiers(), false);
33        // void (*function)(int, exception);
34        static FunctionType catch_func_t(Type::Qualifiers(), false);
35        // int (*function)(exception);
36        static FunctionType match_func_t(Type::Qualifiers(), false);
37        // bool (*function)(exception);
38        static FunctionType handle_func_t(Type::Qualifiers(), false);
39
40        static void init_func_types() {
41                static bool init_complete = false;
42                if (init_complete) {
43                        return;
44                }
45                ObjectDecl index_obj(
46                        "__handler_index",
47                        Type::StorageClasses(),
48                        LinkageSpec::Cforall,
49                        /*bitfieldWidth*/ NULL,
50                        new BasicType(emptyQualifiers, BasicType::UnsignedInt),
51                        /*init*/ NULL
52                );
53                ObjectDecl exception_obj(
54                        "__exception_inst",
55                        Type::StorageClasses(),
56                        LinkageSpec::Cforall,
57                        /*bitfieldWidth*/ NULL,
58                        new BasicType(emptyQualifiers, BasicType::UnsignedInt),
59                        /*init*/ NULL
60                );
61                ObjectDecl bool_obj(
62                        "__ret_bool",
63                        Type::StorageClasses(),
64                        LinkageSpec::Cforall,
65                        /*bitfieldWidth*/ NULL,
66                        new BasicType(emptyQualifiers, BasicType::Bool),
67                        /*init*/ NULL
68                );
69
70                catch_func_t.get_parameters().push_back(index_obj.clone());
71                catch_func_t.get_parameters().push_back(exception_obj.clone());
72                match_func_t.get_returnVals().push_back(index_obj.clone());
73                match_func_t.get_parameters().push_back(exception_obj.clone());
74                handle_func_t.get_returnVals().push_back(bool_obj.clone());
75                handle_func_t.get_parameters().push_back(exception_obj.clone());
76
77                init_complete = true;
78        }
79
80        // Buricratic Helpers (Not having to do with the paritular operation.)
81
82        typedef std::list<CatchStmt*> CatchList;
83
84        void split( CatchList& allHandlers, CatchList& terHandlers,
85                    CatchList& resHandlers ) {
86                while ( !allHandlers.empty() ) {
87                        CatchStmt * stmt = allHandlers.front();
88                        allHandlers.pop_front();
89                        if (CatchStmt::Terminate == stmt->get_kind()) {
90                                terHandlers.push_back(stmt);
91                        } else {
92                                resHandlers.push_back(stmt);
93                        }
94                }
95        }
96
97        template<typename T>
98        void free_all( std::list<T *> &list ) {
99                typename std::list<T *>::iterator it;
100                for ( it = list.begin() ; it != list.end() ; ++it ) {
101                        delete *it;
102                }
103                list.clear();
104        }
105
106        void appendDeclStmt( CompoundStmt * block, Declaration * item ) {
107                block->push_back(new DeclStmt(noLabels, item));
108        }
109
110        Expression * nameOf( DeclarationWithType * decl ) {
111                return new VariableExpr( decl );
112        }
113
114        // ThrowStmt Mutation Helpers
115
116        Statement * create_terminate_throw( ThrowStmt *throwStmt ) {
117                // __throw_terminate( EXPR );
118                UntypedExpr * call = new UntypedExpr( new NameExpr(
119                        "__cfaehm__throw_termination" ) );
120                call->get_args().push_back( throwStmt->get_expr() );
121                Statement * result = new ExprStmt( throwStmt->get_labels(), call );
122                throwStmt->set_expr( nullptr );
123                delete throwStmt;
124                return result;
125        }
126        Statement * create_terminate_rethrow( ThrowStmt *throwStmt ) {
127                // __rethrow_terminate();
128                assert( nullptr == throwStmt->get_expr() );
129                Statement * result = new ExprStmt(
130                        throwStmt->get_labels(),
131                        new UntypedExpr( new NameExpr( "__cfaehm__rethrow_termination" ) )
132                        );
133                delete throwStmt;
134                return result;
135        }
136        Statement * create_resume_throw( ThrowStmt *throwStmt ) {
137                // __throw_resume( EXPR );
138                UntypedExpr * call = new UntypedExpr( new NameExpr(
139                        "__cfaehm__throw_resumption" ) );
140                call->get_args().push_back( throwStmt->get_expr() );
141                Statement * result = new ExprStmt( throwStmt->get_labels(), call );
142                throwStmt->set_expr( nullptr );
143                delete throwStmt;
144                return result;
145        }
146        Statement * create_resume_rethrow( ThrowStmt *throwStmt ) {
147                // return false;
148                Statement * result = new ReturnStmt(
149                        throwStmt->get_labels(),
150                        new ConstantExpr( Constant::from_bool( false ) )
151                        );
152                delete throwStmt;
153                return result;
154        }
155
156        // TryStmt Mutation Helpers
157
158        CompoundStmt * take_try_block( TryStmt *tryStmt ) {
159                CompoundStmt * block = tryStmt->get_block();
160                tryStmt->set_block( nullptr );
161                return block;
162        }
163        FunctionDecl * create_try_wrapper( CompoundStmt *body ) {
164
165                return new FunctionDecl( "try", Type::StorageClasses(),
166                        LinkageSpec::Cforall, void_func_t.clone(), body );
167        }
168
169        FunctionDecl * create_terminate_catch( CatchList &handlers ) {
170                std::list<CaseStmt *> handler_wrappers;
171
172                FunctionType *func_type = catch_func_t.clone();
173                DeclarationWithType * index_obj = func_type->get_parameters().front();
174        //      DeclarationWithType * except_obj = func_type->get_parameters().back();
175
176                // Index 1..{number of handlers}
177                int index = 0;
178                CatchList::iterator it = handlers.begin();
179                for ( ; it != handlers.end() ; ++it ) {
180                        ++index;
181                        CatchStmt * handler = *it;
182
183                        // INTEGERconstant Version
184                        // case `index`:
185                        // {
186                        //     `handler.body`
187                        // }
188                        // return;
189                        std::list<Statement *> caseBody;
190                        caseBody.push_back( handler->get_body() );
191                        handler->set_body( nullptr );
192                        caseBody.push_back( new ReturnStmt( noLabels, nullptr ) );
193
194                        handler_wrappers.push_back( new CaseStmt(
195                                noLabels,
196                                new ConstantExpr( Constant::from_int( index ) ),
197                                caseBody
198                                ) );
199                }
200                // TODO: Some sort of meaningful error on default perhaps?
201
202                std::list<Statement*> stmt_handlers;
203                while ( !handler_wrappers.empty() ) {
204                        stmt_handlers.push_back( handler_wrappers.front() );
205                        handler_wrappers.pop_front();
206                }
207
208                SwitchStmt * handler_lookup = new SwitchStmt(
209                        noLabels,
210                        nameOf( index_obj ),
211                        stmt_handlers
212                        );
213                CompoundStmt * body = new CompoundStmt( noLabels );
214                body->push_back( handler_lookup );
215
216                return new FunctionDecl("catch", Type::StorageClasses(),
217                        LinkageSpec::Cforall, func_type, body);
218        }
219
220        // Create a single check from a moddified handler.
221        // except_obj is referenced, modded_handler will be freed.
222        CompoundStmt *create_single_matcher(
223                        DeclarationWithType * except_obj, CatchStmt * modded_handler ) {
224                CompoundStmt * block = new CompoundStmt( noLabels );
225
226                // INTEGERconstant Version
227                assert( nullptr == modded_handler->get_decl() );
228                ConstantExpr * number =
229                        dynamic_cast<ConstantExpr*>( modded_handler->get_cond() );
230                assert( number );
231                modded_handler->set_cond( nullptr );
232
233                Expression * cond;
234                {
235                        std::list<Expression *> args;
236                        args.push_back( number );
237                        args.push_back( nameOf( except_obj ) );
238                        cond = new UntypedExpr( new NameExpr( "?==?" /*???*/), args );
239                }
240
241                if ( modded_handler->get_cond() ) {
242                        cond = new LogicalExpr( cond, modded_handler->get_cond() );
243                }
244                block->push_back( new IfStmt( noLabels,
245                        cond, modded_handler->get_body(), nullptr ) );
246
247                modded_handler->set_decl( nullptr );
248                modded_handler->set_cond( nullptr );
249                modded_handler->set_body( nullptr );
250                delete modded_handler;
251                return block;
252        }
253
254        FunctionDecl * create_terminate_match( CatchList &handlers ) {
255                CompoundStmt * body = new CompoundStmt( noLabels );
256
257                FunctionType * func_type = match_func_t.clone();
258                DeclarationWithType * except_obj = func_type->get_parameters().back();
259
260                // Index 1..{number of handlers}
261                int index = 0;
262                CatchList::iterator it;
263                for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
264                        ++index;
265                        CatchStmt * handler = *it;
266
267                        // Body should have been taken by create_terminate_catch.
268                        assert( nullptr == handler->get_body() );
269
270                        // Create new body.
271                        handler->set_body( new ReturnStmt( noLabels,
272                                new ConstantExpr( Constant::from_int( index ) ) ) );
273
274                        // Create the handler.
275                        body->push_back( create_single_matcher( except_obj, handler ) );
276                        *it = nullptr;
277                }
278
279                return new FunctionDecl("match", Type::StorageClasses(),
280                        LinkageSpec::Cforall, func_type, body);
281        }
282
283        CompoundStmt * create_terminate_caller(
284                        FunctionDecl * try_wrapper,
285                        FunctionDecl * terminate_catch,
286                        FunctionDecl * terminate_match) {
287
288                UntypedExpr * caller = new UntypedExpr( new NameExpr(
289                        "__cfaehm__try_terminate" ) );
290                std::list<Expression *>& args = caller->get_args();
291                args.push_back( nameOf( try_wrapper ) );
292                args.push_back( nameOf( terminate_catch ) );
293                args.push_back( nameOf( terminate_match ) );
294
295                CompoundStmt * callStmt = new CompoundStmt( noLabels );
296                callStmt->push_back( new ExprStmt( noLabels, caller ) );
297                return callStmt;
298        }
299
300        FunctionDecl * create_resume_handler( CatchList &handlers ) {
301                CompoundStmt * body = new CompoundStmt( noLabels );
302
303                FunctionType * func_type = match_func_t.clone();
304                DeclarationWithType * except_obj = func_type->get_parameters().back();
305
306                CatchList::iterator it;
307                for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
308                        CatchStmt * handler = *it;
309
310                        // Modifiy body.
311                        CompoundStmt * handling_code =
312                                dynamic_cast<CompoundStmt*>( handler->get_body() );
313                        if ( ! handling_code ) {
314                                handling_code = new CompoundStmt( noLabels );
315                                handling_code->push_back( handler->get_body() );
316                        }
317                        handling_code->push_back( new ReturnStmt( noLabels,
318                                new ConstantExpr( Constant::from_bool( false ) ) ) );
319                        handler->set_body( handling_code );
320
321                        // Create the handler.
322                        body->push_back( create_single_matcher( except_obj, handler ) );
323                        *it = nullptr;
324                }
325
326                return new FunctionDecl("handle", Type::StorageClasses(),
327                        LinkageSpec::Cforall, func_type, body);
328        }
329
330        CompoundStmt * create_resume_wrapper(
331                        StructDecl * node_decl,
332                        Statement * wraps,
333                        FunctionDecl * resume_handler ) {
334                CompoundStmt * body = new CompoundStmt( noLabels );
335
336                // struct __try_resume_node __resume_node
337                //      __attribute__((cleanup( __cfaehm__try_resume_cleanup )));
338                // ** unwinding of the stack here could cause problems **
339                // ** however I don't think that can happen currently **
340                // __cfaehm__try_resume_setup( &__resume_node, resume_handler );
341
342                std::list< Attribute * > attributes;
343                {
344                        std::list< Expression * > attr_params;
345                        attr_params.push_back( new NameExpr(
346                                "__cfaehm__try_resume_cleanup" ) );
347                        attributes.push_back( new Attribute( "cleanup", attr_params ) );
348                }
349
350                ObjectDecl * obj = new ObjectDecl(
351                        "__resume_node",
352                        Type::StorageClasses(),
353                        LinkageSpec::Cforall,
354                        nullptr,
355                        new StructInstType(
356                                Type::Qualifiers(),
357                                node_decl
358                                ),
359                        nullptr,
360                        attributes
361                        );
362                appendDeclStmt( body, obj );
363
364                UntypedExpr *setup = new UntypedExpr( new NameExpr(
365                        "__cfaehm__try_resume_setup" ) );
366                setup->get_args().push_back( nameOf( obj ) );
367                setup->get_args().push_back( nameOf( resume_handler ) );
368
369                body->push_back( new ExprStmt( noLabels, setup ) );
370
371                body->push_back( wraps );
372                return body;
373        }
374
375        FunctionDecl * create_finally_wrapper( TryStmt * tryStmt ) {
376                FinallyStmt * finally = tryStmt->get_finally();
377                CompoundStmt * body = finally->get_block();
378                finally->set_block( nullptr );
379                delete finally;
380                tryStmt->set_finally( nullptr );
381
382                return new FunctionDecl("finally", Type::StorageClasses(),
383                        LinkageSpec::Cforall, void_func_t.clone(), body);
384        }
385
386        ObjectDecl * create_finally_hook(
387                        StructDecl * hook_decl, FunctionDecl * finally_wrapper ) {
388                // struct __cfaehm__cleanup_hook __finally_hook
389                //      __attribute__((cleanup( finally_wrapper )));
390
391                // Make Cleanup Attribute.
392                std::list< Attribute * > attributes;
393                {
394                        std::list< Expression * > attr_params;
395                        attr_params.push_back( nameOf( finally_wrapper ) );
396                        attributes.push_back( new Attribute( "cleanup", attr_params ) );
397                }
398
399                return new ObjectDecl(
400                        "__finally_hook",
401                        Type::StorageClasses(),
402                        LinkageSpec::Cforall,
403                        nullptr,
404                        new StructInstType(
405                                emptyQualifiers,
406                                hook_decl
407                                ),
408                        nullptr,
409                        attributes
410                        );
411        }
412
413
414        class ExceptionMutatorCore : public WithScopes {
415                enum Context { NoHandler, TerHandler, ResHandler };
416
417                // Also need to handle goto, break & continue.
418                // They need to be cut off in a ResHandler, until we enter another
419                // loop, switch or the goto stays within the function.
420
421                Context cur_context;
422
423                // We might not need this, but a unique base for each try block's
424                // generated functions might be nice.
425                //std::string curFunctionName;
426                //unsigned int try_count = 0;
427
428                StructDecl *node_decl;
429                StructDecl *hook_decl;
430
431        public:
432                ExceptionMutatorCore() :
433                        cur_context(NoHandler),
434                        node_decl(nullptr), hook_decl(nullptr)
435                {}
436
437                void premutate( CatchStmt *catchStmt );
438                void premutate( StructDecl *structDecl );
439                Statement * postmutate( ThrowStmt *throwStmt );
440                Statement * postmutate( TryStmt *tryStmt );
441        };
442
443        Statement * ExceptionMutatorCore::postmutate( ThrowStmt *throwStmt ) {
444                // Ignoring throwStmt->get_target() for now.
445                if ( ThrowStmt::Terminate == throwStmt->get_kind() ) {
446                        if ( throwStmt->get_expr() ) {
447                                return create_terminate_throw( throwStmt );
448                        } else if ( TerHandler == cur_context ) {
449                                return create_terminate_rethrow( throwStmt );
450                        } else {
451                                assertf(false, "Invalid throw in %s at %i\n",
452                                        throwStmt->location.filename.c_str(),
453                                        throwStmt->location.linenumber);
454                                return nullptr;
455                        }
456                } else {
457                        if ( throwStmt->get_expr() ) {
458                                return create_resume_throw( throwStmt );
459                        } else if ( ResHandler == cur_context ) {
460                                return create_resume_rethrow( throwStmt );
461                        } else {
462                                assertf(false, "Invalid throwResume in %s at %i\n",
463                                        throwStmt->location.filename.c_str(),
464                                        throwStmt->location.linenumber);
465                                return nullptr;
466                        }
467                }
468        }
469
470        Statement * ExceptionMutatorCore::postmutate( TryStmt *tryStmt ) {
471                assert( node_decl );
472                assert( hook_decl );
473
474                // Generate a prefix for the function names?
475
476                CompoundStmt * block = new CompoundStmt( noLabels );
477                CompoundStmt * inner = take_try_block( tryStmt );
478
479                if ( tryStmt->get_finally() ) {
480                        // Define the helper function.
481                        FunctionDecl * finally_block =
482                                create_finally_wrapper( tryStmt );
483                        appendDeclStmt( block, finally_block );
484                        // Create and add the finally cleanup hook.
485                        appendDeclStmt( block,
486                                create_finally_hook( hook_decl, finally_block ) );
487                }
488
489                CatchList termination_handlers;
490                CatchList resumption_handlers;
491                split( tryStmt->get_catchers(),
492                       termination_handlers, resumption_handlers );
493
494                if ( resumption_handlers.size() ) {
495                        // Define the helper function.
496                        FunctionDecl * resume_handler =
497                                create_resume_handler( resumption_handlers );
498                        appendDeclStmt( block, resume_handler );
499                        // Prepare hooks
500                        inner = create_resume_wrapper( node_decl, inner, resume_handler );
501                }
502
503                if ( termination_handlers.size() ) {
504                        // Define the three helper functions.
505                        FunctionDecl * try_wrapper = create_try_wrapper( inner );
506                        appendDeclStmt( block, try_wrapper );
507                        FunctionDecl * terminate_catch =
508                                create_terminate_catch( termination_handlers );
509                        appendDeclStmt( block, terminate_catch );
510                        FunctionDecl * terminate_match =
511                                create_terminate_match( termination_handlers );
512                        appendDeclStmt( block, terminate_match );
513                        // Build the call to the try wrapper.
514                        inner = create_terminate_caller(
515                                try_wrapper, terminate_catch, terminate_match );
516                }
517
518                // Embed the try block.
519                block->push_back( inner );
520
521                //free_all( termination_handlers );
522                //free_all( resumption_handlers );
523
524                return block;
525        }
526
527        void ExceptionMutatorCore::premutate( CatchStmt *catchStmt ) {
528                GuardValue( cur_context );
529                if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
530                        cur_context = TerHandler;
531                } else {
532                        cur_context = ResHandler;
533                }
534        }
535
536        void ExceptionMutatorCore::premutate( StructDecl *structDecl ) {
537                if ( !structDecl->has_body() ) {
538                        // Skip children?
539                        return;
540                } else if ( structDecl->get_name() == "__cfaehm__try_resume_node" ) {
541                        assert( nullptr == node_decl );
542                        node_decl = structDecl;
543                } else if ( structDecl->get_name() == "__cfaehm__cleanup_hook" ) {
544                        assert( nullptr == hook_decl );
545                        hook_decl = structDecl;
546                }
547                // Later we might get the exception type as well.
548        }
549
550    void translateEHM( std::list< Declaration *> & translationUnit ) {
551                init_func_types();
552
553                PassVisitor<ExceptionMutatorCore> translator;
554                for ( Declaration * decl : translationUnit ) {
555                        decl->acceptMutator( translator );
556                }
557        }
558}
Note: See TracBrowser for help on using the repository browser.