source: src/Concurrency/KeywordsNew.cpp @ 21a2a7d

ADTast-experimental
Last change on this file since 21a2a7d was e01eb4a, checked in by Andrew Beach <ajbeach@…>, 19 months ago

Moved some functions from InitTweak? to Inspect.

  • Property mode set to 100644
File size: 48.0 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 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// KeywordsNew.cpp -- Implement concurrency constructs from their keywords.
8//
9// Author           : Andrew Beach
10// Created On       : Tue Nov 16  9:53:00 2021
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Mar 11 10:40:00 2022
13// Update Count     : 2
14//
15
16#include <iostream>
17
18#include "Concurrency/Keywords.h"
19
20#include "AST/Copy.hpp"
21#include "AST/Decl.hpp"
22#include "AST/Expr.hpp"
23#include "AST/Inspect.hpp"
24#include "AST/Pass.hpp"
25#include "AST/Stmt.hpp"
26#include "AST/DeclReplacer.hpp"
27#include "AST/TranslationUnit.hpp"
28#include "CodeGen/OperatorTable.h"
29#include "Common/Examine.h"
30#include "Common/utility.h"
31#include "Common/UniqueName.h"
32#include "ControlStruct/LabelGeneratorNew.hpp"
33#include "InitTweak/InitTweak.h"
34#include "Virtual/Tables.h"
35
36namespace Concurrency {
37
38namespace {
39
40// --------------------------------------------------------------------------
41// Loose Helper Functions:
42
43/// Detect threads constructed with the keyword thread.
44bool isThread( const ast::DeclWithType * decl ) {
45        auto baseType = decl->get_type()->stripDeclarator();
46        auto instType = dynamic_cast<const ast::StructInstType *>( baseType );
47        if ( nullptr == instType ) { return false; }
48        return instType->base->is_thread();
49}
50
51/// Get the virtual type id if given a type name.
52std::string typeIdType( std::string const & exception_name ) {
53        return exception_name.empty() ? std::string()
54                : Virtual::typeIdType( exception_name );
55}
56
57/// Get the vtable type name if given a type name.
58std::string vtableTypeName( std::string const & exception_name ) {
59        return exception_name.empty() ? std::string()
60                : Virtual::vtableTypeName( exception_name );
61}
62
63static ast::Type * mutate_under_references( ast::ptr<ast::Type>& type ) {
64        ast::Type * mutType = type.get_and_mutate();
65        for ( ast::ReferenceType * mutRef
66                ; (mutRef = dynamic_cast<ast::ReferenceType *>( mutType ))
67                ; mutType = mutRef->base.get_and_mutate() );
68        return mutType;
69}
70
71// Describe that it adds the generic parameters and the uses of the generic
72// parameters on the function and first "this" argument.
73ast::FunctionDecl * fixupGenerics(
74                const ast::FunctionDecl * func, const ast::StructDecl * decl ) {
75        const CodeLocation & location = decl->location;
76        // We have to update both the declaration
77        auto mutFunc = ast::mutate( func );
78        auto mutType = mutFunc->type.get_and_mutate();
79
80        if ( decl->params.empty() ) {
81                return mutFunc;
82        }
83
84        assert( 0 != mutFunc->params.size() );
85        assert( 0 != mutType->params.size() );
86
87        // Add the "forall" clause information.
88        for ( const ast::ptr<ast::TypeDecl> & typeParam : decl->params ) {
89                auto typeDecl = ast::deepCopy( typeParam );
90                mutFunc->type_params.push_back( typeDecl );
91                mutType->forall.push_back( new ast::TypeInstType( typeDecl ) );
92                for ( auto & assertion : typeDecl->assertions ) {
93                        mutFunc->assertions.push_back( assertion );
94                        mutType->assertions.emplace_back(
95                                new ast::VariableExpr( location, assertion ) );
96                }
97                typeDecl->assertions.clear();
98        }
99
100        // Even chain_mutate is not powerful enough for this:
101        ast::ptr<ast::Type>& paramType = strict_dynamic_cast<ast::ObjectDecl *>(
102                mutFunc->params[0].get_and_mutate() )->type;
103        auto paramTypeInst = strict_dynamic_cast<ast::StructInstType *>(
104                mutate_under_references( paramType ) );
105        auto typeParamInst = strict_dynamic_cast<ast::StructInstType *>(
106                mutate_under_references( mutType->params[0] ) );
107
108        for ( const ast::ptr<ast::TypeDecl> & typeDecl : mutFunc->type_params ) {
109                paramTypeInst->params.push_back(
110                        new ast::TypeExpr( location, new ast::TypeInstType( typeDecl ) ) );
111                typeParamInst->params.push_back(
112                        new ast::TypeExpr( location, new ast::TypeInstType( typeDecl ) ) );
113        }
114
115        return mutFunc;
116}
117
118// --------------------------------------------------------------------------
119struct ConcurrentSueKeyword : public ast::WithDeclsToAdd<> {
120        ConcurrentSueKeyword(
121                std::string&& type_name, std::string&& field_name,
122                std::string&& getter_name, std::string&& context_error,
123                std::string&& exception_name,
124                bool needs_main, ast::AggregateDecl::Aggregate cast_target
125        ) :
126                type_name( type_name ), field_name( field_name ),
127                getter_name( getter_name ), context_error( context_error ),
128                exception_name( exception_name ),
129                typeid_name( typeIdType( exception_name ) ),
130                vtable_name( vtableTypeName( exception_name ) ),
131                needs_main( needs_main ), cast_target( cast_target )
132        {}
133
134        virtual ~ConcurrentSueKeyword() {}
135
136        const ast::Decl * postvisit( const ast::StructDecl * decl );
137        const ast::DeclWithType * postvisit( const ast::FunctionDecl * decl );
138        const ast::Expr * postvisit( const ast::KeywordCastExpr * expr );
139
140        struct StructAndField {
141                const ast::StructDecl * decl;
142                const ast::ObjectDecl * field;
143        };
144
145        const ast::StructDecl * handleStruct( const ast::StructDecl * );
146        void handleMain( const ast::FunctionDecl *, const ast::StructInstType * );
147        void addTypeId( const ast::StructDecl * );
148        void addVtableForward( const ast::StructDecl * );
149        const ast::FunctionDecl * forwardDeclare( const ast::StructDecl * );
150        StructAndField addField( const ast::StructDecl * );
151        void addGetRoutines( const ast::ObjectDecl *, const ast::FunctionDecl * );
152        void addLockUnlockRoutines( const ast::StructDecl * );
153
154private:
155        const std::string type_name;
156        const std::string field_name;
157        const std::string getter_name;
158        const std::string context_error;
159        const std::string exception_name;
160        const std::string typeid_name;
161        const std::string vtable_name;
162        const bool needs_main;
163        const ast::AggregateDecl::Aggregate cast_target;
164
165        const ast::StructDecl   * type_decl = nullptr;
166        const ast::FunctionDecl * dtor_decl = nullptr;
167        const ast::StructDecl * except_decl = nullptr;
168        const ast::StructDecl * typeid_decl = nullptr;
169        const ast::StructDecl * vtable_decl = nullptr;
170
171};
172
173// Handles thread type declarations:
174//
175// thread Mythread {                         struct MyThread {
176//  int data;                                  int data;
177//  a_struct_t more_data;                      a_struct_t more_data;
178//                                =>             thread$ __thrd_d;
179// };                                        };
180//                                           static inline thread$ * get_thread( MyThread * this ) { return &this->__thrd_d; }
181//
182struct ThreadKeyword final : public ConcurrentSueKeyword {
183        ThreadKeyword() : ConcurrentSueKeyword(
184                "thread$",
185                "__thrd",
186                "get_thread",
187                "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
188                "ThreadCancelled",
189                true,
190                ast::AggregateDecl::Thread )
191        {}
192
193        virtual ~ThreadKeyword() {}
194};
195
196// Handles coroutine type declarations:
197//
198// coroutine MyCoroutine {                   struct MyCoroutine {
199//  int data;                                  int data;
200//  a_struct_t more_data;                      a_struct_t more_data;
201//                                =>             coroutine$ __cor_d;
202// };                                        };
203//                                           static inline coroutine$ * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
204//
205struct CoroutineKeyword final : public ConcurrentSueKeyword {
206        CoroutineKeyword() : ConcurrentSueKeyword(
207                "coroutine$",
208                "__cor",
209                "get_coroutine",
210                "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
211                "CoroutineCancelled",
212                true,
213                ast::AggregateDecl::Coroutine )
214        {}
215
216        virtual ~CoroutineKeyword() {}
217};
218
219// Handles monitor type declarations:
220//
221// monitor MyMonitor {                       struct MyMonitor {
222//  int data;                                  int data;
223//  a_struct_t more_data;                      a_struct_t more_data;
224//                                =>             monitor$ __mon_d;
225// };                                        };
226//                                           static inline monitor$ * get_coroutine( MyMonitor * this ) {
227//                                               return &this->__cor_d;
228//                                           }
229//                                           void lock(MyMonitor & this) {
230//                                               lock(get_monitor(this));
231//                                           }
232//                                           void unlock(MyMonitor & this) {
233//                                               unlock(get_monitor(this));
234//                                           }
235//
236struct MonitorKeyword final : public ConcurrentSueKeyword {
237        MonitorKeyword() : ConcurrentSueKeyword(
238                "monitor$",
239                "__mon",
240                "get_monitor",
241                "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
242                "",
243                false,
244                ast::AggregateDecl::Monitor )
245        {}
246
247        virtual ~MonitorKeyword() {}
248};
249
250// Handles generator type declarations:
251//
252// generator MyGenerator {                   struct MyGenerator {
253//  int data;                                  int data;
254//  a_struct_t more_data;                      a_struct_t more_data;
255//                                =>             int __generator_state;
256// };                                        };
257//
258struct GeneratorKeyword final : public ConcurrentSueKeyword {
259        GeneratorKeyword() : ConcurrentSueKeyword(
260                "generator$",
261                "__generator_state",
262                "get_generator",
263                "Unable to find builtin type generator$\n",
264                "",
265                true,
266                ast::AggregateDecl::Generator )
267        {}
268
269        virtual ~GeneratorKeyword() {}
270};
271
272const ast::Decl * ConcurrentSueKeyword::postvisit(
273                const ast::StructDecl * decl ) {
274        if ( !decl->body ) {
275                return decl;
276        } else if ( cast_target == decl->kind ) {
277                return handleStruct( decl );
278        } else if ( type_name == decl->name ) {
279                assert( !type_decl );
280                type_decl = decl;
281        } else if ( exception_name == decl->name ) {
282                assert( !except_decl );
283                except_decl = decl;
284        } else if ( typeid_name == decl->name ) {
285                assert( !typeid_decl );
286                typeid_decl = decl;
287        } else if ( vtable_name == decl->name ) {
288                assert( !vtable_decl );
289                vtable_decl = decl;
290        }
291        return decl;
292}
293
294// Try to get the full definition, but raise an error on conflicts.
295const ast::FunctionDecl * getDefinition(
296                const ast::FunctionDecl * old_decl,
297                const ast::FunctionDecl * new_decl ) {
298        if ( !new_decl->stmts ) {
299                return old_decl;
300        } else if ( !old_decl->stmts ) {
301                return new_decl;
302        } else {
303                assert( !old_decl->stmts || !new_decl->stmts );
304                return nullptr;
305        }
306}
307
308const ast::DeclWithType * ConcurrentSueKeyword::postvisit(
309                const ast::FunctionDecl * decl ) {
310        if ( type_decl && isDestructorFor( decl, type_decl ) ) {
311                // Check for forward declarations, try to get the full definition.
312                dtor_decl = (dtor_decl) ? getDefinition( dtor_decl, decl ) : decl;
313        } else if ( !vtable_name.empty() && decl->has_body() ) {
314                if (const ast::DeclWithType * param = isMainFor( decl, cast_target )) {
315                        if ( !vtable_decl ) {
316                                SemanticError( decl, context_error );
317                        }
318                        // Should be safe because of isMainFor.
319                        const ast::StructInstType * struct_type =
320                                static_cast<const ast::StructInstType *>(
321                                        static_cast<const ast::ReferenceType *>(
322                                                param->get_type() )->base.get() );
323
324                        handleMain( decl, struct_type );
325                }
326        }
327        return decl;
328}
329
330const ast::Expr * ConcurrentSueKeyword::postvisit(
331                const ast::KeywordCastExpr * expr ) {
332        if ( cast_target == expr->target ) {
333                // Convert `(thread &)ex` to `(thread$ &)*get_thread(ex)`, etc.
334                if ( !type_decl || !dtor_decl ) {
335                        SemanticError( expr, context_error );
336                }
337                assert( nullptr == expr->result );
338                auto cast = ast::mutate( expr );
339                cast->result = new ast::ReferenceType( new ast::StructInstType( type_decl ) );
340                cast->concrete_target.field  = field_name;
341                cast->concrete_target.getter = getter_name;
342                return cast;
343        }
344        return expr;
345}
346
347const ast::StructDecl * ConcurrentSueKeyword::handleStruct(
348                const ast::StructDecl * decl ) {
349        assert( decl->body );
350
351        if ( !type_decl || !dtor_decl ) {
352                SemanticError( decl, context_error );
353        }
354
355        if ( !exception_name.empty() ) {
356                if( !typeid_decl || !vtable_decl ) {
357                        SemanticError( decl, context_error );
358                }
359                addTypeId( decl );
360                addVtableForward( decl );
361        }
362
363        const ast::FunctionDecl * func = forwardDeclare( decl );
364        StructAndField addFieldRet = addField( decl );
365        decl = addFieldRet.decl;
366        const ast::ObjectDecl * field = addFieldRet.field;
367
368        addGetRoutines( field, func );
369        // Add routines to monitors for use by mutex stmt.
370        if ( ast::AggregateDecl::Monitor == cast_target ) {
371                addLockUnlockRoutines( decl );
372        }
373
374        return decl;
375}
376
377void ConcurrentSueKeyword::handleMain(
378                const ast::FunctionDecl * decl, const ast::StructInstType * type ) {
379        assert( vtable_decl );
380        assert( except_decl );
381
382        const CodeLocation & location = decl->location;
383
384        std::vector<ast::ptr<ast::Expr>> poly_args = {
385                new ast::TypeExpr( location, type ),
386        };
387        ast::ObjectDecl * vtable_object = Virtual::makeVtableInstance(
388                location,
389                "_default_vtable_object_declaration",
390                new ast::StructInstType( vtable_decl, copy( poly_args ) ),
391                type,
392                nullptr
393        );
394        declsToAddAfter.push_back( vtable_object );
395        declsToAddAfter.push_back(
396                new ast::ObjectDecl(
397                        location,
398                        Virtual::concurrentDefaultVTableName(),
399                        new ast::ReferenceType( vtable_object->type, ast::CV::Const ),
400                        new ast::SingleInit( location,
401                                new ast::VariableExpr( location, vtable_object ) )
402                )
403        );
404        declsToAddAfter.push_back( Virtual::makeGetExceptionFunction(
405                location,
406                vtable_object,
407                new ast::StructInstType( except_decl, copy( poly_args ) )
408        ) );
409}
410
411void ConcurrentSueKeyword::addTypeId( const ast::StructDecl * decl ) {
412        assert( typeid_decl );
413        const CodeLocation & location = decl->location;
414
415        ast::StructInstType * typeid_type =
416                new ast::StructInstType( typeid_decl, ast::CV::Const );
417        typeid_type->params.push_back(
418                new ast::TypeExpr( location, new ast::StructInstType( decl ) ) );
419        declsToAddBefore.push_back(
420                Virtual::makeTypeIdInstance( location, typeid_type ) );
421        // If the typeid_type is going to be kept, the other reference will have
422        // been made by now, but we also get to avoid extra mutates.
423        ast::ptr<ast::StructInstType> typeid_cleanup = typeid_type;
424}
425
426void ConcurrentSueKeyword::addVtableForward( const ast::StructDecl * decl ) {
427        assert( vtable_decl );
428        const CodeLocation& location = decl->location;
429
430        std::vector<ast::ptr<ast::Expr>> poly_args = {
431                new ast::TypeExpr( location, new ast::StructInstType( decl ) ),
432        };
433        declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
434                location,
435                new ast::StructInstType( vtable_decl, copy( poly_args ) ),
436                new ast::StructInstType( except_decl, copy( poly_args ) )
437        ) );
438        ast::ObjectDecl * vtable_object = Virtual::makeVtableForward(
439                location,
440                "_default_vtable_object_declaration",
441                new ast::StructInstType( vtable_decl, std::move( poly_args ) )
442        );
443        declsToAddBefore.push_back( vtable_object );
444        declsToAddBefore.push_back(
445                new ast::ObjectDecl(
446                        location,
447                        Virtual::concurrentDefaultVTableName(),
448                        new ast::ReferenceType( vtable_object->type, ast::CV::Const ),
449                        nullptr,
450                        ast::Storage::Extern,
451                        ast::Linkage::Cforall
452                )
453        );
454}
455
456const ast::FunctionDecl * ConcurrentSueKeyword::forwardDeclare(
457                const ast::StructDecl * decl ) {
458        const CodeLocation & location = decl->location;
459
460        ast::StructDecl * forward = ast::deepCopy( decl );
461        {
462                // If removing members makes ref-count go to zero, do not free.
463                ast::ptr<ast::StructDecl> forward_ptr = forward;
464                forward->body = false;
465                forward->members.clear();
466                forward_ptr.release();
467        }
468
469        ast::ObjectDecl * this_decl = new ast::ObjectDecl(
470                location,
471                "this",
472                new ast::ReferenceType( new ast::StructInstType( decl ) )
473        );
474
475        ast::ObjectDecl * ret_decl = new ast::ObjectDecl(
476                location,
477                "ret",
478                new ast::PointerType( new ast::StructInstType( type_decl ) )
479        );
480
481        ast::FunctionDecl * get_decl = new ast::FunctionDecl(
482                location,
483                getter_name,
484                {}, // forall
485                { this_decl }, // params
486                { ret_decl }, // returns
487                nullptr, // stmts
488                ast::Storage::Static,
489                ast::Linkage::Cforall,
490                { new ast::Attribute( "const" ) },
491                ast::Function::Inline
492        );
493        get_decl = fixupGenerics( get_decl, decl );
494
495        ast::FunctionDecl * main_decl = nullptr;
496        if ( needs_main ) {
497                // `this_decl` is copied here because the original was used above.
498                main_decl = new ast::FunctionDecl(
499                        location,
500                        "main",
501                        {},
502                        { ast::deepCopy( this_decl ) },
503                        {},
504                        nullptr,
505                        ast::Storage::Classes(),
506                        ast::Linkage::Cforall
507                );
508                main_decl = fixupGenerics( main_decl, decl );
509        }
510
511        declsToAddBefore.push_back( forward );
512        if ( needs_main ) declsToAddBefore.push_back( main_decl );
513        declsToAddBefore.push_back( get_decl );
514
515        return get_decl;
516}
517
518ConcurrentSueKeyword::StructAndField ConcurrentSueKeyword::addField(
519                const ast::StructDecl * decl ) {
520        const CodeLocation & location = decl->location;
521
522        ast::ObjectDecl * field = new ast::ObjectDecl(
523                location,
524                field_name,
525                new ast::StructInstType( type_decl )
526        );
527
528        auto mutDecl = ast::mutate( decl );
529        mutDecl->members.push_back( field );
530
531        return {mutDecl, field};
532}
533
534void ConcurrentSueKeyword::addGetRoutines(
535                const ast::ObjectDecl * field, const ast::FunctionDecl * forward ) {
536        // Say it is generated at the "same" places as the forward declaration.
537        const CodeLocation & location = forward->location;
538
539        const ast::DeclWithType * param = forward->params.front();
540        ast::Stmt * stmt = new ast::ReturnStmt( location,
541                new ast::AddressExpr( location,
542                        new ast::MemberExpr( location,
543                                field,
544                                new ast::CastExpr( location,
545                                        new ast::VariableExpr( location, param ),
546                                        ast::deepCopy( param->get_type()->stripReferences() ),
547                                        ast::ExplicitCast
548                                )
549                        )
550                )
551        );
552
553        ast::FunctionDecl * decl = ast::deepCopy( forward );
554        decl->stmts = new ast::CompoundStmt( location, { stmt } );
555        declsToAddAfter.push_back( decl );
556}
557
558void ConcurrentSueKeyword::addLockUnlockRoutines(
559                const ast::StructDecl * decl ) {
560        // This should only be used on monitors.
561        assert( ast::AggregateDecl::Monitor == cast_target );
562
563        const CodeLocation & location = decl->location;
564
565        // The parameter for both routines.
566        ast::ObjectDecl * this_decl = new ast::ObjectDecl(
567                location,
568                "this",
569                new ast::ReferenceType( new ast::StructInstType( decl ) )
570        );
571
572        ast::FunctionDecl * lock_decl = new ast::FunctionDecl(
573                location,
574                "lock",
575                { /* forall */ },
576                {
577                        // Copy the declaration of this.
578                        ast::deepCopy( this_decl ),
579                },
580                { /* returns */ },
581                nullptr,
582                ast::Storage::Static,
583                ast::Linkage::Cforall,
584                { /* attributes */ },
585                ast::Function::Inline
586        );
587        lock_decl = fixupGenerics( lock_decl, decl );
588
589        lock_decl->stmts = new ast::CompoundStmt( location, {
590                new ast::ExprStmt( location,
591                        new ast::UntypedExpr( location,
592                                new ast::NameExpr( location, "lock" ),
593                                {
594                                        new ast::UntypedExpr( location,
595                                                new ast::NameExpr( location, "get_monitor" ),
596                                                { new ast::VariableExpr( location,
597                                                        InitTweak::getParamThis( lock_decl ) ) }
598                                        )
599                                }
600                        )
601                )
602        } );
603
604        ast::FunctionDecl * unlock_decl = new ast::FunctionDecl(
605                location,
606                "unlock",
607                { /* forall */ },
608                {
609                        // Last use, consume the declaration of this.
610                        this_decl,
611                },
612                { /* returns */ },
613                nullptr,
614                ast::Storage::Static,
615                ast::Linkage::Cforall,
616                { /* attributes */ },
617                ast::Function::Inline
618        );
619        unlock_decl = fixupGenerics( unlock_decl, decl );
620
621        unlock_decl->stmts = new ast::CompoundStmt( location, {
622                new ast::ExprStmt( location,
623                        new ast::UntypedExpr( location,
624                                new ast::NameExpr( location, "unlock" ),
625                                {
626                                        new ast::UntypedExpr( location,
627                                                new ast::NameExpr( location, "get_monitor" ),
628                                                { new ast::VariableExpr( location,
629                                                        InitTweak::getParamThis( unlock_decl ) ) }
630                                        )
631                                }
632                        )
633                )
634        } );
635
636        declsToAddAfter.push_back( lock_decl );
637        declsToAddAfter.push_back( unlock_decl );
638}
639
640
641// --------------------------------------------------------------------------
642struct SuspendKeyword final :
643                public ast::WithStmtsToAdd<>, public ast::WithGuards {
644        SuspendKeyword() = default;
645        virtual ~SuspendKeyword() = default;
646
647        void previsit( const ast::FunctionDecl * );
648        const ast::DeclWithType * postvisit( const ast::FunctionDecl * );
649        const ast::Stmt * postvisit( const ast::SuspendStmt * );
650
651private:
652        bool is_real_suspend( const ast::FunctionDecl * );
653
654        const ast::Stmt * make_generator_suspend( const ast::SuspendStmt * );
655        const ast::Stmt * make_coroutine_suspend( const ast::SuspendStmt * );
656
657        struct LabelPair {
658                ast::Label obj;
659                int idx;
660        };
661
662        LabelPair make_label(const ast::Stmt * stmt ) {
663                labels.push_back( ControlStruct::newLabel( "generator", stmt ) );
664                return { labels.back(), int(labels.size()) };
665        }
666
667        const ast::DeclWithType * in_generator = nullptr;
668        const ast::FunctionDecl * decl_suspend = nullptr;
669        std::vector<ast::Label> labels;
670};
671
672void SuspendKeyword::previsit( const ast::FunctionDecl * decl ) {
673        GuardValue( in_generator ); in_generator = nullptr;
674
675        // If it is the real suspend, grab it if we don't have one already.
676        if ( is_real_suspend( decl ) ) {
677                decl_suspend = decl_suspend ? decl_suspend : decl;
678                return;
679        }
680
681        // Otherwise check if this is a generator main and, if so, handle it.
682        auto param = isMainFor( decl, ast::AggregateDecl::Generator );
683        if ( !param ) return;
684
685        if ( 0 != decl->returns.size() ) {
686                SemanticError( decl->location, "Generator main must return void" );
687        }
688
689        in_generator = param;
690        GuardValue( labels ); labels.clear();
691}
692
693const ast::DeclWithType * SuspendKeyword::postvisit(
694                const ast::FunctionDecl * decl ) {
695        // Only modify a full definition of a generator with states.
696        if ( !decl->stmts || !in_generator || labels.empty() ) return decl;
697
698        const CodeLocation & location = decl->location;
699
700        // Create a new function body:
701        // static void * __generator_labels[] = {&&s0, &&s1, ...};
702        // void * __generator_label = __generator_labels[GEN.__generator_state];
703        // goto * __generator_label;
704        // s0: ;
705        // OLD_BODY
706
707        // This is the null statement inserted right before the body.
708        ast::NullStmt * noop = new ast::NullStmt( location );
709        noop->labels.push_back( ControlStruct::newLabel( "generator", noop ) );
710        const ast::Label & first_label = noop->labels.back();
711
712        // Add each label to the init, starting with the first label.
713        std::vector<ast::ptr<ast::Init>> inits = {
714                new ast::SingleInit( location,
715                        new ast::LabelAddressExpr( location, copy( first_label ) ) ) };
716        // Then go through all the stored labels, and clear the store.
717        for ( auto && label : labels ) {
718                inits.push_back( new ast::SingleInit( label.location,
719                        new ast::LabelAddressExpr( label.location, std::move( label )
720                        ) ) );
721        }
722        labels.clear();
723        // Then construct the initializer itself.
724        auto init = new ast::ListInit( location, std::move( inits ) );
725
726        ast::ObjectDecl * generatorLabels = new ast::ObjectDecl(
727                location,
728                "__generator_labels",
729                new ast::ArrayType(
730                        new ast::PointerType( new ast::VoidType() ),
731                        nullptr,
732                        ast::FixedLen,
733                        ast::DynamicDim
734                ),
735                init,
736                ast::Storage::Classes(),
737                ast::Linkage::AutoGen
738        );
739
740        ast::ObjectDecl * generatorLabel = new ast::ObjectDecl(
741                location,
742                "__generator_label",
743                new ast::PointerType( new ast::VoidType() ),
744                new ast::SingleInit( location,
745                        new ast::UntypedExpr( location,
746                                new ast::NameExpr( location, "?[?]" ),
747                                {
748                                        // TODO: Could be a variable expr.
749                                        new ast::NameExpr( location, "__generator_labels" ),
750                                        new ast::UntypedMemberExpr( location,
751                                                new ast::NameExpr( location, "__generator_state" ),
752                                                new ast::VariableExpr( location, in_generator )
753                                        )
754                                }
755                        )
756                ),
757                ast::Storage::Classes(),
758                ast::Linkage::AutoGen
759        );
760
761        ast::BranchStmt * theGoTo = new ast::BranchStmt(
762                location, new ast::VariableExpr( location, generatorLabel )
763        );
764
765        // The noop goes here in order.
766
767        ast::CompoundStmt * body = new ast::CompoundStmt( location, {
768                { new ast::DeclStmt( location, generatorLabels ) },
769                { new ast::DeclStmt( location, generatorLabel ) },
770                { theGoTo },
771                { noop },
772                { decl->stmts },
773        } );
774
775        auto mutDecl = ast::mutate( decl );
776        mutDecl->stmts = body;
777        return mutDecl;
778}
779
780const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) {
781        switch ( stmt->type ) {
782        case ast::SuspendStmt::None:
783                // Use the context to determain the implicit target.
784                if ( in_generator ) {
785                        return make_generator_suspend( stmt );
786                } else {
787                        return make_coroutine_suspend( stmt );
788                }
789        case ast::SuspendStmt::Coroutine:
790                return make_coroutine_suspend( stmt );
791        case ast::SuspendStmt::Generator:
792                // Generator suspends must be directly in a generator.
793                if ( !in_generator ) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type." );
794                return make_generator_suspend( stmt );
795        }
796        assert( false );
797        return stmt;
798}
799
800/// Find the real/official suspend declaration.
801bool SuspendKeyword::is_real_suspend( const ast::FunctionDecl * decl ) {
802        return ( !decl->linkage.is_mangled
803                && 0 == decl->params.size()
804                && 0 == decl->returns.size()
805                && "__cfactx_suspend" == decl->name );
806}
807
808const ast::Stmt * SuspendKeyword::make_generator_suspend(
809                const ast::SuspendStmt * stmt ) {
810        assert( in_generator );
811        // Target code is:
812        //   GEN.__generator_state = X;
813        //   THEN
814        //   return;
815        //   __gen_X:;
816
817        const CodeLocation & location = stmt->location;
818
819        LabelPair label = make_label( stmt );
820
821        // This is the context saving statement.
822        stmtsToAddBefore.push_back( new ast::ExprStmt( location,
823                new ast::UntypedExpr( location,
824                        new ast::NameExpr( location, "?=?" ),
825                        {
826                                new ast::UntypedMemberExpr( location,
827                                        new ast::NameExpr( location, "__generator_state" ),
828                                        new ast::VariableExpr( location, in_generator )
829                                ),
830                                ast::ConstantExpr::from_int( location, label.idx ),
831                        }
832                )
833        ) );
834
835        // The THEN component is conditional (return is not).
836        if ( stmt->then ) {
837                stmtsToAddBefore.push_back( stmt->then.get() );
838        }
839        stmtsToAddBefore.push_back( new ast::ReturnStmt( location, nullptr ) );
840
841        // The null statement replaces the old suspend statement.
842        return new ast::NullStmt( location, { label.obj } );
843}
844
845const ast::Stmt * SuspendKeyword::make_coroutine_suspend(
846                const ast::SuspendStmt * stmt ) {
847        // The only thing we need from the old statement is the location.
848        const CodeLocation & location = stmt->location;
849
850        if ( !decl_suspend ) {
851                SemanticError( location, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n" );
852        }
853        if ( stmt->then ) {
854                SemanticError( location, "Compound statement following coroutines is not implemented." );
855        }
856
857        return new ast::ExprStmt( location,
858                new ast::UntypedExpr( location,
859                        ast::VariableExpr::functionPointer( location, decl_suspend ) )
860        );
861}
862
863// --------------------------------------------------------------------------
864struct MutexKeyword final : public ast::WithDeclsToAdd<> {
865        const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl );
866        void postvisit( const ast::StructDecl * decl );
867        const ast::Stmt * postvisit( const ast::MutexStmt * stmt );
868
869        static std::vector<const ast::DeclWithType *> findMutexArgs(
870                        const ast::FunctionDecl * decl, bool & first );
871        static void validate( const ast::DeclWithType * decl );
872
873        ast::CompoundStmt * addDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt *, const std::vector<const ast::DeclWithType *> &);
874        ast::CompoundStmt * addStatements( const ast::FunctionDecl* func, const ast::CompoundStmt *, const std::vector<const ast::DeclWithType *> &);
875        ast::CompoundStmt * addStatements( const ast::CompoundStmt * body, const std::vector<ast::ptr<ast::Expr>> & args );
876        ast::CompoundStmt * addThreadDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt * body, const std::vector<const ast::DeclWithType *> & args );
877        ast::ExprStmt * genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param);
878        ast::IfStmt * genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam );
879private:
880        const ast::StructDecl * monitor_decl = nullptr;
881        const ast::StructDecl * guard_decl = nullptr;
882        const ast::StructDecl * dtor_guard_decl = nullptr;
883        const ast::StructDecl * thread_guard_decl = nullptr;
884        const ast::StructDecl * lock_guard_decl = nullptr;
885
886        static ast::ptr<ast::Type> generic_func;
887
888        UniqueName mutex_func_namer = UniqueName("__lock_unlock_curr");
889};
890
891const ast::FunctionDecl * MutexKeyword::postvisit(
892                const ast::FunctionDecl * decl ) {
893        bool is_first_argument_mutex = false;
894        const std::vector<const ast::DeclWithType *> mutexArgs =
895                findMutexArgs( decl, is_first_argument_mutex );
896        bool const isDtor = CodeGen::isDestructor( decl->name );
897
898        // Does this function have any mutex arguments that connect to monitors?
899        if ( mutexArgs.empty() ) {
900                // If this is the destructor for a monitor it must be mutex.
901                if ( isDtor ) {
902                        // This reflects MutexKeyword::validate, but no error messages.
903                        const ast::Type * type = decl->type->params.front();
904
905                        // If it's a copy, it's not a mutex.
906                        const ast::ReferenceType * refType = dynamic_cast<const ast::ReferenceType *>( type );
907                        if ( nullptr == refType ) {
908                                return decl;
909                        }
910
911                        // If it is not pointing directly to a type, it's not a mutex.
912                        auto base = refType->base;
913                        if ( base.as<ast::ReferenceType>() ) return decl;
914                        if ( base.as<ast::PointerType>() ) return decl;
915
916                        // If it is not a struct, it's not a mutex.
917                        auto baseStruct = base.as<ast::StructInstType>();
918                        if ( nullptr == baseStruct ) return decl;
919
920                        // If it is a monitor, then it is a monitor.
921                        if( baseStruct->base->is_monitor() || baseStruct->base->is_thread() ) {
922                                SemanticError( decl, "destructors for structures declared as \"monitor\" must use mutex parameters\n" );
923                        }
924                }
925                return decl;
926        }
927
928        // Monitors can't be constructed with mutual exclusion.
929        if ( CodeGen::isConstructor( decl->name ) && is_first_argument_mutex ) {
930                SemanticError( decl, "constructors cannot have mutex parameters\n" );
931        }
932
933        // It makes no sense to have multiple mutex parameters for the destructor.
934        if ( isDtor && mutexArgs.size() != 1 ) {
935                SemanticError( decl, "destructors can only have 1 mutex argument\n" );
936        }
937
938        // Make sure all the mutex arguments are monitors.
939        for ( auto arg : mutexArgs ) {
940                validate( arg );
941        }
942
943        // Check to see if the body needs to be instrument the body.
944        const ast::CompoundStmt * body = decl->stmts;
945        if ( !body ) return decl;
946
947        // Check to if the required headers have been seen.
948        if ( !monitor_decl || !guard_decl || !dtor_guard_decl ) {
949                SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor.hfa>\n" );
950        }
951
952        // Instrument the body.
953        ast::CompoundStmt * newBody = nullptr;
954        if ( isDtor && isThread( mutexArgs.front() ) ) {
955                if ( !thread_guard_decl ) {
956                        SemanticError( decl, "thread destructor requires threads to be in scope, add #include <thread.hfa>\n" );
957                }
958                newBody = addThreadDtorStatements( decl, body, mutexArgs );
959        } else if ( isDtor ) {
960                newBody = addDtorStatements( decl, body, mutexArgs );
961        } else {
962                newBody = addStatements( decl, body, mutexArgs );
963        }
964        assert( newBody );
965        return ast::mutate_field( decl, &ast::FunctionDecl::stmts, newBody );
966}
967
968void MutexKeyword::postvisit( const ast::StructDecl * decl ) {
969        if ( !decl->body ) {
970                return;
971        } else if ( decl->name == "monitor$" ) {
972                assert( !monitor_decl );
973                monitor_decl = decl;
974        } else if ( decl->name == "monitor_guard_t" ) {
975                assert( !guard_decl );
976                guard_decl = decl;
977        } else if ( decl->name == "monitor_dtor_guard_t" ) {
978                assert( !dtor_guard_decl );
979                dtor_guard_decl = decl;
980        } else if ( decl->name == "thread_dtor_guard_t" ) {
981                assert( !thread_guard_decl );
982                thread_guard_decl = decl;
983        } else if ( decl->name == "__mutex_stmt_lock_guard" ) {
984                assert( !lock_guard_decl );
985                lock_guard_decl = decl;
986        }
987}
988
989const ast::Stmt * MutexKeyword::postvisit( const ast::MutexStmt * stmt ) {
990        if ( !lock_guard_decl ) {
991                SemanticError( stmt->location, "mutex stmt requires a header, add #include <mutex_stmt.hfa>\n" );
992        }
993        ast::CompoundStmt * body =
994                        new ast::CompoundStmt( stmt->location, { stmt->stmt } );
995       
996        return addStatements( body, stmt->mutexObjs );;
997}
998
999std::vector<const ast::DeclWithType *> MutexKeyword::findMutexArgs(
1000                const ast::FunctionDecl * decl, bool & first ) {
1001        std::vector<const ast::DeclWithType *> mutexArgs;
1002
1003        bool once = true;
1004        for ( auto arg : decl->params ) {
1005                const ast::Type * type = arg->get_type();
1006                if ( type->is_mutex() ) {
1007                        if ( once ) first = true;
1008                        mutexArgs.push_back( arg.get() );
1009                }
1010                once = false;
1011        }
1012        return mutexArgs;
1013}
1014
1015void MutexKeyword::validate( const ast::DeclWithType * decl ) {
1016        const ast::Type * type = decl->get_type();
1017
1018        // If it's a copy, it's not a mutex.
1019        const ast::ReferenceType * refType = dynamic_cast<const ast::ReferenceType *>( type );
1020        if ( nullptr == refType ) {
1021                SemanticError( decl, "Mutex argument must be of reference type " );
1022        }
1023
1024        // If it is not pointing directly to a type, it's not a mutex.
1025        auto base = refType->base;
1026        if ( base.as<ast::ReferenceType>() || base.as<ast::PointerType>() ) {
1027                SemanticError( decl, "Mutex argument have exactly one level of indirection " );
1028        }
1029
1030        // If it is not a struct, it's not a mutex.
1031        auto baseStruct = base.as<ast::StructInstType>();
1032        if ( nullptr == baseStruct ) return;
1033
1034        // Make sure that only the outer reference is mutex.
1035        if( baseStruct->is_mutex() ) {
1036                SemanticError( decl, "mutex keyword may only appear once per argument " );
1037        }
1038}
1039
1040ast::CompoundStmt * MutexKeyword::addDtorStatements(
1041                const ast::FunctionDecl* func, const ast::CompoundStmt * body,
1042                const std::vector<const ast::DeclWithType *> & args ) {
1043        ast::Type * argType = ast::shallowCopy( args.front()->get_type() );
1044        argType->set_mutex( false );
1045
1046        ast::CompoundStmt * mutBody = ast::mutate( body );
1047
1048        // Generated code goes near the beginning of body:
1049        const CodeLocation & location = mutBody->location;
1050
1051        const ast::ObjectDecl * monitor = new ast::ObjectDecl(
1052                location,
1053                "__monitor",
1054                new ast::PointerType( new ast::StructInstType( monitor_decl ) ),
1055                new ast::SingleInit(
1056                        location,
1057                        new ast::UntypedExpr(
1058                                location,
1059                                new ast::NameExpr( location, "get_monitor" ),
1060                                { new ast::CastExpr(
1061                                        location,
1062                                        new ast::VariableExpr( location, args.front() ),
1063                                        argType, ast::ExplicitCast
1064                                ) }
1065                        )
1066                )
1067        );
1068
1069        assert( generic_func );
1070
1071        // In reverse order:
1072        // monitor_dtor_guard_t __guard = { __monitor, func, false };
1073        mutBody->push_front(
1074                new ast::DeclStmt( location, new ast::ObjectDecl(
1075                        location,
1076                        "__guard",
1077                        new ast::StructInstType( dtor_guard_decl ),
1078                        new ast::ListInit(
1079                                location,
1080                                {
1081                                        new ast::SingleInit( location,
1082                                                new ast::AddressExpr( location,
1083                                                        new ast::VariableExpr( location, monitor ) ) ),
1084                                        new ast::SingleInit( location,
1085                                                new ast::CastExpr( location,
1086                                                        new ast::VariableExpr( location, func ),
1087                                                        generic_func,
1088                                                        ast::ExplicitCast ) ),
1089                                        new ast::SingleInit( location,
1090                                                ast::ConstantExpr::from_bool( location, false ) ),
1091                                },
1092                                {},
1093                                ast::MaybeConstruct
1094                        )
1095                ))
1096        );
1097
1098        // monitor$ * __monitor = get_monitor(a);
1099        mutBody->push_front( new ast::DeclStmt( location, monitor ) );
1100
1101        return mutBody;
1102}
1103
1104ast::CompoundStmt * MutexKeyword::addStatements(
1105                const ast::FunctionDecl* func, const ast::CompoundStmt * body,
1106                const std::vector<const ast::DeclWithType * > & args ) {
1107        ast::CompoundStmt * mutBody = ast::mutate( body );
1108
1109        // Code is generated near the beginning of the compound statement.
1110        const CodeLocation & location = mutBody->location;
1111
1112        // Make pointer to the monitors.
1113        ast::ObjectDecl * monitors = new ast::ObjectDecl(
1114                location,
1115                "__monitors",
1116                new ast::ArrayType(
1117                        new ast::PointerType(
1118                                new ast::StructInstType( monitor_decl )
1119                        ),
1120                        ast::ConstantExpr::from_ulong( location, args.size() ),
1121                        ast::FixedLen,
1122                        ast::DynamicDim
1123                ),
1124                new ast::ListInit(
1125                        location,
1126                        map_range<std::vector<ast::ptr<ast::Init>>>(
1127                                args,
1128                                []( const ast::DeclWithType * decl ) {
1129                                        return new ast::SingleInit(
1130                                                decl->location,
1131                                                new ast::UntypedExpr(
1132                                                        decl->location,
1133                                                        new ast::NameExpr( decl->location, "get_monitor" ),
1134                                                        {
1135                                                                new ast::CastExpr(
1136                                                                        decl->location,
1137                                                                        new ast::VariableExpr( decl->location, decl ),
1138                                                                        decl->get_type(),
1139                                                                        ast::ExplicitCast
1140                                                                )
1141                                                        }
1142                                                )
1143                                        );
1144                                }
1145                        )
1146                )
1147        );
1148
1149        assert( generic_func );
1150
1151        // In Reverse Order:
1152        mutBody->push_front(
1153                new ast::DeclStmt( location, new ast::ObjectDecl(
1154                        location,
1155                        "__guard",
1156                        new ast::StructInstType( guard_decl ),
1157                        new ast::ListInit(
1158                                location,
1159                                {
1160                                        new ast::SingleInit( location,
1161                                                new ast::VariableExpr( location, monitors ) ),
1162                                        new ast::SingleInit( location,
1163                                                ast::ConstantExpr::from_ulong( location, args.size() ) ),
1164                                        new ast::SingleInit( location, new ast::CastExpr(
1165                                                location,
1166                                                new ast::VariableExpr( location, func ),
1167                                                generic_func,
1168                                                ast::ExplicitCast
1169                                        ) ),
1170                                },
1171                                {},
1172                                ast::MaybeConstruct
1173                        )
1174                ))
1175        );
1176
1177        // monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) };
1178        mutBody->push_front( new ast::DeclStmt( location, monitors ) );
1179
1180        return mutBody;
1181}
1182
1183// generates a cast to the void ptr to the appropriate lock type and dereferences it before calling lock or unlock on it
1184// used to undo the type erasure done by storing all the lock pointers as void
1185ast::ExprStmt * MutexKeyword::genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param ) {
1186        return new ast::ExprStmt( location,
1187                new ast::UntypedExpr( location,
1188                        new ast::NameExpr( location, fnName ), {
1189                                ast::UntypedExpr::createDeref(
1190                                        location,
1191                                        new ast::CastExpr( location, 
1192                                                param,
1193                                                new ast::PointerType( new ast::TypeofType( new ast::UntypedExpr(
1194                                                        expr->location,
1195                                                        new ast::NameExpr( expr->location, "__get_mutexstmt_lock_type" ),
1196                                                        { expr }
1197                                                ) ) ),
1198                                                ast::GeneratedFlag::ExplicitCast
1199                                        )
1200                                )
1201                        }
1202                )
1203        );
1204}
1205
1206ast::IfStmt * MutexKeyword::genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam ) {
1207        ast::IfStmt * outerLockIf = nullptr;
1208        ast::IfStmt * lastLockIf = nullptr;
1209
1210        //adds an if/elif clause for each lock to assign type from void ptr based on ptr address
1211        for ( long unsigned int i = 0; i < args.size(); i++ ) {
1212               
1213                ast::UntypedExpr * ifCond = new ast::UntypedExpr( location,
1214                        new ast::NameExpr( location, "?==?" ), {
1215                                ast::deepCopy( thisParam ),
1216                                new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() ))
1217                        }
1218                );
1219
1220                ast::IfStmt * currLockIf = new ast::IfStmt( 
1221                        location,
1222                        ifCond,
1223                        genVirtLockUnlockExpr( fnName, args.at(i), location, ast::deepCopy( thisParam ) )
1224                );
1225               
1226                if ( i == 0 ) {
1227                        outerLockIf = currLockIf;
1228                } else {
1229                        // add ifstmt to else of previous stmt
1230                        lastLockIf->else_ = currLockIf;
1231                }
1232
1233                lastLockIf = currLockIf;
1234        }
1235        return outerLockIf;
1236}
1237
1238ast::CompoundStmt * MutexKeyword::addStatements(
1239                const ast::CompoundStmt * body,
1240                const std::vector<ast::ptr<ast::Expr>> & args ) {
1241
1242        // Code is generated near the beginning of the compound statement.
1243        const CodeLocation & location = body->location;
1244
1245                // final body to return
1246        ast::CompoundStmt * newBody = new ast::CompoundStmt( location );
1247
1248        // std::string lockFnName = mutex_func_namer.newName();
1249        // std::string unlockFnName = mutex_func_namer.newName();
1250
1251        // Make pointer to the monitors.
1252        ast::ObjectDecl * monitors = new ast::ObjectDecl(
1253                location,
1254                "__monitors",
1255                new ast::ArrayType(
1256                        new ast::PointerType(
1257                                new ast::VoidType()
1258                        ),
1259                        ast::ConstantExpr::from_ulong( location, args.size() ),
1260                        ast::FixedLen,
1261                        ast::DynamicDim
1262                ),
1263                new ast::ListInit(
1264                        location,
1265                        map_range<std::vector<ast::ptr<ast::Init>>>(
1266                                args, [](const ast::Expr * expr) {
1267                                        return new ast::SingleInit(
1268                                                expr->location,
1269                                                new ast::UntypedExpr(
1270                                                        expr->location,
1271                                                        new ast::NameExpr( expr->location, "__get_mutexstmt_lock_ptr" ),
1272                                                        { expr }
1273                                                )
1274                                        );
1275                                }
1276                        )
1277                )
1278        );
1279
1280        ast::StructInstType * lock_guard_struct =
1281                        new ast::StructInstType( lock_guard_decl );
1282
1283        // use try stmts to lock and finally to unlock
1284        ast::TryStmt * outerTry = nullptr;
1285        ast::TryStmt * currentTry;
1286        ast::CompoundStmt * lastBody = nullptr;
1287
1288        // adds a nested try stmt for each lock we are locking
1289        for ( long unsigned int i = 0; i < args.size(); i++ ) {
1290                ast::UntypedExpr * innerAccess = new ast::UntypedExpr( 
1291                        location,
1292                        new ast::NameExpr( location,"?[?]" ), {
1293                                new ast::NameExpr( location, "__monitors" ),
1294                                ast::ConstantExpr::from_int( location, i )
1295                        }
1296                );
1297
1298                // make the try body
1299                ast::CompoundStmt * currTryBody = new ast::CompoundStmt( location );
1300                ast::IfStmt * lockCall = genTypeDiscrimLockUnlock( "lock", args, location, innerAccess );
1301                currTryBody->push_back( lockCall );
1302
1303                // make the finally stmt
1304                ast::CompoundStmt * currFinallyBody = new ast::CompoundStmt( location );
1305                ast::IfStmt * unlockCall = genTypeDiscrimLockUnlock( "unlock", args, location, innerAccess );
1306                currFinallyBody->push_back( unlockCall );
1307
1308                // construct the current try
1309                currentTry = new ast::TryStmt(
1310                        location,
1311                        currTryBody,
1312                        {},
1313                        new ast::FinallyClause( location, currFinallyBody )
1314                );
1315                if ( i == 0 ) outerTry = currentTry;
1316                else {
1317                        // pushback try into the body of the outer try
1318                        lastBody->push_back( currentTry );
1319                }
1320                lastBody = currTryBody;
1321        }
1322
1323        // push body into innermost try body
1324        if ( lastBody != nullptr ) {
1325                lastBody->push_back( body );
1326                newBody->push_front( outerTry );
1327        }
1328
1329        // monitor_guard_t __guard = { __monitors, # };
1330        newBody->push_front(
1331                new ast::DeclStmt(
1332                        location,
1333                        new ast::ObjectDecl(
1334                                location,
1335                                "__guard",
1336                                lock_guard_struct,
1337                                new ast::ListInit(
1338                                        location,
1339                                        {
1340                                                new ast::SingleInit(
1341                                                        location,
1342                                                        new ast::VariableExpr( location, monitors ) ),
1343                                                new ast::SingleInit(
1344                                                        location,
1345                                                        ast::ConstantExpr::from_ulong( location, args.size() ) ),
1346                                        },
1347                                        {},
1348                                        ast::MaybeConstruct
1349                                )
1350                        )
1351                )
1352        );
1353
1354        // monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) };
1355        newBody->push_front( new ast::DeclStmt( location, monitors ) );
1356
1357        // // The parameter for both __lock_curr/__unlock_curr routines.
1358        // ast::ObjectDecl * this_decl = new ast::ObjectDecl(
1359        //      location,
1360        //      "this",
1361        //      new ast::PointerType( new ast::VoidType() ),
1362        //      nullptr,
1363        //      {},
1364        //      ast::Linkage::Cforall
1365        // );
1366
1367        // ast::FunctionDecl * lock_decl = new ast::FunctionDecl(
1368        //      location,
1369        //      lockFnName,
1370        //      { /* forall */ },
1371        //      {
1372        //              // Copy the declaration of this.
1373        //              this_decl,
1374        //      },
1375        //      { /* returns */ },
1376        //      nullptr,
1377        //      0,
1378        //      ast::Linkage::Cforall,
1379        //      { /* attributes */ },
1380        //      ast::Function::Inline
1381        // );
1382
1383        // ast::FunctionDecl * unlock_decl = new ast::FunctionDecl(
1384        //      location,
1385        //      unlockFnName,
1386        //      { /* forall */ },
1387        //      {
1388        //              // Copy the declaration of this.
1389        //              ast::deepCopy( this_decl ),
1390        //      },
1391        //      { /* returns */ },
1392        //      nullptr,
1393        //      0,
1394        //      ast::Linkage::Cforall,
1395        //      { /* attributes */ },
1396        //      ast::Function::Inline
1397        // );
1398
1399        // ast::IfStmt * outerLockIf = nullptr;
1400        // ast::IfStmt * outerUnlockIf = nullptr;
1401        // ast::IfStmt * lastLockIf = nullptr;
1402        // ast::IfStmt * lastUnlockIf = nullptr;
1403
1404        // //adds an if/elif clause for each lock to assign type from void ptr based on ptr address
1405        // for ( long unsigned int i = 0; i < args.size(); i++ ) {
1406        //      ast::VariableExpr * thisParam = new ast::VariableExpr( location, InitTweak::getParamThis( lock_decl ) );
1407        //      ast::UntypedExpr * ifCond = new ast::UntypedExpr( location,
1408        //              new ast::NameExpr( location, "?==?" ), {
1409        //                      thisParam,
1410        //                      new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() ))
1411        //              }
1412        //      );
1413
1414        //      ast::IfStmt * currLockIf = new ast::IfStmt(
1415        //              location,
1416        //              ast::deepCopy( ifCond ),
1417        //              genVirtLockUnlockExpr( "lock", args.at(i), location, ast::deepCopy( thisParam ) )
1418        //      );
1419
1420        //      ast::IfStmt * currUnlockIf = new ast::IfStmt(
1421        //              location,
1422        //              ifCond,
1423        //              genVirtLockUnlockExpr( "unlock", args.at(i), location, ast::deepCopy( thisParam ) )
1424        //      );
1425               
1426        //      if ( i == 0 ) {
1427        //              outerLockIf = currLockIf;
1428        //              outerUnlockIf = currUnlockIf;
1429        //      } else {
1430        //              // add ifstmt to else of previous stmt
1431        //              lastLockIf->else_ = currLockIf;
1432        //              lastUnlockIf->else_ = currUnlockIf;
1433        //      }
1434
1435        //      lastLockIf = currLockIf;
1436        //      lastUnlockIf = currUnlockIf;
1437        // }
1438       
1439        // // add pointer typing if/elifs to body of routines
1440        // lock_decl->stmts = new ast::CompoundStmt( location, { outerLockIf } );
1441        // unlock_decl->stmts = new ast::CompoundStmt( location, { outerUnlockIf } );
1442
1443        // // add routines to scope
1444        // declsToAddBefore.push_back( lock_decl );
1445        // declsToAddBefore.push_back( unlock_decl );
1446
1447        // newBody->push_front(new ast::DeclStmt( location, lock_decl ));
1448        // newBody->push_front(new ast::DeclStmt( location, unlock_decl ));
1449
1450        return newBody;
1451}
1452
1453ast::CompoundStmt * MutexKeyword::addThreadDtorStatements(
1454                const ast::FunctionDecl*, const ast::CompoundStmt * body,
1455                const std::vector<const ast::DeclWithType * > & args ) {
1456        assert( args.size() == 1 );
1457        const ast::DeclWithType * arg = args.front();
1458        const ast::Type * argType = arg->get_type();
1459        assert( argType->is_mutex() );
1460
1461        ast::CompoundStmt * mutBody = ast::mutate( body );
1462
1463        // The code is generated near the front of the body.
1464        const CodeLocation & location = mutBody->location;
1465
1466        // thread_dtor_guard_t __guard = { this, intptr( 0 ) };
1467        mutBody->push_front( new ast::DeclStmt(
1468                location,
1469                new ast::ObjectDecl(
1470                        location,
1471                        "__guard",
1472                        new ast::StructInstType( thread_guard_decl ),
1473                        new ast::ListInit(
1474                                location,
1475                                {
1476                                        new ast::SingleInit( location,
1477                                                new ast::CastExpr( location,
1478                                                        new ast::VariableExpr( location, arg ), argType ) ),
1479                                        new ast::SingleInit(
1480                                                location,
1481                                                new ast::UntypedExpr(
1482                                                        location,
1483                                                        new ast::NameExpr( location, "intptr" ), {
1484                                                                ast::ConstantExpr::from_int( location, 0 ),
1485                                                        }
1486                                                ) ),
1487                                },
1488                                {},
1489                                ast::MaybeConstruct
1490                        )
1491                )
1492        ));
1493
1494        return mutBody;
1495}
1496
1497ast::ptr<ast::Type> MutexKeyword::generic_func =
1498        new ast::FunctionType( ast::VariableArgs );
1499
1500// --------------------------------------------------------------------------
1501struct ThreadStarter final {
1502        void previsit( const ast::StructDecl * decl );
1503        const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl );
1504
1505private:
1506        bool thread_ctor_seen = false;
1507        const ast::StructDecl * thread_decl = nullptr;
1508};
1509
1510void ThreadStarter::previsit( const ast::StructDecl * decl ) {
1511        if ( decl->body && decl->name == "thread$" ) {
1512                assert( !thread_decl );
1513                thread_decl = decl;
1514        }
1515}
1516
1517const ast::FunctionDecl * ThreadStarter::postvisit( const ast::FunctionDecl * decl ) {
1518        if ( !CodeGen::isConstructor( decl->name ) ) return decl;
1519
1520        // Seach for the thread constructor.
1521        // (Are the "prefixes" of these to blocks the same?)
1522        const ast::Type * typeof_this = InitTweak::getTypeofThis( decl->type );
1523        auto ctored_type = dynamic_cast<const ast::StructInstType *>( typeof_this );
1524        if ( ctored_type && ctored_type->base == thread_decl ) {
1525                thread_ctor_seen = true;
1526        }
1527
1528        // Modify this declaration, the extra checks to see if we will are first.
1529        const ast::ptr<ast::DeclWithType> & param = decl->params.front();
1530        auto type = dynamic_cast<const ast::StructInstType *>(
1531                ast::getPointerBase( param->get_type() ) );
1532        if ( nullptr == type ) return decl;
1533        if ( !type->base->is_thread() ) return decl;
1534        if ( !thread_decl || !thread_ctor_seen ) {
1535                SemanticError( type->base->location, "thread keyword requires threads to be in scope, add #include <thread.hfa>" );
1536        }
1537        const ast::CompoundStmt * stmt = decl->stmts;
1538        if ( nullptr == stmt ) return decl;
1539
1540        // Now do the actual modification:
1541        ast::CompoundStmt * mutStmt = ast::mutate( stmt );
1542        const CodeLocation & location = mutStmt->location;
1543        mutStmt->push_back(
1544                new ast::ExprStmt(
1545                        location,
1546                        new ast::UntypedExpr(
1547                                location,
1548                                new ast::NameExpr( location, "__thrd_start" ),
1549                                {
1550                                        new ast::VariableExpr( location, param ),
1551                                        new ast::NameExpr( location, "main" ),
1552                                }
1553                        )
1554                )
1555        );
1556
1557        return ast::mutate_field( decl, &ast::FunctionDecl::stmts, mutStmt );
1558}
1559
1560} // namespace
1561
1562// --------------------------------------------------------------------------
1563// Interface Functions:
1564
1565void implementKeywords( ast::TranslationUnit & translationUnit ) {
1566        ast::Pass<ThreadKeyword>::run( translationUnit );
1567        ast::Pass<CoroutineKeyword>::run( translationUnit );
1568        ast::Pass<MonitorKeyword>::run( translationUnit );
1569        ast::Pass<GeneratorKeyword>::run( translationUnit );
1570        ast::Pass<SuspendKeyword>::run( translationUnit );
1571}
1572
1573void implementMutex( ast::TranslationUnit & translationUnit ) {
1574        ast::Pass<MutexKeyword>::run( translationUnit );
1575}
1576
1577void implementThreadStarter( ast::TranslationUnit & translationUnit ) {
1578        ast::Pass<ThreadStarter>::run( translationUnit );
1579}
1580
1581}
1582
1583// Local Variables: //
1584// tab-width: 4 //
1585// mode: c++ //
1586// compile-command: "make install" //
1587// End: //
Note: See TracBrowser for help on using the repository browser.