source: src/Concurrency/KeywordsNew.cpp @ 09f34a84

ADTast-experimentalpthread-emulation
Last change on this file since 09f34a84 was e8616b6, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Changed the default Linkage on ast::ObjectDecl? from C to Cforall. There appears to be only one internal name that actually needed to be C.

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