Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Concurrency/KeywordsNew.cpp

    r41d3c8d r56f519b  
    1010// Created On       : Tue Nov 16  9:53:00 2021
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Mar 11 10:40:00 2022
    13 // Update Count     : 2
     12// Last Modified On : Wed Dec  1 11:24:00 2021
     13// Update Count     : 1
    1414//
    15 
    16 #include <iostream>
    1715
    1816#include "Concurrency/Keywords.h"
     
    2018#include "AST/Copy.hpp"
    2119#include "AST/Decl.hpp"
    22 #include "AST/Expr.hpp"
    2320#include "AST/Pass.hpp"
    2421#include "AST/Stmt.hpp"
    25 #include "AST/DeclReplacer.hpp"
    2622#include "AST/TranslationUnit.hpp"
    2723#include "CodeGen/OperatorTable.h"
    28 #include "Common/Examine.h"
    2924#include "Common/utility.h"
    30 #include "Common/UniqueName.h"
    31 #include "ControlStruct/LabelGeneratorNew.hpp"
    3225#include "InitTweak/InitTweak.h"
    33 #include "Virtual/Tables.h"
    3426
    3527namespace Concurrency {
     
    3729namespace {
    3830
    39 // --------------------------------------------------------------------------
    40 // Loose Helper Functions:
    41 
    42 /// Detect threads constructed with the keyword thread.
    43 bool isThread( const ast::DeclWithType * decl ) {
     31inline static bool isThread( const ast::DeclWithType * decl ) {
    4432        auto baseType = decl->get_type()->stripDeclarator();
    4533        auto instType = dynamic_cast<const ast::StructInstType *>( baseType );
     
    4836}
    4937
    50 /// Get the virtual type id if given a type name.
    51 std::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.
    57 std::string vtableTypeName( std::string const & exception_name ) {
    58         return exception_name.empty() ? std::string()
    59                 : Virtual::vtableTypeName( exception_name );
    60 }
    61 
    62 static 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.
    72 ast::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(
    91                         new ast::TypeInstType( typeDecl->name, 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,
    111                                 new ast::TypeInstType( typeDecl->name, typeDecl ) ) );
    112                 typeParamInst->params.push_back(
    113                         new ast::TypeExpr( location,
    114                                 new ast::TypeInstType( typeDecl->name, typeDecl ) ) );
    115         }
    116 
    117         return mutFunc;
    118 }
    119 
    12038// --------------------------------------------------------------------------
    121 struct ConcurrentSueKeyword : public ast::WithDeclsToAdd<> {
    122         ConcurrentSueKeyword(
    123                 std::string&& type_name, std::string&& field_name,
    124                 std::string&& getter_name, std::string&& context_error,
    125                 std::string&& exception_name,
    126                 bool needs_main, ast::AggregateDecl::Aggregate cast_target
    127         ) :
    128                 type_name( type_name ), field_name( field_name ),
    129                 getter_name( getter_name ), context_error( context_error ),
    130                 exception_name( exception_name ),
    131                 typeid_name( typeIdType( exception_name ) ),
    132                 vtable_name( vtableTypeName( exception_name ) ),
    133                 needs_main( needs_main ), cast_target( cast_target )
    134         {}
    135 
    136         virtual ~ConcurrentSueKeyword() {}
    137 
    138         const ast::Decl * postvisit( const ast::StructDecl * decl );
    139         const ast::DeclWithType * postvisit( const ast::FunctionDecl * decl );
    140         const ast::Expr * postvisit( const ast::KeywordCastExpr * expr );
    141 
    142         struct StructAndField {
    143                 const ast::StructDecl * decl;
    144                 const ast::ObjectDecl * field;
    145         };
    146 
    147         const ast::StructDecl * handleStruct( const ast::StructDecl * );
    148         void handleMain( const ast::FunctionDecl *, const ast::StructInstType * );
    149         void addTypeId( const ast::StructDecl * );
    150         void addVtableForward( const ast::StructDecl * );
    151         const ast::FunctionDecl * forwardDeclare( const ast::StructDecl * );
    152         StructAndField addField( const ast::StructDecl * );
    153         void addGetRoutines( const ast::ObjectDecl *, const ast::FunctionDecl * );
    154         void addLockUnlockRoutines( const ast::StructDecl * );
    155 
    156 private:
    157         const std::string type_name;
    158         const std::string field_name;
    159         const std::string getter_name;
    160         const std::string context_error;
    161         const std::string exception_name;
    162         const std::string typeid_name;
    163         const std::string vtable_name;
    164         const bool needs_main;
    165         const ast::AggregateDecl::Aggregate cast_target;
    166 
    167         const ast::StructDecl   * type_decl = nullptr;
    168         const ast::FunctionDecl * dtor_decl = nullptr;
    169         const ast::StructDecl * except_decl = nullptr;
    170         const ast::StructDecl * typeid_decl = nullptr;
    171         const ast::StructDecl * vtable_decl = nullptr;
    172 
    173 };
    174 
    175 // Handles thread type declarations:
    176 //
    177 // thread Mythread {                         struct MyThread {
    178 //  int data;                                  int data;
    179 //  a_struct_t more_data;                      a_struct_t more_data;
    180 //                                =>             thread$ __thrd_d;
    181 // };                                        };
    182 //                                           static inline thread$ * get_thread( MyThread * this ) { return &this->__thrd_d; }
    183 //
    184 struct ThreadKeyword final : public ConcurrentSueKeyword {
    185         ThreadKeyword() : ConcurrentSueKeyword(
    186                 "thread$",
    187                 "__thrd",
    188                 "get_thread",
    189                 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
    190                 "ThreadCancelled",
    191                 true,
    192                 ast::AggregateDecl::Thread )
    193         {}
    194 
    195         virtual ~ThreadKeyword() {}
    196 };
    197 
    198 // Handles coroutine type declarations:
    199 //
    200 // coroutine MyCoroutine {                   struct MyCoroutine {
    201 //  int data;                                  int data;
    202 //  a_struct_t more_data;                      a_struct_t more_data;
    203 //                                =>             coroutine$ __cor_d;
    204 // };                                        };
    205 //                                           static inline coroutine$ * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
    206 //
    207 struct CoroutineKeyword final : public ConcurrentSueKeyword {
    208         CoroutineKeyword() : ConcurrentSueKeyword(
    209                 "coroutine$",
    210                 "__cor",
    211                 "get_coroutine",
    212                 "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
    213                 "CoroutineCancelled",
    214                 true,
    215                 ast::AggregateDecl::Coroutine )
    216         {}
    217 
    218         virtual ~CoroutineKeyword() {}
    219 };
    220 
    221 // Handles monitor type declarations:
    222 //
    223 // monitor MyMonitor {                       struct MyMonitor {
    224 //  int data;                                  int data;
    225 //  a_struct_t more_data;                      a_struct_t more_data;
    226 //                                =>             monitor$ __mon_d;
    227 // };                                        };
    228 //                                           static inline monitor$ * get_coroutine( MyMonitor * this ) {
    229 //                                               return &this->__cor_d;
    230 //                                           }
    231 //                                           void lock(MyMonitor & this) {
    232 //                                               lock(get_monitor(this));
    233 //                                           }
    234 //                                           void unlock(MyMonitor & this) {
    235 //                                               unlock(get_monitor(this));
    236 //                                           }
    237 //
    238 struct MonitorKeyword final : public ConcurrentSueKeyword {
    239         MonitorKeyword() : ConcurrentSueKeyword(
    240                 "monitor$",
    241                 "__mon",
    242                 "get_monitor",
    243                 "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
    244                 "",
    245                 false,
    246                 ast::AggregateDecl::Monitor )
    247         {}
    248 
    249         virtual ~MonitorKeyword() {}
    250 };
    251 
    252 // Handles generator type declarations:
    253 //
    254 // generator MyGenerator {                   struct MyGenerator {
    255 //  int data;                                  int data;
    256 //  a_struct_t more_data;                      a_struct_t more_data;
    257 //                                =>             int __generator_state;
    258 // };                                        };
    259 //
    260 struct GeneratorKeyword final : public ConcurrentSueKeyword {
    261         GeneratorKeyword() : ConcurrentSueKeyword(
    262                 "generator$",
    263                 "__generator_state",
    264                 "get_generator",
    265                 "Unable to find builtin type generator$\n",
    266                 "",
    267                 true,
    268                 ast::AggregateDecl::Generator )
    269         {}
    270 
    271         virtual ~GeneratorKeyword() {}
    272 };
    273 
    274 const ast::Decl * ConcurrentSueKeyword::postvisit(
    275                 const ast::StructDecl * decl ) {
    276         if ( !decl->body ) {
    277                 return decl;
    278         } else if ( cast_target == decl->kind ) {
    279                 return handleStruct( decl );
    280         } else if ( type_name == decl->name ) {
    281                 assert( !type_decl );
    282                 type_decl = decl;
    283         } else if ( exception_name == decl->name ) {
    284                 assert( !except_decl );
    285                 except_decl = decl;
    286         } else if ( typeid_name == decl->name ) {
    287                 assert( !typeid_decl );
    288                 typeid_decl = decl;
    289         } else if ( vtable_name == decl->name ) {
    290                 assert( !vtable_decl );
    291                 vtable_decl = decl;
    292         }
    293         return decl;
    294 }
    295 
    296 // Try to get the full definition, but raise an error on conflicts.
    297 const ast::FunctionDecl * getDefinition(
    298                 const ast::FunctionDecl * old_decl,
    299                 const ast::FunctionDecl * new_decl ) {
    300         if ( !new_decl->stmts ) {
    301                 return old_decl;
    302         } else if ( !old_decl->stmts ) {
    303                 return new_decl;
    304         } else {
    305                 assert( !old_decl->stmts || !new_decl->stmts );
    306                 return nullptr;
    307         }
    308 }
    309 
    310 const ast::DeclWithType * ConcurrentSueKeyword::postvisit(
    311                 const ast::FunctionDecl * decl ) {
    312         if ( type_decl && isDestructorFor( decl, type_decl ) ) {
    313                 // Check for forward declarations, try to get the full definition.
    314                 dtor_decl = (dtor_decl) ? getDefinition( dtor_decl, decl ) : decl;
    315         } else if ( !vtable_name.empty() && decl->has_body() ) {
    316                 if (const ast::DeclWithType * param = isMainFor( decl, cast_target )) {
    317                         if ( !vtable_decl ) {
    318                                 SemanticError( decl, context_error );
    319                         }
    320                         // Should be safe because of isMainFor.
    321                         const ast::StructInstType * struct_type =
    322                                 static_cast<const ast::StructInstType *>(
    323                                         static_cast<const ast::ReferenceType *>(
    324                                                 param->get_type() )->base.get() );
    325 
    326                         handleMain( decl, struct_type );
    327                 }
    328         }
    329         return decl;
    330 }
    331 
    332 const ast::Expr * ConcurrentSueKeyword::postvisit(
    333                 const ast::KeywordCastExpr * expr ) {
    334         if ( cast_target == expr->target ) {
    335                 // Convert `(thread &)ex` to `(thread$ &)*get_thread(ex)`, etc.
    336                 if ( !type_decl || !dtor_decl ) {
    337                         SemanticError( expr, context_error );
    338                 }
    339                 assert( nullptr == expr->result );
    340                 auto cast = ast::mutate( expr );
    341                 cast->result = new ast::ReferenceType( new ast::StructInstType( type_decl ) );
    342                 cast->concrete_target.field  = field_name;
    343                 cast->concrete_target.getter = getter_name;
    344                 return cast;
    345         }
    346         return expr;
    347 }
    348 
    349 const ast::StructDecl * ConcurrentSueKeyword::handleStruct(
    350                 const ast::StructDecl * decl ) {
    351         assert( decl->body );
    352 
    353         if ( !type_decl || !dtor_decl ) {
    354                 SemanticError( decl, context_error );
    355         }
    356 
    357         if ( !exception_name.empty() ) {
    358                 if( !typeid_decl || !vtable_decl ) {
    359                         SemanticError( decl, context_error );
    360                 }
    361                 addTypeId( decl );
    362                 addVtableForward( decl );
    363         }
    364 
    365         const ast::FunctionDecl * func = forwardDeclare( decl );
    366         StructAndField addFieldRet = addField( decl );
    367         decl = addFieldRet.decl;
    368         const ast::ObjectDecl * field = addFieldRet.field;
    369 
    370         addGetRoutines( field, func );
    371         // Add routines to monitors for use by mutex stmt.
    372         if ( ast::AggregateDecl::Monitor == cast_target ) {
    373                 addLockUnlockRoutines( decl );
    374         }
    375 
    376         return decl;
    377 }
    378 
    379 void ConcurrentSueKeyword::handleMain(
    380                 const ast::FunctionDecl * decl, const ast::StructInstType * type ) {
    381         assert( vtable_decl );
    382         assert( except_decl );
    383 
    384         const CodeLocation & location = decl->location;
    385 
    386         std::vector<ast::ptr<ast::Expr>> poly_args = {
    387                 new ast::TypeExpr( location, type ),
    388         };
    389         ast::ObjectDecl * vtable_object = Virtual::makeVtableInstance(
    390                 location,
    391                 "_default_vtable_object_declaration",
    392                 new ast::StructInstType( vtable_decl, copy( poly_args ) ),
    393                 type,
    394                 nullptr
    395         );
    396         declsToAddAfter.push_back( vtable_object );
    397         declsToAddAfter.push_back(
    398                 new ast::ObjectDecl(
    399                         location,
    400                         Virtual::concurrentDefaultVTableName(),
    401                         new ast::ReferenceType( vtable_object->type, ast::CV::Const ),
    402                         new ast::SingleInit( location,
    403                                 new ast::VariableExpr( location, vtable_object ) ),
    404                         ast::Storage::Classes(),
    405                         ast::Linkage::Cforall
    406                 )
    407         );
    408         declsToAddAfter.push_back( Virtual::makeGetExceptionFunction(
    409                 location,
    410                 vtable_object,
    411                 new ast::StructInstType( except_decl, copy( poly_args ) )
    412         ) );
    413 }
    414 
    415 void ConcurrentSueKeyword::addTypeId( const ast::StructDecl * decl ) {
    416         assert( typeid_decl );
    417         const CodeLocation & location = decl->location;
    418 
    419         ast::StructInstType * typeid_type =
    420                 new ast::StructInstType( typeid_decl, ast::CV::Const );
    421         typeid_type->params.push_back(
    422                 new ast::TypeExpr( location, new ast::StructInstType( decl ) ) );
    423         declsToAddBefore.push_back(
    424                 Virtual::makeTypeIdInstance( location, typeid_type ) );
    425         // If the typeid_type is going to be kept, the other reference will have
    426         // been made by now, but we also get to avoid extra mutates.
    427         ast::ptr<ast::StructInstType> typeid_cleanup = typeid_type;
    428 }
    429 
    430 void ConcurrentSueKeyword::addVtableForward( const ast::StructDecl * decl ) {
    431         assert( vtable_decl );
    432         const CodeLocation& location = decl->location;
    433 
    434         std::vector<ast::ptr<ast::Expr>> poly_args = {
    435                 new ast::TypeExpr( location, new ast::StructInstType( decl ) ),
    436         };
    437         declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
    438                 location,
    439                 new ast::StructInstType( vtable_decl, copy( poly_args ) ),
    440                 new ast::StructInstType( except_decl, copy( poly_args ) )
    441         ) );
    442         ast::ObjectDecl * vtable_object = Virtual::makeVtableForward(
    443                 location,
    444                 "_default_vtable_object_declaration",
    445                 new ast::StructInstType( vtable_decl, std::move( poly_args ) )
    446         );
    447         declsToAddBefore.push_back( vtable_object );
    448         declsToAddBefore.push_back(
    449                 new ast::ObjectDecl(
    450                         location,
    451                         Virtual::concurrentDefaultVTableName(),
    452                         new ast::ReferenceType( vtable_object->type, ast::CV::Const ),
    453                         nullptr,
    454                         ast::Storage::Extern,
    455                         ast::Linkage::Cforall
    456                 )
    457         );
    458 }
    459 
    460 const ast::FunctionDecl * ConcurrentSueKeyword::forwardDeclare(
    461                 const ast::StructDecl * decl ) {
    462         const CodeLocation & location = decl->location;
    463 
    464         ast::StructDecl * forward = ast::deepCopy( decl );
    465         {
    466                 // If removing members makes ref-count go to zero, do not free.
    467                 ast::ptr<ast::StructDecl> forward_ptr = forward;
    468                 forward->body = false;
    469                 forward->members.clear();
    470                 forward_ptr.release();
    471         }
    472 
    473         ast::ObjectDecl * this_decl = new ast::ObjectDecl(
    474                 location,
    475                 "this",
    476                 new ast::ReferenceType( new ast::StructInstType( decl ) ),
    477                 nullptr,
    478                 ast::Storage::Classes(),
    479                 ast::Linkage::Cforall
    480         );
    481 
    482         ast::ObjectDecl * ret_decl = new ast::ObjectDecl(
    483                 location,
    484                 "ret",
    485                 new ast::PointerType( new ast::StructInstType( type_decl ) ),
    486                 nullptr,
    487                 ast::Storage::Classes(),
    488                 ast::Linkage::Cforall
    489         );
    490 
    491         ast::FunctionDecl * get_decl = new ast::FunctionDecl(
    492                 location,
    493                 getter_name,
    494                 {}, // forall
    495                 { this_decl }, // params
    496                 { ret_decl }, // returns
    497                 nullptr, // stmts
    498                 ast::Storage::Static,
    499                 ast::Linkage::Cforall,
    500                 { new ast::Attribute( "const" ) },
    501                 ast::Function::Inline
    502         );
    503         get_decl = fixupGenerics( get_decl, decl );
    504 
    505         ast::FunctionDecl * main_decl = nullptr;
    506         if ( needs_main ) {
    507                 // `this_decl` is copied here because the original was used above.
    508                 main_decl = new ast::FunctionDecl(
    509                         location,
    510                         "main",
    511                         {},
    512                         { ast::deepCopy( this_decl ) },
    513                         {},
    514                         nullptr,
    515                         ast::Storage::Classes(),
    516                         ast::Linkage::Cforall
    517                 );
    518                 main_decl = fixupGenerics( main_decl, decl );
    519         }
    520 
    521         declsToAddBefore.push_back( forward );
    522         if ( needs_main ) declsToAddBefore.push_back( main_decl );
    523         declsToAddBefore.push_back( get_decl );
    524 
    525         return get_decl;
    526 }
    527 
    528 ConcurrentSueKeyword::StructAndField ConcurrentSueKeyword::addField(
    529                 const ast::StructDecl * decl ) {
    530         const CodeLocation & location = decl->location;
    531 
    532         ast::ObjectDecl * field = new ast::ObjectDecl(
    533                 location,
    534                 field_name,
    535                 new ast::StructInstType( type_decl ),
    536                 nullptr,
    537                 ast::Storage::Classes(),
    538                 ast::Linkage::Cforall
    539         );
    540 
    541         auto mutDecl = ast::mutate( decl );
    542         mutDecl->members.push_back( field );
    543 
    544         return {mutDecl, field};
    545 }
    546 
    547 void ConcurrentSueKeyword::addGetRoutines(
    548                 const ast::ObjectDecl * field, const ast::FunctionDecl * forward ) {
    549         // Say it is generated at the "same" places as the forward declaration.
    550         const CodeLocation & location = forward->location;
    551 
    552         const ast::DeclWithType * param = forward->params.front();
    553         ast::Stmt * stmt = new ast::ReturnStmt( location,
    554                 new ast::AddressExpr( location,
    555                         new ast::MemberExpr( location,
    556                                 field,
    557                                 new ast::CastExpr( location,
    558                                         new ast::VariableExpr( location, param ),
    559                                         ast::deepCopy( param->get_type()->stripReferences() ),
    560                                         ast::ExplicitCast
    561                                 )
    562                         )
    563                 )
    564         );
    565 
    566         ast::FunctionDecl * decl = ast::deepCopy( forward );
    567         decl->stmts = new ast::CompoundStmt( location, { stmt } );
    568         declsToAddAfter.push_back( decl );
    569 }
    570 
    571 void ConcurrentSueKeyword::addLockUnlockRoutines(
    572                 const ast::StructDecl * decl ) {
    573         // This should only be used on monitors.
    574         assert( ast::AggregateDecl::Monitor == cast_target );
    575 
    576         const CodeLocation & location = decl->location;
    577 
    578         // The parameter for both routines.
    579         ast::ObjectDecl * this_decl = new ast::ObjectDecl(
    580                 location,
    581                 "this",
    582                 new ast::ReferenceType( new ast::StructInstType( decl ) ),
    583                 nullptr,
    584                 ast::Storage::Classes(),
    585                 ast::Linkage::Cforall
    586         );
    587 
    588         ast::FunctionDecl * lock_decl = new ast::FunctionDecl(
    589                 location,
    590                 "lock",
    591                 { /* forall */ },
    592                 {
    593                         // Copy the declaration of this.
    594                         ast::deepCopy( this_decl ),
    595                 },
    596                 { /* returns */ },
    597                 nullptr,
    598                 ast::Storage::Static,
    599                 ast::Linkage::Cforall,
    600                 { /* attributes */ },
    601                 ast::Function::Inline
    602         );
    603         lock_decl = fixupGenerics( lock_decl, decl );
    604 
    605         lock_decl->stmts = new ast::CompoundStmt( location, {
    606                 new ast::ExprStmt( location,
    607                         new ast::UntypedExpr( location,
    608                                 new ast::NameExpr( location, "lock" ),
    609                                 {
    610                                         new ast::UntypedExpr( location,
    611                                                 new ast::NameExpr( location, "get_monitor" ),
    612                                                 { new ast::VariableExpr( location,
    613                                                         InitTweak::getParamThis( lock_decl ) ) }
    614                                         )
    615                                 }
    616                         )
    617                 )
    618         } );
    619 
    620         ast::FunctionDecl * unlock_decl = new ast::FunctionDecl(
    621                 location,
    622                 "unlock",
    623                 { /* forall */ },
    624                 {
    625                         // Last use, consume the declaration of this.
    626                         this_decl,
    627                 },
    628                 { /* returns */ },
    629                 nullptr,
    630                 ast::Storage::Static,
    631                 ast::Linkage::Cforall,
    632                 { /* attributes */ },
    633                 ast::Function::Inline
    634         );
    635         unlock_decl = fixupGenerics( unlock_decl, decl );
    636 
    637         unlock_decl->stmts = new ast::CompoundStmt( location, {
    638                 new ast::ExprStmt( location,
    639                         new ast::UntypedExpr( location,
    640                                 new ast::NameExpr( location, "unlock" ),
    641                                 {
    642                                         new ast::UntypedExpr( location,
    643                                                 new ast::NameExpr( location, "get_monitor" ),
    644                                                 { new ast::VariableExpr( location,
    645                                                         InitTweak::getParamThis( unlock_decl ) ) }
    646                                         )
    647                                 }
    648                         )
    649                 )
    650         } );
    651 
    652         declsToAddAfter.push_back( lock_decl );
    653         declsToAddAfter.push_back( unlock_decl );
    654 }
    655 
    656 
    657 // --------------------------------------------------------------------------
    658 struct SuspendKeyword final :
    659                 public ast::WithStmtsToAdd<>, public ast::WithGuards {
    660         SuspendKeyword() = default;
    661         virtual ~SuspendKeyword() = default;
    662 
    663         void previsit( const ast::FunctionDecl * );
    664         const ast::DeclWithType * postvisit( const ast::FunctionDecl * );
    665         const ast::Stmt * postvisit( const ast::SuspendStmt * );
    666 
    667 private:
    668         bool is_real_suspend( const ast::FunctionDecl * );
    669 
    670         const ast::Stmt * make_generator_suspend( const ast::SuspendStmt * );
    671         const ast::Stmt * make_coroutine_suspend( const ast::SuspendStmt * );
    672 
    673         struct LabelPair {
    674                 ast::Label obj;
    675                 int idx;
    676         };
    677 
    678         LabelPair make_label(const ast::Stmt * stmt ) {
    679                 labels.push_back( ControlStruct::newLabel( "generator", stmt ) );
    680                 return { labels.back(), int(labels.size()) };
    681         }
    682 
    683         const ast::DeclWithType * in_generator = nullptr;
    684         const ast::FunctionDecl * decl_suspend = nullptr;
    685         std::vector<ast::Label> labels;
    686 };
    687 
    688 void SuspendKeyword::previsit( const ast::FunctionDecl * decl ) {
    689         GuardValue( in_generator ); in_generator = nullptr;
    690 
    691         // If it is the real suspend, grab it if we don't have one already.
    692         if ( is_real_suspend( decl ) ) {
    693                 decl_suspend = decl_suspend ? decl_suspend : decl;
    694                 return;
    695         }
    696 
    697         // Otherwise check if this is a generator main and, if so, handle it.
    698         auto param = isMainFor( decl, ast::AggregateDecl::Generator );
    699         if ( !param ) return;
    700 
    701         if ( 0 != decl->returns.size() ) {
    702                 SemanticError( decl->location, "Generator main must return void" );
    703         }
    704 
    705         in_generator = param;
    706         GuardValue( labels ); labels.clear();
    707 }
    708 
    709 const ast::DeclWithType * SuspendKeyword::postvisit(
    710                 const ast::FunctionDecl * decl ) {
    711         // Only modify a full definition of a generator with states.
    712         if ( !decl->stmts || !in_generator || labels.empty() ) return decl;
    713 
    714         const CodeLocation & location = decl->location;
    715 
    716         // Create a new function body:
    717         // static void * __generator_labels[] = {&&s0, &&s1, ...};
    718         // void * __generator_label = __generator_labels[GEN.__generator_state];
    719         // goto * __generator_label;
    720         // s0: ;
    721         // OLD_BODY
    722 
    723         // This is the null statement inserted right before the body.
    724         ast::NullStmt * noop = new ast::NullStmt( location );
    725         noop->labels.push_back( ControlStruct::newLabel( "generator", noop ) );
    726         const ast::Label & first_label = noop->labels.back();
    727 
    728         // Add each label to the init, starting with the first label.
    729         std::vector<ast::ptr<ast::Init>> inits = {
    730                 new ast::SingleInit( location,
    731                         new ast::LabelAddressExpr( location, copy( first_label ) ) ) };
    732         // Then go through all the stored labels, and clear the store.
    733         for ( auto && label : labels ) {
    734                 inits.push_back( new ast::SingleInit( label.location,
    735                         new ast::LabelAddressExpr( label.location, std::move( label )
    736                         ) ) );
    737         }
    738         labels.clear();
    739         // Then construct the initializer itself.
    740         auto init = new ast::ListInit( location, std::move( inits ) );
    741 
    742         ast::ObjectDecl * generatorLabels = new ast::ObjectDecl(
    743                 location,
    744                 "__generator_labels",
    745                 new ast::ArrayType(
    746                         new ast::PointerType( new ast::VoidType() ),
    747                         nullptr,
    748                         ast::FixedLen,
    749                         ast::DynamicDim
    750                 ),
    751                 init,
    752                 ast::Storage::Classes(),
    753                 ast::Linkage::AutoGen
    754         );
    755 
    756         ast::ObjectDecl * generatorLabel = new ast::ObjectDecl(
    757                 location,
    758                 "__generator_label",
    759                 new ast::PointerType( new ast::VoidType() ),
    760                 new ast::SingleInit( location,
    761                         new ast::UntypedExpr( location,
    762                                 new ast::NameExpr( location, "?[?]" ),
    763                                 {
    764                                         // TODO: Could be a variable expr.
    765                                         new ast::NameExpr( location, "__generator_labels" ),
    766                                         new ast::UntypedMemberExpr( location,
    767                                                 new ast::NameExpr( location, "__generator_state" ),
    768                                                 new ast::VariableExpr( location, in_generator )
    769                                         )
    770                                 }
    771                         )
    772                 ),
    773                 ast::Storage::Classes(),
    774                 ast::Linkage::AutoGen
    775         );
    776 
    777         ast::BranchStmt * theGoTo = new ast::BranchStmt(
    778                 location, new ast::VariableExpr( location, generatorLabel )
    779         );
    780 
    781         // The noop goes here in order.
    782 
    783         ast::CompoundStmt * body = new ast::CompoundStmt( location, {
    784                 { new ast::DeclStmt( location, generatorLabels ) },
    785                 { new ast::DeclStmt( location, generatorLabel ) },
    786                 { theGoTo },
    787                 { noop },
    788                 { decl->stmts },
    789         } );
    790 
    791         auto mutDecl = ast::mutate( decl );
    792         mutDecl->stmts = body;
    793         return mutDecl;
    794 }
    795 
    796 const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) {
    797         switch ( stmt->type ) {
    798         case ast::SuspendStmt::None:
    799                 // Use the context to determain the implicit target.
    800                 if ( in_generator ) {
    801                         return make_generator_suspend( stmt );
    802                 } else {
    803                         return make_coroutine_suspend( stmt );
    804                 }
    805         case ast::SuspendStmt::Coroutine:
    806                 return make_coroutine_suspend( stmt );
    807         case ast::SuspendStmt::Generator:
    808                 // Generator suspends must be directly in a generator.
    809                 if ( !in_generator ) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type." );
    810                 return make_generator_suspend( stmt );
    811         }
    812         assert( false );
    813         return stmt;
    814 }
    815 
    816 /// Find the real/official suspend declaration.
    817 bool SuspendKeyword::is_real_suspend( const ast::FunctionDecl * decl ) {
    818         return ( !decl->linkage.is_mangled
    819                 && 0 == decl->params.size()
    820                 && 0 == decl->returns.size()
    821                 && "__cfactx_suspend" == decl->name );
    822 }
    823 
    824 const ast::Stmt * SuspendKeyword::make_generator_suspend(
    825                 const ast::SuspendStmt * stmt ) {
    826         assert( in_generator );
    827         // Target code is:
    828         //   GEN.__generator_state = X;
    829         //   THEN
    830         //   return;
    831         //   __gen_X:;
    832 
    833         const CodeLocation & location = stmt->location;
    834 
    835         LabelPair label = make_label( stmt );
    836 
    837         // This is the context saving statement.
    838         stmtsToAddBefore.push_back( new ast::ExprStmt( location,
    839                 new ast::UntypedExpr( location,
    840                         new ast::NameExpr( location, "?=?" ),
    841                         {
    842                                 new ast::UntypedMemberExpr( location,
    843                                         new ast::NameExpr( location, "__generator_state" ),
    844                                         new ast::VariableExpr( location, in_generator )
    845                                 ),
    846                                 ast::ConstantExpr::from_int( location, label.idx ),
    847                         }
    848                 )
    849         ) );
    850 
    851         // The THEN component is conditional (return is not).
    852         if ( stmt->then ) {
    853                 stmtsToAddBefore.push_back( stmt->then.get() );
    854         }
    855         stmtsToAddBefore.push_back( new ast::ReturnStmt( location, nullptr ) );
    856 
    857         // The null statement replaces the old suspend statement.
    858         return new ast::NullStmt( location, { label.obj } );
    859 }
    860 
    861 const ast::Stmt * SuspendKeyword::make_coroutine_suspend(
    862                 const ast::SuspendStmt * stmt ) {
    863         // The only thing we need from the old statement is the location.
    864         const CodeLocation & location = stmt->location;
    865 
    866         if ( !decl_suspend ) {
    867                 SemanticError( location, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n" );
    868         }
    869         if ( stmt->then ) {
    870                 SemanticError( location, "Compound statement following coroutines is not implemented." );
    871         }
    872 
    873         return new ast::ExprStmt( location,
    874                 new ast::UntypedExpr( location,
    875                         ast::VariableExpr::functionPointer( location, decl_suspend ) )
    876         );
    877 }
    878 
    879 // --------------------------------------------------------------------------
    880 struct MutexKeyword final : public ast::WithDeclsToAdd<> {
     39struct MutexKeyword final {
    88140        const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl );
    88241        void postvisit( const ast::StructDecl * decl );
     
    89150        ast::CompoundStmt * addStatements( const ast::CompoundStmt * body, const std::vector<ast::ptr<ast::Expr>> & args );
    89251        ast::CompoundStmt * addThreadDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt * body, const std::vector<const ast::DeclWithType *> & args );
    893         ast::ExprStmt * genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param);
    894         ast::IfStmt * genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam );
     52
    89553private:
    89654        const ast::StructDecl * monitor_decl = nullptr;
     
    90159
    90260        static ast::ptr<ast::Type> generic_func;
    903 
    904         UniqueName mutex_func_namer = UniqueName("__lock_unlock_curr");
    90561};
    90662
     
    1004160
    1005161const ast::Stmt * MutexKeyword::postvisit( const ast::MutexStmt * stmt ) {
    1006         if ( !lock_guard_decl ) {
    1007                 SemanticError( stmt->location, "mutex stmt requires a header, add #include <mutex_stmt.hfa>\n" );
    1008         }
    1009162        ast::CompoundStmt * body =
    1010163                        new ast::CompoundStmt( stmt->location, { stmt->stmt } );
    1011        
    1012         return addStatements( body, stmt->mutexObjs );;
     164        addStatements( body, stmt->mutexObjs );
     165        return body;
    1013166}
    1014167
     
    1098251                                {
    1099252                                        new ast::SingleInit( location,
    1100                                                 new ast::AddressExpr( location,
     253                                                new ast::AddressExpr(
    1101254                                                        new ast::VariableExpr( location, monitor ) ) ),
    1102255                                        new ast::SingleInit( location,
     
    1205358}
    1206359
    1207 // generates a cast to the void ptr to the appropriate lock type and dereferences it before calling lock or unlock on it
    1208 // used to undo the type erasure done by storing all the lock pointers as void
    1209 ast::ExprStmt * MutexKeyword::genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param ) {
    1210         return new ast::ExprStmt( location,
    1211                 new ast::UntypedExpr( location,
    1212                         new ast::NameExpr( location, fnName ), {
    1213                                 ast::UntypedExpr::createDeref(
    1214                                         location,
    1215                                         new ast::CastExpr( location,
    1216                                                 param,
    1217                                                 new ast::PointerType( new ast::TypeofType( new ast::UntypedExpr(
    1218                                                         expr->location,
    1219                                                         new ast::NameExpr( expr->location, "__get_mutexstmt_lock_type" ),
    1220                                                         { expr }
    1221                                                 ) ) ),
    1222                                                 ast::GeneratedFlag::ExplicitCast
    1223                                         )
    1224                                 )
    1225                         }
    1226                 )
    1227         );
    1228 }
    1229 
    1230 ast::IfStmt * MutexKeyword::genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam ) {
    1231         ast::IfStmt * outerLockIf = nullptr;
    1232         ast::IfStmt * lastLockIf = nullptr;
    1233 
    1234         //adds an if/elif clause for each lock to assign type from void ptr based on ptr address
    1235         for ( long unsigned int i = 0; i < args.size(); i++ ) {
    1236                
    1237                 ast::UntypedExpr * ifCond = new ast::UntypedExpr( location,
    1238                         new ast::NameExpr( location, "?==?" ), {
    1239                                 ast::deepCopy( thisParam ),
    1240                                 new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() ))
    1241                         }
    1242                 );
    1243 
    1244                 ast::IfStmt * currLockIf = new ast::IfStmt(
    1245                         location,
    1246                         ifCond,
    1247                         genVirtLockUnlockExpr( fnName, args.at(i), location, ast::deepCopy( thisParam ) )
    1248                 );
    1249                
    1250                 if ( i == 0 ) {
    1251                         outerLockIf = currLockIf;
    1252                 } else {
    1253                         // add ifstmt to else of previous stmt
    1254                         lastLockIf->else_ = currLockIf;
    1255                 }
    1256 
    1257                 lastLockIf = currLockIf;
    1258         }
    1259         return outerLockIf;
    1260 }
    1261 
    1262360ast::CompoundStmt * MutexKeyword::addStatements(
    1263361                const ast::CompoundStmt * body,
    1264362                const std::vector<ast::ptr<ast::Expr>> & args ) {
     363        ast::CompoundStmt * mutBody = ast::mutate( body );
    1265364
    1266365        // Code is generated near the beginning of the compound statement.
    1267         const CodeLocation & location = body->location;
    1268 
    1269                 // final body to return
    1270         ast::CompoundStmt * newBody = new ast::CompoundStmt( location );
    1271 
    1272         // std::string lockFnName = mutex_func_namer.newName();
    1273         // std::string unlockFnName = mutex_func_namer.newName();
     366        const CodeLocation & location = mutBody->location;
    1274367
    1275368        // Make pointer to the monitors.
     
    1279372                new ast::ArrayType(
    1280373                        new ast::PointerType(
    1281                                 new ast::VoidType()
     374                                new ast::TypeofType(
     375                                        new ast::UntypedExpr(
     376                                                location,
     377                                                new ast::NameExpr( location, "__get_type" ),
     378                                                { args.front() }
     379                                        )
     380                                )
    1282381                        ),
    1283382                        ast::ConstantExpr::from_ulong( location, args.size() ),
     
    1293392                                                new ast::UntypedExpr(
    1294393                                                        expr->location,
    1295                                                         new ast::NameExpr( expr->location, "__get_mutexstmt_lock_ptr" ),
     394                                                        new ast::NameExpr( expr->location, "__get_ptr" ),
    1296395                                                        { expr }
    1297396                                                )
     
    1306405        ast::StructInstType * lock_guard_struct =
    1307406                        new ast::StructInstType( lock_guard_decl );
    1308 
    1309         // use try stmts to lock and finally to unlock
    1310         ast::TryStmt * outerTry = nullptr;
    1311         ast::TryStmt * currentTry;
    1312         ast::CompoundStmt * lastBody = nullptr;
    1313 
    1314         // adds a nested try stmt for each lock we are locking
    1315         for ( long unsigned int i = 0; i < args.size(); i++ ) {
    1316                 ast::UntypedExpr * innerAccess = new ast::UntypedExpr(
    1317                         location,
    1318                         new ast::NameExpr( location,"?[?]" ), {
    1319                                 new ast::NameExpr( location, "__monitors" ),
    1320                                 ast::ConstantExpr::from_int( location, i )
    1321                         }
    1322                 );
    1323 
    1324                 // make the try body
    1325                 ast::CompoundStmt * currTryBody = new ast::CompoundStmt( location );
    1326                 ast::IfStmt * lockCall = genTypeDiscrimLockUnlock( "lock", args, location, innerAccess );
    1327                 currTryBody->push_back( lockCall );
    1328 
    1329                 // make the finally stmt
    1330                 ast::CompoundStmt * currFinallyBody = new ast::CompoundStmt( location );
    1331                 ast::IfStmt * unlockCall = genTypeDiscrimLockUnlock( "unlock", args, location, innerAccess );
    1332                 currFinallyBody->push_back( unlockCall );
    1333 
    1334                 // construct the current try
    1335                 currentTry = new ast::TryStmt(
    1336                         location,
    1337                         currTryBody,
    1338                         {},
    1339                         new ast::FinallyStmt( location, currFinallyBody )
    1340                 );
    1341                 if ( i == 0 ) outerTry = currentTry;
    1342                 else {
    1343                         // pushback try into the body of the outer try
    1344                         lastBody->push_back( currentTry );
    1345                 }
    1346                 lastBody = currTryBody;
    1347         }
    1348 
    1349         // push body into innermost try body
    1350         if ( lastBody != nullptr ) {
    1351                 lastBody->push_back( body );
    1352                 newBody->push_front( outerTry );
    1353         }       
    1354 
     407        ast::TypeExpr * lock_type_expr = new ast::TypeExpr(
     408                location,
     409                new ast::TypeofType(
     410                        new ast::UntypedExpr(
     411                                location,
     412                                new ast::NameExpr( location, "__get_type" ),
     413                                { args.front() }
     414                        )
     415                )
     416        );
     417
     418        lock_guard_struct->params.push_back( lock_type_expr );
     419
     420        // In reverse order:
    1355421        // monitor_guard_t __guard = { __monitors, # };
    1356         newBody->push_front(
     422        mutBody->push_front(
    1357423                new ast::DeclStmt(
    1358424                        location,
     
    1381447
    1382448        // monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) };
    1383         newBody->push_front( new ast::DeclStmt( location, monitors ) );
    1384 
    1385         // // The parameter for both __lock_curr/__unlock_curr routines.
    1386         // ast::ObjectDecl * this_decl = new ast::ObjectDecl(
    1387         //      location,
    1388         //      "this",
    1389         //      new ast::PointerType( new ast::VoidType() ),
    1390         //      nullptr,
    1391         //      {},
    1392         //      ast::Linkage::Cforall
    1393         // );
    1394 
    1395         // ast::FunctionDecl * lock_decl = new ast::FunctionDecl(
    1396         //      location,
    1397         //      lockFnName,
    1398         //      { /* forall */ },
    1399         //      {
    1400         //              // Copy the declaration of this.
    1401         //              this_decl,
    1402         //      },
    1403         //      { /* returns */ },
    1404         //      nullptr,
    1405         //      0,
    1406         //      ast::Linkage::Cforall,
    1407         //      { /* attributes */ },
    1408         //      ast::Function::Inline
    1409         // );
    1410 
    1411         // ast::FunctionDecl * unlock_decl = new ast::FunctionDecl(
    1412         //      location,
    1413         //      unlockFnName,
    1414         //      { /* forall */ },
    1415         //      {
    1416         //              // Copy the declaration of this.
    1417         //              ast::deepCopy( this_decl ),
    1418         //      },
    1419         //      { /* returns */ },
    1420         //      nullptr,
    1421         //      0,
    1422         //      ast::Linkage::Cforall,
    1423         //      { /* attributes */ },
    1424         //      ast::Function::Inline
    1425         // );
    1426 
    1427         // ast::IfStmt * outerLockIf = nullptr;
    1428         // ast::IfStmt * outerUnlockIf = nullptr;
    1429         // ast::IfStmt * lastLockIf = nullptr;
    1430         // ast::IfStmt * lastUnlockIf = nullptr;
    1431 
    1432         // //adds an if/elif clause for each lock to assign type from void ptr based on ptr address
    1433         // for ( long unsigned int i = 0; i < args.size(); i++ ) {
    1434         //      ast::VariableExpr * thisParam = new ast::VariableExpr( location, InitTweak::getParamThis( lock_decl ) );
    1435         //      ast::UntypedExpr * ifCond = new ast::UntypedExpr( location,
    1436         //              new ast::NameExpr( location, "?==?" ), {
    1437         //                      thisParam,
    1438         //                      new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() ))
    1439         //              }
    1440         //      );
    1441 
    1442         //      ast::IfStmt * currLockIf = new ast::IfStmt(
    1443         //              location,
    1444         //              ast::deepCopy( ifCond ),
    1445         //              genVirtLockUnlockExpr( "lock", args.at(i), location, ast::deepCopy( thisParam ) )
    1446         //      );
    1447 
    1448         //      ast::IfStmt * currUnlockIf = new ast::IfStmt(
    1449         //              location,
    1450         //              ifCond,
    1451         //              genVirtLockUnlockExpr( "unlock", args.at(i), location, ast::deepCopy( thisParam ) )
    1452         //      );
    1453                
    1454         //      if ( i == 0 ) {
    1455         //              outerLockIf = currLockIf;
    1456         //              outerUnlockIf = currUnlockIf;
    1457         //      } else {
    1458         //              // add ifstmt to else of previous stmt
    1459         //              lastLockIf->else_ = currLockIf;
    1460         //              lastUnlockIf->else_ = currUnlockIf;
    1461         //      }
    1462 
    1463         //      lastLockIf = currLockIf;
    1464         //      lastUnlockIf = currUnlockIf;
    1465         // }
    1466        
    1467         // // add pointer typing if/elifs to body of routines
    1468         // lock_decl->stmts = new ast::CompoundStmt( location, { outerLockIf } );
    1469         // unlock_decl->stmts = new ast::CompoundStmt( location, { outerUnlockIf } );
    1470 
    1471         // // add routines to scope
    1472         // declsToAddBefore.push_back( lock_decl );
    1473         // declsToAddBefore.push_back( unlock_decl );
    1474 
    1475         // newBody->push_front(new ast::DeclStmt( location, lock_decl ));
    1476         // newBody->push_front(new ast::DeclStmt( location, unlock_decl ));
    1477 
    1478         return newBody;
     449        mutBody->push_front( new ast::DeclStmt( location, monitors ) );
     450
     451        return mutBody;
    1479452}
    1480453
     
    1591564
    1592565// --------------------------------------------------------------------------
    1593 // Interface Functions:
    1594566
    1595567void implementKeywords( ast::TranslationUnit & translationUnit ) {
    1596         ast::Pass<ThreadKeyword>::run( translationUnit );
    1597         ast::Pass<CoroutineKeyword>::run( translationUnit );
    1598         ast::Pass<MonitorKeyword>::run( translationUnit );
    1599         ast::Pass<GeneratorKeyword>::run( translationUnit );
    1600         ast::Pass<SuspendKeyword>::run( translationUnit );
     568        (void)translationUnit;
     569        assertf(false, "Apply Keywords not implemented." );
    1601570}
    1602571
Note: See TracChangeset for help on using the changeset viewer.