Changeset 4f6dda0 for src/Concurrency
- Timestamp:
- Mar 11, 2022, 11:08:19 AM (3 years ago)
- Branches:
- ADT, ast-experimental, enum, master, pthread-emulation, qualifiedEnum
- Children:
- 630c4bb
- Parents:
- b053083
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Concurrency/KeywordsNew.cpp
rb053083 r4f6dda0 10 10 // Created On : Tue Nov 16 9:53:00 2021 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Dec 1 11:24:00 202113 // Update Count : 112 // Last Modified On : Fri Mar 11 10:40:00 2022 13 // Update Count : 2 14 14 // 15 15 … … 18 18 #include "AST/Copy.hpp" 19 19 #include "AST/Decl.hpp" 20 #include "AST/Expr.hpp" 20 21 #include "AST/Pass.hpp" 21 22 #include "AST/Stmt.hpp" 23 #include "AST/DeclReplacer.hpp" 22 24 #include "AST/TranslationUnit.hpp" 23 25 #include "CodeGen/OperatorTable.h" 26 #include "Common/Examine.h" 24 27 #include "Common/utility.h" 28 #include "ControlStruct/LabelGeneratorNew.hpp" 25 29 #include "InitTweak/InitTweak.h" 30 #include "Virtual/Tables.h" 26 31 27 32 namespace Concurrency { … … 29 34 namespace { 30 35 31 inline static bool isThread( const ast::DeclWithType * decl ) { 36 // -------------------------------------------------------------------------- 37 // Loose Helper Functions: 38 39 /// Detect threads constructed with the keyword thread. 40 bool isThread( const ast::DeclWithType * decl ) { 32 41 auto baseType = decl->get_type()->stripDeclarator(); 33 42 auto instType = dynamic_cast<const ast::StructInstType *>( baseType ); 34 43 if ( nullptr == instType ) { return false; } 35 44 return instType->base->is_thread(); 45 } 46 47 /// Get the virtual type id if given a type name. 48 std::string typeIdType( std::string const & exception_name ) { 49 return exception_name.empty() ? std::string() 50 : Virtual::typeIdType( exception_name ); 51 } 52 53 /// Get the vtable type name if given a type name. 54 std::string vtableTypeName( std::string const & exception_name ) { 55 return exception_name.empty() ? std::string() 56 : Virtual::vtableTypeName( exception_name ); 57 } 58 59 static ast::Type * mutate_under_references( ast::ptr<ast::Type>& type ) { 60 ast::Type * mutType = type.get_and_mutate(); 61 for ( ast::ReferenceType * mutRef 62 ; (mutRef = dynamic_cast<ast::ReferenceType *>( mutType )) 63 ; mutType = mutRef->base.get_and_mutate() ); 64 return mutType; 65 } 66 67 // Describe that it adds the generic parameters and the uses of the generic 68 // parameters on the function and first "this" argument. 69 ast::FunctionDecl * fixupGenerics( 70 const ast::FunctionDecl * func, const ast::StructDecl * decl ) { 71 const CodeLocation & location = decl->location; 72 // We have to update both the declaration 73 auto mutFunc = ast::mutate( func ); 74 auto mutType = mutFunc->type.get_and_mutate(); 75 76 if ( decl->params.empty() ) { 77 return mutFunc; 78 } 79 80 assert( 0 != mutFunc->params.size() ); 81 assert( 0 != mutType->params.size() ); 82 83 // Add the "forall" clause information. 84 for ( const ast::ptr<ast::TypeDecl> & typeParam : decl->params ) { 85 auto typeDecl = ast::deepCopy( typeParam ); 86 mutFunc->type_params.push_back( typeDecl ); 87 mutType->forall.push_back( 88 new ast::TypeInstType( typeDecl->name, typeDecl ) ); 89 for ( auto & assertion : typeDecl->assertions ) { 90 mutFunc->assertions.push_back( assertion ); 91 mutType->assertions.emplace_back( 92 new ast::VariableExpr( location, assertion ) ); 93 } 94 typeDecl->assertions.clear(); 95 } 96 97 // Even chain_mutate is not powerful enough for this: 98 ast::ptr<ast::Type>& paramType = strict_dynamic_cast<ast::ObjectDecl *>( 99 mutFunc->params[0].get_and_mutate() )->type; 100 auto paramTypeInst = strict_dynamic_cast<ast::StructInstType *>( 101 mutate_under_references( paramType ) ); 102 auto typeParamInst = strict_dynamic_cast<ast::StructInstType *>( 103 mutate_under_references( mutType->params[0] ) ); 104 105 for ( const ast::ptr<ast::TypeDecl> & typeDecl : mutFunc->type_params ) { 106 paramTypeInst->params.push_back( 107 new ast::TypeExpr( location, 108 new ast::TypeInstType( typeDecl->name, typeDecl ) ) ); 109 typeParamInst->params.push_back( 110 new ast::TypeExpr( location, 111 new ast::TypeInstType( typeDecl->name, typeDecl ) ) ); 112 } 113 114 return mutFunc; 115 } 116 117 // -------------------------------------------------------------------------- 118 struct 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 153 private: 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 // Handles thread type declarations: 172 // 173 // thread Mythread { struct MyThread { 174 // int data; int data; 175 // a_struct_t more_data; a_struct_t more_data; 176 // => thread$ __thrd_d; 177 // }; }; 178 // static inline thread$ * get_thread( MyThread * this ) { return &this->__thrd_d; } 179 // 180 struct ThreadKeyword final : public ConcurrentSueKeyword { 181 ThreadKeyword() : ConcurrentSueKeyword( 182 "thread$", 183 "__thrd", 184 "get_thread", 185 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n", 186 "ThreadCancelled", 187 true, 188 ast::AggregateDecl::Thread ) 189 {} 190 191 virtual ~ThreadKeyword() {} 192 }; 193 194 // Handles coroutine type declarations: 195 // 196 // coroutine MyCoroutine { struct MyCoroutine { 197 // int data; int data; 198 // a_struct_t more_data; a_struct_t more_data; 199 // => coroutine$ __cor_d; 200 // }; }; 201 // static inline coroutine$ * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; } 202 // 203 struct CoroutineKeyword final : public ConcurrentSueKeyword { 204 CoroutineKeyword() : ConcurrentSueKeyword( 205 "coroutine$", 206 "__cor", 207 "get_coroutine", 208 "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n", 209 "CoroutineCancelled", 210 true, 211 ast::AggregateDecl::Coroutine ) 212 {} 213 214 virtual ~CoroutineKeyword() {} 215 }; 216 217 // Handles monitor type declarations: 218 // 219 // monitor MyMonitor { struct MyMonitor { 220 // int data; int data; 221 // a_struct_t more_data; a_struct_t more_data; 222 // => monitor$ __mon_d; 223 // }; }; 224 // static inline monitor$ * get_coroutine( MyMonitor * this ) { 225 // return &this->__cor_d; 226 // } 227 // void lock(MyMonitor & this) { 228 // lock(get_monitor(this)); 229 // } 230 // void unlock(MyMonitor & this) { 231 // unlock(get_monitor(this)); 232 // } 233 // 234 struct MonitorKeyword final : public ConcurrentSueKeyword { 235 MonitorKeyword() : ConcurrentSueKeyword( 236 "monitor$", 237 "__mon", 238 "get_monitor", 239 "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n", 240 "", 241 false, 242 ast::AggregateDecl::Monitor ) 243 {} 244 245 virtual ~MonitorKeyword() {} 246 }; 247 248 // Handles generator type declarations: 249 // 250 // generator MyGenerator { struct MyGenerator { 251 // int data; int data; 252 // a_struct_t more_data; a_struct_t more_data; 253 // => int __generator_state; 254 // }; }; 255 // 256 struct GeneratorKeyword final : public ConcurrentSueKeyword { 257 GeneratorKeyword() : ConcurrentSueKeyword( 258 "generator$", 259 "__generator_state", 260 "get_generator", 261 "Unable to find builtin type generator$\n", 262 "", 263 true, 264 ast::AggregateDecl::Generator ) 265 {} 266 267 virtual ~GeneratorKeyword() {} 268 }; 269 270 const ast::Decl * ConcurrentSueKeyword::postvisit( 271 const ast::StructDecl * decl ) { 272 if ( !decl->body ) { 273 return decl; 274 } else if ( cast_target == decl->kind ) { 275 return handleStruct( decl ); 276 } else if ( type_name == decl->name ) { 277 assert( !type_decl ); 278 type_decl = decl; 279 } else if ( exception_name == decl->name ) { 280 assert( !except_decl ); 281 except_decl = decl; 282 } else if ( typeid_name == decl->name ) { 283 assert( !typeid_decl ); 284 typeid_decl = decl; 285 } else if ( vtable_name == decl->name ) { 286 assert( !vtable_decl ); 287 vtable_decl = decl; 288 } 289 return decl; 290 } 291 292 // Try to get the full definition, but raise an error on conflicts. 293 const ast::FunctionDecl * getDefinition( 294 const ast::FunctionDecl * old_decl, 295 const ast::FunctionDecl * new_decl ) { 296 if ( !new_decl->stmts ) { 297 return old_decl; 298 } else if ( !old_decl->stmts ) { 299 return new_decl; 300 } else { 301 assert( !old_decl->stmts || !new_decl->stmts ); 302 return nullptr; 303 } 304 } 305 306 const ast::DeclWithType * ConcurrentSueKeyword::postvisit( 307 const ast::FunctionDecl * decl ) { 308 if ( type_decl && isDestructorFor( decl, type_decl ) ) { 309 // Check for forward declarations, try to get the full definition. 310 dtor_decl = (dtor_decl) ? getDefinition( dtor_decl, decl ) : decl; 311 } else if ( !vtable_name.empty() && decl->has_body() ) { 312 if (const ast::DeclWithType * param = isMainFor( decl, cast_target )) { 313 if ( !vtable_decl ) { 314 SemanticError( decl, context_error ); 315 } 316 // Should be safe because of isMainFor. 317 const ast::StructInstType * struct_type = 318 static_cast<const ast::StructInstType *>( 319 static_cast<const ast::ReferenceType *>( 320 param->get_type() )->base.get() ); 321 322 handleMain( decl, struct_type ); 323 } 324 } 325 return decl; 326 } 327 328 const ast::Expr * ConcurrentSueKeyword::postvisit( 329 const ast::KeywordCastExpr * expr ) { 330 if ( cast_target == expr->target ) { 331 // Convert `(thread &)ex` to `(thread$ &)*get_thread(ex)`, etc. 332 if ( !type_decl || !dtor_decl ) { 333 SemanticError( expr, context_error ); 334 } 335 assert( nullptr == expr->result ); 336 auto cast = ast::mutate( expr ); 337 cast->result = new ast::ReferenceType( new ast::StructInstType( type_decl ) ); 338 cast->concrete_target.field = field_name; 339 cast->concrete_target.getter = getter_name; 340 return cast; 341 } 342 return expr; 343 } 344 345 const ast::StructDecl * ConcurrentSueKeyword::handleStruct( 346 const ast::StructDecl * decl ) { 347 assert( decl->body ); 348 349 if ( !type_decl || !dtor_decl ) { 350 SemanticError( decl, context_error ); 351 } 352 353 if ( !exception_name.empty() ) { 354 if( !typeid_decl || !vtable_decl ) { 355 SemanticError( decl, context_error ); 356 } 357 addTypeId( decl ); 358 addVtableForward( decl ); 359 } 360 361 const ast::FunctionDecl * func = forwardDeclare( decl ); 362 StructAndField addFieldRet = addField( decl ); 363 decl = addFieldRet.decl; 364 const ast::ObjectDecl * field = addFieldRet.field; 365 366 addGetRoutines( field, func ); 367 // Add routines to monitors for use by mutex stmt. 368 if ( ast::AggregateDecl::Monitor == cast_target ) { 369 addLockUnlockRoutines( decl ); 370 } 371 372 return decl; 373 } 374 375 void ConcurrentSueKeyword::handleMain( 376 const ast::FunctionDecl * decl, const ast::StructInstType * type ) { 377 assert( vtable_decl ); 378 assert( except_decl ); 379 380 const CodeLocation & location = decl->location; 381 382 std::vector<ast::ptr<ast::Expr>> poly_args = { 383 new ast::TypeExpr( location, type ), 384 }; 385 ast::ObjectDecl * vtable_object = Virtual::makeVtableInstance( 386 location, 387 "_default_vtable_object_declaration", 388 new ast::StructInstType( vtable_decl, copy( poly_args ) ), 389 type, 390 nullptr 391 ); 392 declsToAddAfter.push_back( vtable_object ); 393 declsToAddAfter.push_back( 394 new ast::ObjectDecl( 395 location, 396 Virtual::concurrentDefaultVTableName(), 397 new ast::ReferenceType( vtable_object->type, ast::CV::Const ), 398 new ast::SingleInit( location, 399 new ast::VariableExpr( location, vtable_object ) ), 400 ast::Storage::Classes(), 401 ast::Linkage::Cforall 402 ) 403 ); 404 declsToAddAfter.push_back( Virtual::makeGetExceptionFunction( 405 location, 406 vtable_object, 407 new ast::StructInstType( except_decl, copy( poly_args ) ) 408 ) ); 409 } 410 411 void ConcurrentSueKeyword::addTypeId( const ast::StructDecl * decl ) { 412 assert( typeid_decl ); 413 const CodeLocation & location = decl->location; 414 415 ast::StructInstType * typeid_type = 416 new ast::StructInstType( typeid_decl, ast::CV::Const ); 417 typeid_type->params.push_back( 418 new ast::TypeExpr( location, new ast::StructInstType( decl ) ) ); 419 declsToAddBefore.push_back( 420 Virtual::makeTypeIdInstance( location, typeid_type ) ); 421 // If the typeid_type is going to be kept, the other reference will have 422 // been made by now, but we also get to avoid extra mutates. 423 ast::ptr<ast::StructInstType> typeid_cleanup = typeid_type; 424 } 425 426 void ConcurrentSueKeyword::addVtableForward( const ast::StructDecl * decl ) { 427 assert( vtable_decl ); 428 const CodeLocation& location = decl->location; 429 430 std::vector<ast::ptr<ast::Expr>> poly_args = { 431 new ast::TypeExpr( location, new ast::StructInstType( decl ) ), 432 }; 433 declsToAddBefore.push_back( Virtual::makeGetExceptionForward( 434 location, 435 new ast::StructInstType( vtable_decl, copy( poly_args ) ), 436 new ast::StructInstType( except_decl, copy( poly_args ) ) 437 ) ); 438 ast::ObjectDecl * vtable_object = Virtual::makeVtableForward( 439 location, 440 "_default_vtable_object_declaration", 441 new ast::StructInstType( vtable_decl, std::move( poly_args ) ) 442 ); 443 declsToAddBefore.push_back( vtable_object ); 444 declsToAddBefore.push_back( 445 new ast::ObjectDecl( 446 location, 447 Virtual::concurrentDefaultVTableName(), 448 new ast::ReferenceType( vtable_object->type, ast::CV::Const ), 449 nullptr, 450 ast::Storage::Extern, 451 ast::Linkage::Cforall 452 ) 453 ); 454 } 455 456 const ast::FunctionDecl * ConcurrentSueKeyword::forwardDeclare( 457 const ast::StructDecl * decl ) { 458 const CodeLocation & location = decl->location; 459 460 ast::StructDecl * forward = ast::deepCopy( decl ); 461 { 462 // If removing members makes ref-count go to zero, do not free. 463 ast::ptr<ast::StructDecl> forward_ptr = forward; 464 forward->body = false; 465 forward->members.clear(); 466 forward_ptr.release(); 467 } 468 469 ast::ObjectDecl * this_decl = new ast::ObjectDecl( 470 location, 471 "this", 472 new ast::ReferenceType( new ast::StructInstType( decl ) ), 473 nullptr, 474 ast::Storage::Classes(), 475 ast::Linkage::Cforall 476 ); 477 478 ast::ObjectDecl * ret_decl = new ast::ObjectDecl( 479 location, 480 "ret", 481 new ast::PointerType( new ast::StructInstType( type_decl ) ), 482 nullptr, 483 ast::Storage::Classes(), 484 ast::Linkage::Cforall 485 ); 486 487 ast::FunctionDecl * get_decl = new ast::FunctionDecl( 488 location, 489 getter_name, 490 {}, // forall 491 { this_decl }, // params 492 { ret_decl }, // returns 493 nullptr, // stmts 494 ast::Storage::Static, 495 ast::Linkage::Cforall, 496 { new ast::Attribute( "const" ) }, 497 ast::Function::Inline 498 ); 499 get_decl = fixupGenerics( get_decl, decl ); 500 501 ast::FunctionDecl * main_decl = nullptr; 502 if ( needs_main ) { 503 // `this_decl` is copied here because the original was used above. 504 main_decl = new ast::FunctionDecl( 505 location, 506 "main", 507 {}, 508 { ast::deepCopy( this_decl ) }, 509 {}, 510 nullptr, 511 ast::Storage::Classes(), 512 ast::Linkage::Cforall 513 ); 514 main_decl = fixupGenerics( main_decl, decl ); 515 } 516 517 declsToAddBefore.push_back( forward ); 518 if ( needs_main ) declsToAddBefore.push_back( main_decl ); 519 declsToAddBefore.push_back( get_decl ); 520 521 return get_decl; 522 } 523 524 ConcurrentSueKeyword::StructAndField ConcurrentSueKeyword::addField( 525 const ast::StructDecl * decl ) { 526 const CodeLocation & location = decl->location; 527 528 ast::ObjectDecl * field = new ast::ObjectDecl( 529 location, 530 field_name, 531 new ast::StructInstType( type_decl ), 532 nullptr, 533 ast::Storage::Classes(), 534 ast::Linkage::Cforall 535 ); 536 537 auto mutDecl = ast::mutate( decl ); 538 mutDecl->members.push_back( field ); 539 540 return {mutDecl, field}; 541 } 542 543 void ConcurrentSueKeyword::addGetRoutines( 544 const ast::ObjectDecl * field, const ast::FunctionDecl * forward ) { 545 // Say it is generated at the "same" places as the forward declaration. 546 const CodeLocation & location = forward->location; 547 548 const ast::DeclWithType * param = forward->params.front(); 549 ast::Stmt * stmt = new ast::ReturnStmt( location, 550 new ast::AddressExpr( location, 551 new ast::MemberExpr( location, 552 field, 553 new ast::CastExpr( location, 554 new ast::VariableExpr( location, param ), 555 ast::deepCopy( param->get_type()->stripReferences() ), 556 ast::ExplicitCast 557 ) 558 ) 559 ) 560 ); 561 562 ast::FunctionDecl * decl = ast::deepCopy( forward ); 563 decl->stmts = new ast::CompoundStmt( location, { stmt } ); 564 declsToAddAfter.push_back( decl ); 565 } 566 567 void ConcurrentSueKeyword::addLockUnlockRoutines( 568 const ast::StructDecl * decl ) { 569 // This should only be used on monitors. 570 assert( ast::AggregateDecl::Monitor == cast_target ); 571 572 const CodeLocation & location = decl->location; 573 574 // The parameter for both routines. 575 ast::ObjectDecl * this_decl = new ast::ObjectDecl( 576 location, 577 "this", 578 new ast::ReferenceType( new ast::StructInstType( decl ) ), 579 nullptr, 580 ast::Storage::Classes(), 581 ast::Linkage::Cforall 582 ); 583 584 ast::FunctionDecl * lock_decl = new ast::FunctionDecl( 585 location, 586 "lock", 587 { /* forall */ }, 588 { 589 // Copy the declaration of this. 590 ast::deepCopy( this_decl ), 591 }, 592 { /* returns */ }, 593 nullptr, 594 ast::Storage::Static, 595 ast::Linkage::Cforall, 596 { /* attributes */ }, 597 ast::Function::Inline 598 ); 599 lock_decl = fixupGenerics( lock_decl, decl ); 600 601 lock_decl->stmts = new ast::CompoundStmt( location, { 602 new ast::ExprStmt( location, 603 new ast::UntypedExpr( location, 604 new ast::NameExpr( location, "lock" ), 605 { 606 new ast::UntypedExpr( location, 607 new ast::NameExpr( location, "get_monitor" ), 608 { new ast::VariableExpr( location, 609 InitTweak::getParamThis( lock_decl ) ) } 610 ) 611 } 612 ) 613 ) 614 } ); 615 616 ast::FunctionDecl * unlock_decl = new ast::FunctionDecl( 617 location, 618 "unlock", 619 { /* forall */ }, 620 { 621 // Last use, consume the declaration of this. 622 this_decl, 623 }, 624 { /* returns */ }, 625 nullptr, 626 ast::Storage::Static, 627 ast::Linkage::Cforall, 628 { /* attributes */ }, 629 ast::Function::Inline 630 ); 631 unlock_decl = fixupGenerics( unlock_decl, decl ); 632 633 unlock_decl->stmts = new ast::CompoundStmt( location, { 634 new ast::ExprStmt( location, 635 new ast::UntypedExpr( location, 636 new ast::NameExpr( location, "unlock" ), 637 { 638 new ast::UntypedExpr( location, 639 new ast::NameExpr( location, "get_monitor" ), 640 { new ast::VariableExpr( location, 641 InitTweak::getParamThis( unlock_decl ) ) } 642 ) 643 } 644 ) 645 ) 646 } ); 647 648 declsToAddAfter.push_back( lock_decl ); 649 declsToAddAfter.push_back( unlock_decl ); 650 } 651 652 653 // -------------------------------------------------------------------------- 654 struct SuspendKeyword final : 655 public ast::WithStmtsToAdd<>, public ast::WithGuards { 656 SuspendKeyword() = default; 657 virtual ~SuspendKeyword() = default; 658 659 void previsit( const ast::FunctionDecl * ); 660 const ast::DeclWithType * postvisit( const ast::FunctionDecl * ); 661 const ast::Stmt * postvisit( const ast::SuspendStmt * ); 662 663 private: 664 bool is_real_suspend( const ast::FunctionDecl * ); 665 666 const ast::Stmt * make_generator_suspend( const ast::SuspendStmt * ); 667 const ast::Stmt * make_coroutine_suspend( const ast::SuspendStmt * ); 668 669 struct LabelPair { 670 ast::Label obj; 671 int idx; 672 }; 673 674 LabelPair make_label(const ast::Stmt * stmt ) { 675 labels.push_back( ControlStruct::newLabel( "generator", stmt ) ); 676 return { labels.back(), int(labels.size()) }; 677 } 678 679 const ast::DeclWithType * in_generator = nullptr; 680 const ast::FunctionDecl * decl_suspend = nullptr; 681 std::vector<ast::Label> labels; 682 }; 683 684 void SuspendKeyword::previsit( const ast::FunctionDecl * decl ) { 685 GuardValue( in_generator ); in_generator = nullptr; 686 687 // If it is the real suspend, grab it if we don't have one already. 688 if ( is_real_suspend( decl ) ) { 689 decl_suspend = decl_suspend ? decl_suspend : decl; 690 return; 691 } 692 693 // Otherwise check if this is a generator main and, if so, handle it. 694 auto param = isMainFor( decl, ast::AggregateDecl::Generator ); 695 if ( !param ) return; 696 697 if ( 0 != decl->returns.size() ) { 698 SemanticError( decl->location, "Generator main must return void" ); 699 } 700 701 in_generator = param; 702 GuardValue( labels ); labels.clear(); 703 } 704 705 const ast::DeclWithType * SuspendKeyword::postvisit( 706 const ast::FunctionDecl * decl ) { 707 // Only modify a full definition of a generator with states. 708 if ( !decl->stmts || !in_generator || labels.empty() ) return decl; 709 710 const CodeLocation & location = decl->location; 711 712 // Create a new function body: 713 // static void * __generator_labels[] = {&&s0, &&s1, ...}; 714 // void * __generator_label = __generator_labels[GEN.__generator_state]; 715 // goto * __generator_label; 716 // s0: ; 717 // OLD_BODY 718 719 // This is the null statement inserted right before the body. 720 ast::NullStmt * noop = new ast::NullStmt( location ); 721 noop->labels.push_back( ControlStruct::newLabel( "generator", noop ) ); 722 const ast::Label & first_label = noop->labels.back(); 723 724 // Add each label to the init, starting with the first label. 725 std::vector<ast::ptr<ast::Init>> inits = { 726 new ast::SingleInit( location, 727 new ast::LabelAddressExpr( location, copy( first_label ) ) ) }; 728 // Then go through all the stored labels, and clear the store. 729 for ( auto && label : labels ) { 730 inits.push_back( new ast::SingleInit( label.location, 731 new ast::LabelAddressExpr( label.location, std::move( label ) 732 ) ) ); 733 } 734 labels.clear(); 735 // Then construct the initializer itself. 736 auto init = new ast::ListInit( location, std::move( inits ) ); 737 738 ast::ObjectDecl * generatorLabels = new ast::ObjectDecl( 739 location, 740 "__generator_labels", 741 new ast::ArrayType( 742 new ast::PointerType( new ast::VoidType() ), 743 nullptr, 744 ast::FixedLen, 745 ast::DynamicDim 746 ), 747 init, 748 ast::Storage::Classes(), 749 ast::Linkage::AutoGen 750 ); 751 752 ast::ObjectDecl * generatorLabel = new ast::ObjectDecl( 753 location, 754 "__generator_label", 755 new ast::PointerType( new ast::VoidType() ), 756 new ast::SingleInit( location, 757 new ast::UntypedExpr( location, 758 new ast::NameExpr( location, "?[?]" ), 759 { 760 // TODO: Could be a variable expr. 761 new ast::NameExpr( location, "__generator_labels" ), 762 new ast::UntypedMemberExpr( location, 763 new ast::NameExpr( location, "__generator_state" ), 764 new ast::VariableExpr( location, in_generator ) 765 ) 766 } 767 ) 768 ), 769 ast::Storage::Classes(), 770 ast::Linkage::AutoGen 771 ); 772 773 ast::BranchStmt * theGoTo = new ast::BranchStmt( 774 location, new ast::VariableExpr( location, generatorLabel ) 775 ); 776 777 // The noop goes here in order. 778 779 ast::CompoundStmt * body = new ast::CompoundStmt( location, { 780 { new ast::DeclStmt( location, generatorLabels ) }, 781 { new ast::DeclStmt( location, generatorLabel ) }, 782 { theGoTo }, 783 { noop }, 784 { decl->stmts }, 785 } ); 786 787 auto mutDecl = ast::mutate( decl ); 788 mutDecl->stmts = body; 789 return mutDecl; 790 } 791 792 const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) { 793 switch ( stmt->type ) { 794 case ast::SuspendStmt::None: 795 // Use the context to determain the implicit target. 796 if ( in_generator ) { 797 return make_generator_suspend( stmt ); 798 } else { 799 return make_coroutine_suspend( stmt ); 800 } 801 case ast::SuspendStmt::Coroutine: 802 return make_coroutine_suspend( stmt ); 803 case ast::SuspendStmt::Generator: 804 // Generator suspends must be directly in a generator. 805 if ( !in_generator ) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type." ); 806 return make_generator_suspend( stmt ); 807 } 808 assert( false ); 809 return stmt; 810 } 811 812 /// Find the real/official suspend declaration. 813 bool SuspendKeyword::is_real_suspend( const ast::FunctionDecl * decl ) { 814 return ( !decl->linkage.is_mangled 815 && 0 == decl->params.size() 816 && 0 == decl->returns.size() 817 && "__cfactx_suspend" == decl->name ); 818 } 819 820 const ast::Stmt * SuspendKeyword::make_generator_suspend( 821 const ast::SuspendStmt * stmt ) { 822 assert( in_generator ); 823 // Target code is: 824 // GEN.__generator_state = X; 825 // THEN 826 // return; 827 // __gen_X:; 828 829 const CodeLocation & location = stmt->location; 830 831 LabelPair label = make_label( stmt ); 832 833 // This is the context saving statement. 834 stmtsToAddBefore.push_back( new ast::ExprStmt( location, 835 new ast::UntypedExpr( location, 836 new ast::NameExpr( location, "?=?" ), 837 { 838 new ast::UntypedMemberExpr( location, 839 new ast::NameExpr( location, "__generator_state" ), 840 new ast::VariableExpr( location, in_generator ) 841 ), 842 ast::ConstantExpr::from_int( location, label.idx ), 843 } 844 ) 845 ) ); 846 847 // The THEN component is conditional (return is not). 848 if ( stmt->then ) { 849 stmtsToAddBefore.push_back( stmt->then.get() ); 850 } 851 stmtsToAddBefore.push_back( new ast::ReturnStmt( location, nullptr ) ); 852 853 // The null statement replaces the old suspend statement. 854 return new ast::NullStmt( location, { label.obj } ); 855 } 856 857 const ast::Stmt * SuspendKeyword::make_coroutine_suspend( 858 const ast::SuspendStmt * stmt ) { 859 // The only thing we need from the old statement is the location. 860 const CodeLocation & location = stmt->location; 861 862 if ( !decl_suspend ) { 863 SemanticError( location, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n" ); 864 } 865 if ( stmt->then ) { 866 SemanticError( location, "Compound statement following coroutines is not implemented." ); 867 } 868 869 return new ast::ExprStmt( location, 870 new ast::UntypedExpr( location, 871 ast::VariableExpr::functionPointer( location, decl_suspend ) ) 872 ); 36 873 } 37 874 … … 251 1088 { 252 1089 new ast::SingleInit( location, 253 new ast::AddressExpr( 1090 new ast::AddressExpr( location, 254 1091 new ast::VariableExpr( location, monitor ) ) ), 255 1092 new ast::SingleInit( location, … … 564 1401 565 1402 // -------------------------------------------------------------------------- 1403 // Interface Functions: 566 1404 567 1405 void implementKeywords( ast::TranslationUnit & translationUnit ) { 568 (void)translationUnit; 569 assertf(false, "Apply Keywords not implemented." ); 1406 ast::Pass<ThreadKeyword>::run( translationUnit ); 1407 ast::Pass<CoroutineKeyword>::run( translationUnit ); 1408 ast::Pass<MonitorKeyword>::run( translationUnit ); 1409 ast::Pass<GeneratorKeyword>::run( translationUnit ); 1410 ast::Pass<SuspendKeyword>::run( translationUnit ); 570 1411 } 571 1412
Note: See TracChangeset
for help on using the changeset viewer.