source: src/ControlStruct/ExceptTranslate.cc @ ba912706

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

Exception translation code (draft) added.

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