source: src/Concurrency/Keywords.cc@ b7fe2e6

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since b7fe2e6 was b81fd95, checked in by Michael Brooks <mlbrooks@…>, 5 years ago

Fix bug where pointer and reference types allow unsound initialization and return. Fixes #189

There are two instances of the same basic change, which is using conversionCost instead of castCost for resolving...
A: an InitExpr, always; affects variable initializations
B: a CastExpr, for type-system-generated casts only; affects function returns

Changing the behaviour of the typechecker on initialization (do A) and cast (do B):
src/ResolvExpr/AlternativeFinder.cc
src/SynTree/Expression.h
testsinit1.*

Making type of string literal consistent with how C defines it (accommodate A):
src/Parser/ExpressionNode.cc

Making type system happy with incumbent use of void* (accommodate A):
libcfa/src/concurrency/kernel.cfa
libcfa/src/containers/list.hfa
tests/bugs/66.cfa
tests/avltree/avl1.cfa
tests/concurrent/signal/block.cfa
tests/searchsort.cfa

Making type system happy with incumbent plan-9 downcast (accommodate B):
libcfa/src/containers/list.hfa

Fixing previously incorrect constness of declarations (accommodate A):
tests/exceptions/defaults.cfa
libcfa/src/iostream.hfa

Fixing previously incorrect isGenerated classification of casts that desugaring introduces (accommodate B):
src/Concurrency/Keywords.cc
src/Concurrency/Waitfor.cc

Working around trac #207 (revealed by A):
tests/io2.cfa

Working around trac #208 (speculatively created by B):
libcfa/src/bits/locks.hfa
libcfa/src/concurrency/preemption.cfa

Misc:
tests/exceptions/conditional.cfa (accommodate A)

a _msg function for an exception was declared with wrong return type, so it was not compatible for assignment into the vtable instance

libcfa/src/stdlib.hfa

the compiler now prohibits a prior attempt to call a nonexistent realloc overload; calling alloc_align in its place

  • Property mode set to 100644
File size: 31.6 KB
RevLine 
[64adb03]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// Keywords.cc --
8//
9// Author : Thierry Delisle
10// Created On : Mon Mar 13 12:41:22 2017
11// Last Modified By :
12// Last Modified On :
[07de76b]13// Update Count : 10
[64adb03]14//
15
16#include "Concurrency/Keywords.h"
17
[427854b]18#include <cassert> // for assert
19#include <string> // for string, operator==
20
21#include "Common/PassVisitor.h" // for PassVisitor
22#include "Common/SemanticError.h" // for SemanticError
23#include "Common/utility.h" // for deleteAll, map_range
24#include "CodeGen/OperatorTable.h" // for isConstructor
25#include "ControlStruct/LabelGenerator.h" // for LebelGenerator
26#include "InitTweak/InitTweak.h" // for getPointerBase
27#include "SynTree/LinkageSpec.h" // for Cforall
28#include "SynTree/Constant.h" // for Constant
29#include "SynTree/Declaration.h" // for StructDecl, FunctionDecl, ObjectDecl
30#include "SynTree/Expression.h" // for VariableExpr, ConstantExpr, Untype...
31#include "SynTree/Initializer.h" // for SingleInit, ListInit, Initializer ...
32#include "SynTree/Label.h" // for Label
33#include "SynTree/Statement.h" // for CompoundStmt, DeclStmt, ExprStmt
34#include "SynTree/Type.h" // for StructInstType, Type, PointerType
35#include "SynTree/Visitor.h" // for Visitor, acceptAll
[bf2438c]36
37class Attribute;
[64adb03]38
39namespace Concurrency {
40 //=============================================================================================
[2065609]41 // Pass declarations
[64adb03]42 //=============================================================================================
43
[bcda04c]44 //-----------------------------------------------------------------------------
45 //Handles sue type declarations :
46 // sue MyType { struct MyType {
47 // int data; int data;
48 // a_struct_t more_data; a_struct_t more_data;
49 // => NewField_t newField;
50 // }; };
51 // static inline NewField_t * getter_name( MyType * this ) { return &this->newField; }
52 //
[2065609]53 class ConcurrentSueKeyword : public WithDeclsToAdd {
[bcda04c]54 public:
55
[312029a]56 ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main, AggregateDecl::Aggregate cast_target ) :
[9a705dc8]57 type_name( type_name ), field_name( field_name ), getter_name( getter_name ), context_error( context_error ), needs_main( needs_main ), cast_target( cast_target ) {}
[bcda04c]58
59 virtual ~ConcurrentSueKeyword() {}
60
[9a705dc8]61 Declaration * postmutate( StructDecl * decl );
[6c3a5ac1]62 DeclarationWithType * postmutate( FunctionDecl * decl );
[bcda04c]63
64 void handle( StructDecl * );
65 FunctionDecl * forwardDeclare( StructDecl * );
66 ObjectDecl * addField( StructDecl * );
[2f9a722]67 void addRoutines( ObjectDecl *, FunctionDecl * );
[bcda04c]68
69 virtual bool is_target( StructDecl * decl ) = 0;
70
[9a705dc8]71 Expression * postmutate( KeywordCastExpr * cast );
72
[bcda04c]73 private:
74 const std::string type_name;
75 const std::string field_name;
76 const std::string getter_name;
77 const std::string context_error;
[bd4d011]78 bool needs_main;
[312029a]79 AggregateDecl::Aggregate cast_target;
[bcda04c]80
[6c3a5ac1]81 StructDecl * type_decl = nullptr;
82 FunctionDecl * dtor_decl = nullptr;
[bcda04c]83 };
84
85
[64adb03]86 //-----------------------------------------------------------------------------
87 //Handles thread type declarations :
88 // thread Mythread { struct MyThread {
89 // int data; int data;
90 // a_struct_t more_data; a_struct_t more_data;
[ac2b598]91 // => $thread __thrd_d;
[64adb03]92 // }; };
[ac2b598]93 // static inline $thread * get_thread( MyThread * this ) { return &this->__thrd_d; }
[64adb03]94 //
[bcda04c]95 class ThreadKeyword final : public ConcurrentSueKeyword {
[64adb03]96 public:
97
[bcda04c]98 ThreadKeyword() : ConcurrentSueKeyword(
[ac2b598]99 "$thread",
[bcda04c]100 "__thrd",
101 "get_thread",
[6c3a5ac1]102 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
[9a705dc8]103 true,
[312029a]104 AggregateDecl::Thread
[bcda04c]105 )
106 {}
107
108 virtual ~ThreadKeyword() {}
109
110 virtual bool is_target( StructDecl * decl ) override final { return decl->is_thread(); }
111
112 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]113 PassVisitor< ThreadKeyword > impl;
[9a705dc8]114 mutateAll( translationUnit, impl );
[bcda04c]115 }
[64adb03]116 };
117
118 //-----------------------------------------------------------------------------
119 //Handles coroutine type declarations :
120 // coroutine MyCoroutine { struct MyCoroutine {
121 // int data; int data;
122 // a_struct_t more_data; a_struct_t more_data;
[ac2b598]123 // => $coroutine __cor_d;
[64adb03]124 // }; };
[ac2b598]125 // static inline $coroutine * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
[64adb03]126 //
[bcda04c]127 class CoroutineKeyword final : public ConcurrentSueKeyword {
[64adb03]128 public:
129
[bcda04c]130 CoroutineKeyword() : ConcurrentSueKeyword(
[ac2b598]131 "$coroutine",
[bcda04c]132 "__cor",
133 "get_coroutine",
[6c3a5ac1]134 "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
[9a705dc8]135 true,
[312029a]136 AggregateDecl::Coroutine
[bcda04c]137 )
138 {}
[b32ada31]139
[bcda04c]140 virtual ~CoroutineKeyword() {}
141
142 virtual bool is_target( StructDecl * decl ) override final { return decl->is_coroutine(); }
[b32ada31]143
144 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]145 PassVisitor< CoroutineKeyword > impl;
[9a705dc8]146 mutateAll( translationUnit, impl );
[b32ada31]147 }
[64adb03]148 };
149
[427854b]150
151
[64adb03]152 //-----------------------------------------------------------------------------
153 //Handles monitor type declarations :
154 // monitor MyMonitor { struct MyMonitor {
155 // int data; int data;
156 // a_struct_t more_data; a_struct_t more_data;
[ac2b598]157 // => $monitor __mon_d;
[64adb03]158 // }; };
[ac2b598]159 // static inline $monitor * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
[64adb03]160 //
[bcda04c]161 class MonitorKeyword final : public ConcurrentSueKeyword {
[64adb03]162 public:
163
[bcda04c]164 MonitorKeyword() : ConcurrentSueKeyword(
[ac2b598]165 "$monitor",
[bcda04c]166 "__mon",
167 "get_monitor",
[6c3a5ac1]168 "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
[9a705dc8]169 false,
[312029a]170 AggregateDecl::Monitor
[bcda04c]171 )
172 {}
173
174 virtual ~MonitorKeyword() {}
175
176 virtual bool is_target( StructDecl * decl ) override final { return decl->is_monitor(); }
177
178 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]179 PassVisitor< MonitorKeyword > impl;
[9a705dc8]180 mutateAll( translationUnit, impl );
[bcda04c]181 }
[64adb03]182 };
183
[427854b]184 //-----------------------------------------------------------------------------
185 //Handles generator type declarations :
186 // generator MyGenerator { struct MyGenerator {
187 // int data; int data;
188 // a_struct_t more_data; a_struct_t more_data;
189 // => int __gen_next;
190 // }; };
191 //
192 class GeneratorKeyword final : public ConcurrentSueKeyword {
193 public:
194
195 GeneratorKeyword() : ConcurrentSueKeyword(
196 "$generator",
197 "__generator_state",
198 "get_generator",
199 "Unable to find builtin type $generator\n",
200 true,
201 AggregateDecl::Generator
202 )
203 {}
204
205 virtual ~GeneratorKeyword() {}
206
207 virtual bool is_target( StructDecl * decl ) override final { return decl->is_generator(); }
208
209 static void implement( std::list< Declaration * > & translationUnit ) {
210 PassVisitor< GeneratorKeyword > impl;
211 mutateAll( translationUnit, impl );
212 }
213 };
214
215
216 //-----------------------------------------------------------------------------
217 class SuspendKeyword final : public WithStmtsToAdd, public WithGuards {
218 public:
219 SuspendKeyword() = default;
220 virtual ~SuspendKeyword() = default;
221
222 void premutate( FunctionDecl * );
223 DeclarationWithType * postmutate( FunctionDecl * );
224
225 Statement * postmutate( SuspendStmt * );
226
227 static void implement( std::list< Declaration * > & translationUnit ) {
228 PassVisitor< SuspendKeyword > impl;
229 mutateAll( translationUnit, impl );
230 }
231
232 private:
233 DeclarationWithType * is_main( FunctionDecl * );
234 bool is_real_suspend( FunctionDecl * );
235
236 Statement * make_generator_suspend( SuspendStmt * );
237 Statement * make_coroutine_suspend( SuspendStmt * );
238
239 struct LabelPair {
240 Label obj;
241 int idx;
242 };
243
244 LabelPair make_label() {
245 labels.push_back( gen.newLabel("generator") );
246 return { labels.back(), int(labels.size()) };
247 }
248
249 DeclarationWithType * in_generator = nullptr;
250 FunctionDecl * decl_suspend = nullptr;
251 std::vector<Label> labels;
252 ControlStruct::LabelGenerator & gen = *ControlStruct::LabelGenerator::getGenerator();
253 };
254
[64adb03]255 //-----------------------------------------------------------------------------
256 //Handles mutex routines definitions :
257 // void foo( A * mutex a, B * mutex b, int i ) { void foo( A * a, B * b, int i ) {
[ac2b598]258 // $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
[64adb03]259 // monitor_guard_t __guard = { __monitors, 2 };
260 // /*Some code*/ => /*Some code*/
261 // } }
262 //
[2065609]263 class MutexKeyword final {
[64adb03]264 public:
265
[2065609]266 void postvisit( FunctionDecl * decl );
267 void postvisit( StructDecl * decl );
[64adb03]268
[db4d8e3]269 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first );
[64adb03]270 void validate( DeclarationWithType * );
[549c006]271 void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
[97e3296]272 void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
[64adb03]273
274 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]275 PassVisitor< MutexKeyword > impl;
[64adb03]276 acceptAll( translationUnit, impl );
277 }
[9243cc91]278
279 private:
280 StructDecl* monitor_decl = nullptr;
[ef42b143]281 StructDecl* guard_decl = nullptr;
[549c006]282 StructDecl* dtor_guard_decl = nullptr;
[97e3296]283
284 static std::unique_ptr< Type > generic_func;
[64adb03]285 };
286
[97e3296]287 std::unique_ptr< Type > MutexKeyword::generic_func = std::unique_ptr< Type >(
288 new FunctionType(
289 noQualifiers,
290 true
291 )
292 );
293
[bd4d011]294 //-----------------------------------------------------------------------------
295 //Handles mutex routines definitions :
296 // void foo( A * mutex a, B * mutex b, int i ) { void foo( A * a, B * b, int i ) {
[ac2b598]297 // $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
[bd4d011]298 // monitor_guard_t __guard = { __monitors, 2 };
299 // /*Some code*/ => /*Some code*/
300 // } }
301 //
[2065609]302 class ThreadStarter final {
[bd4d011]303 public:
304
[2065609]305 void postvisit( FunctionDecl * decl );
[549c006]306 void previsit ( StructDecl * decl );
[bd4d011]307
308 void addStartStatement( FunctionDecl * decl, DeclarationWithType * param );
309
310 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]311 PassVisitor< ThreadStarter > impl;
[bd4d011]312 acceptAll( translationUnit, impl );
313 }
[549c006]314
315 private :
316 bool thread_ctor_seen = false;
317 StructDecl * thread_decl = nullptr;
[bd4d011]318 };
319
[64adb03]320 //=============================================================================================
321 // General entry routine
322 //=============================================================================================
323 void applyKeywords( std::list< Declaration * > & translationUnit ) {
324 ThreadKeyword ::implement( translationUnit );
325 CoroutineKeyword ::implement( translationUnit );
326 MonitorKeyword ::implement( translationUnit );
[427854b]327 GeneratorKeyword ::implement( translationUnit );
328 SuspendKeyword ::implement( translationUnit );
[bcda04c]329 }
330
331 void implementMutexFuncs( std::list< Declaration * > & translationUnit ) {
[64adb03]332 MutexKeyword ::implement( translationUnit );
333 }
334
[bcda04c]335 void implementThreadStarter( std::list< Declaration * > & translationUnit ) {
[bd4d011]336 ThreadStarter ::implement( translationUnit );
[bcda04c]337 }
338
[b32ada31]339 //=============================================================================================
[bcda04c]340 // Generic keyword implementation
[b32ada31]341 //=============================================================================================
[2db79e5]342 void fixupGenerics(FunctionType * func, StructDecl * decl) {
343 cloneAll(decl->parameters, func->forall);
344 for ( TypeDecl * td : func->forall ) {
345 strict_dynamic_cast<StructInstType*>(
346 func->parameters.front()->get_type()->stripReferences()
347 )->parameters.push_back(
348 new TypeExpr( new TypeInstType( noQualifiers, td->name, td ) )
349 );
350 }
351 }
352
[9a705dc8]353 Declaration * ConcurrentSueKeyword::postmutate(StructDecl * decl) {
[9f5ecf5]354 if( decl->name == type_name && decl->body ) {
[bcda04c]355 assert( !type_decl );
356 type_decl = decl;
[b32ada31]357 }
[bcda04c]358 else if ( is_target(decl) ) {
[b32ada31]359 handle( decl );
360 }
[9a705dc8]361 return decl;
[b32ada31]362 }
363
[6c3a5ac1]364 DeclarationWithType * ConcurrentSueKeyword::postmutate( FunctionDecl * decl ) {
365 if( !type_decl ) return decl;
366 if( !CodeGen::isDestructor( decl->name ) ) return decl;
367
368 auto params = decl->type->parameters;
369 if( params.size() != 1 ) return decl;
370
371 auto type = dynamic_cast<ReferenceType*>( params.front()->get_type() );
372 if( !type ) return decl;
373
374 auto stype = dynamic_cast<StructInstType*>( type->base );
375 if( !stype ) return decl;
376 if( stype->baseStruct != type_decl ) return decl;
377
378 if( !dtor_decl ) dtor_decl = decl;
379 return decl;
380 }
381
[9a705dc8]382 Expression * ConcurrentSueKeyword::postmutate( KeywordCastExpr * cast ) {
383 if ( cast_target == cast->target ) {
[ac2b598]384 // convert (thread &)t to ($thread &)*get_thread(t), etc.
[9a705dc8]385 if( !type_decl ) SemanticError( cast, context_error );
[6c3a5ac1]386 if( !dtor_decl ) SemanticError( cast, context_error );
[3b0c8cb]387 assert( cast->result == nullptr );
388 cast->set_result( new ReferenceType( noQualifiers, new StructInstType( noQualifiers, type_decl ) ) );
389 cast->concrete_target.field = field_name;
390 cast->concrete_target.getter = getter_name;
[9a705dc8]391 }
392 return cast;
393 }
394
395
[bcda04c]396 void ConcurrentSueKeyword::handle( StructDecl * decl ) {
[9f5ecf5]397 if( ! decl->body ) return;
[b32ada31]398
[a16764a6]399 if( !type_decl ) SemanticError( decl, context_error );
[6c3a5ac1]400 if( !dtor_decl ) SemanticError( decl, context_error );
[b32ada31]401
[bcda04c]402 FunctionDecl * func = forwardDeclare( decl );
403 ObjectDecl * field = addField( decl );
[2f9a722]404 addRoutines( field, func );
[b32ada31]405 }
406
[bcda04c]407 FunctionDecl * ConcurrentSueKeyword::forwardDeclare( StructDecl * decl ) {
408
409 StructDecl * forward = decl->clone();
410 forward->set_body( false );
411 deleteAll( forward->get_members() );
412 forward->get_members().clear();
413
[bd4d011]414 FunctionType * get_type = new FunctionType( noQualifiers, false );
[bcda04c]415 ObjectDecl * this_decl = new ObjectDecl(
416 "this",
[ba3706f]417 noStorageClasses,
[b32ada31]418 LinkageSpec::Cforall,
419 nullptr,
[83a071f9]420 new ReferenceType(
[b32ada31]421 noQualifiers,
[bcda04c]422 new StructInstType(
423 noQualifiers,
424 decl
425 )
[b32ada31]426 ),
427 nullptr
428 );
429
[2db79e5]430 get_type->get_parameters().push_back( this_decl->clone() );
[bd4d011]431 get_type->get_returnVals().push_back(
[e04b636]432 new ObjectDecl(
433 "ret",
[ba3706f]434 noStorageClasses,
[e04b636]435 LinkageSpec::Cforall,
436 nullptr,
437 new PointerType(
438 noQualifiers,
439 new StructInstType(
440 noQualifiers,
[bcda04c]441 type_decl
[e04b636]442 )
443 ),
444 nullptr
445 )
446 );
[2db79e5]447 fixupGenerics(get_type, decl);
[b32ada31]448
[bcda04c]449 FunctionDecl * get_decl = new FunctionDecl(
450 getter_name,
451 Type::Static,
452 LinkageSpec::Cforall,
[bd4d011]453 get_type,
[bcda04c]454 nullptr,
[a8078ee]455 { new Attribute("const") },
[bcda04c]456 Type::Inline
457 );
458
[bd4d011]459 FunctionDecl * main_decl = nullptr;
460
461 if( needs_main ) {
462 FunctionType * main_type = new FunctionType( noQualifiers, false );
[bf2438c]463
[bd4d011]464 main_type->get_parameters().push_back( this_decl->clone() );
465
466 main_decl = new FunctionDecl(
467 "main",
[ba3706f]468 noStorageClasses,
[bd4d011]469 LinkageSpec::Cforall,
470 main_type,
471 nullptr
472 );
[2db79e5]473 fixupGenerics(main_type, decl);
[bd4d011]474 }
475
[2db79e5]476 delete this_decl;
477
[2065609]478 declsToAddBefore.push_back( forward );
479 if( needs_main ) declsToAddBefore.push_back( main_decl );
480 declsToAddBefore.push_back( get_decl );
[bcda04c]481
482 return get_decl;
483 }
484
485 ObjectDecl * ConcurrentSueKeyword::addField( StructDecl * decl ) {
486 ObjectDecl * field = new ObjectDecl(
487 field_name,
[ba3706f]488 noStorageClasses,
[bcda04c]489 LinkageSpec::Cforall,
490 nullptr,
491 new StructInstType(
492 noQualifiers,
493 type_decl
494 ),
495 nullptr
496 );
497
498 decl->get_members().push_back( field );
499
500 return field;
501 }
502
[2f9a722]503 void ConcurrentSueKeyword::addRoutines( ObjectDecl * field, FunctionDecl * func ) {
[ba3706f]504 CompoundStmt * statement = new CompoundStmt();
[bf2438c]505 statement->push_back(
[b32ada31]506 new ReturnStmt(
[e04b636]507 new AddressExpr(
[bcda04c]508 new MemberExpr(
509 field,
[2db79e5]510 new CastExpr(
511 new VariableExpr( func->get_functionType()->get_parameters().front() ),
[b81fd95]512 func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone(),
513 false
[2db79e5]514 )
[e04b636]515 )
[b32ada31]516 )
517 )
518 );
519
[bcda04c]520 FunctionDecl * get_decl = func->clone();
521
522 get_decl->set_statements( statement );
[e04b636]523
524 declsToAddAfter.push_back( get_decl );
[427854b]525 }
526
527 //=============================================================================================
528 // Suspend keyword implementation
529 //=============================================================================================
530 DeclarationWithType * SuspendKeyword::is_main( FunctionDecl * func) {
531 if(func->name != "main") return nullptr;
532 if(func->type->parameters.size() != 1) return nullptr;
533
534 auto param = func->type->parameters.front();
535
536 auto type = dynamic_cast<ReferenceType * >(param->get_type());
537 if(!type) return nullptr;
[e04b636]538
[427854b]539 auto obj = dynamic_cast<StructInstType *>(type->base);
540 if(!obj) return nullptr;
541
542 if(!obj->baseStruct->is_generator()) return nullptr;
543
544 return param;
545 }
546
547 bool SuspendKeyword::is_real_suspend( FunctionDecl * func ) {
548 if(isMangled(func->linkage)) return false; // the real suspend isn't mangled
549 if(func->name != "__cfactx_suspend") return false; // the real suspend has a specific name
550 if(func->type->parameters.size() != 0) return false; // Too many parameters
551 if(func->type->returnVals.size() != 0) return false; // Too many return values
552
553 return true;
[b32ada31]554 }
555
[427854b]556 void SuspendKeyword::premutate( FunctionDecl * func ) {
557 GuardValue(in_generator);
558 in_generator = nullptr;
559
560 // Is this the real suspend?
561 if(is_real_suspend(func)) {
562 decl_suspend = decl_suspend ? decl_suspend : func;
563 return;
564 }
565
566 // Is this the main of a generator?
567 auto param = is_main( func );
568 if(!param) return;
569
570 if(func->type->returnVals.size() != 0) SemanticError(func->location, "Generator main must return void");
571
572 in_generator = param;
573 GuardValue(labels);
574 labels.clear();
575 }
576
577 DeclarationWithType * SuspendKeyword::postmutate( FunctionDecl * func ) {
578 if( !func->statements ) return func; // Not the actual definition, don't do anything
579 if( !in_generator ) return func; // Not in a generator, don't do anything
580 if( labels.empty() ) return func; // Generator has no states, nothing to do, could throw a warning
581
582 // This is a generator main, we need to add the following code to the top
583 // static void * __generator_labels[] = {&&s0, &&s1, ...};
584 // goto * __generator_labels[gen.__generator_state];
585 const auto & loc = func->location;
586
587 const auto first_label = gen.newLabel("generator");
588
589 // for each label add to declaration
590 std::list<Initializer*> inits = { new SingleInit( new LabelAddressExpr( first_label ) ) };
591 for(const auto & label : labels) {
592 inits.push_back(
593 new SingleInit(
594 new LabelAddressExpr( label )
595 )
596 );
597 }
598 auto init = new ListInit(std::move(inits), noDesignators, true);
599 labels.clear();
600
601 // create decl
602 auto decl = new ObjectDecl(
603 "__generator_labels",
604 Type::StorageClasses( Type::Static ),
605 LinkageSpec::AutoGen,
606 nullptr,
607 new ArrayType(
608 Type::Qualifiers(),
609 new PointerType(
610 Type::Qualifiers(),
611 new VoidType( Type::Qualifiers() )
612 ),
613 nullptr,
614 false, false
615 ),
616 init
617 );
618
619 // create the goto
620 assert(in_generator);
621
622 auto go_decl = new ObjectDecl(
623 "__generator_label",
624 noStorageClasses,
625 LinkageSpec::AutoGen,
626 nullptr,
627 new PointerType(
628 Type::Qualifiers(),
629 new VoidType( Type::Qualifiers() )
630 ),
631 new SingleInit(
632 new UntypedExpr(
633 new NameExpr("?[?]"),
634 {
635 new NameExpr("__generator_labels"),
636 new UntypedMemberExpr(
637 new NameExpr("__generator_state"),
638 new VariableExpr( in_generator )
639 )
640 }
641 )
642 )
643 );
644 go_decl->location = loc;
645
646 auto go = new BranchStmt(
647 new VariableExpr( go_decl ),
648 BranchStmt::Goto
649 );
650 go->location = loc;
651 go->computedTarget->location = loc;
652
653 auto noop = new NullStmt({ first_label });
654 noop->location = loc;
655
656 // wrap everything in a nice compound
657 auto body = new CompoundStmt({
658 new DeclStmt( decl ),
659 new DeclStmt( go_decl ),
660 go,
661 noop,
662 func->statements
663 });
664 body->location = loc;
665 func->statements = body;
666
667 return func;
668 }
669
670 Statement * SuspendKeyword::postmutate( SuspendStmt * stmt ) {
671 SuspendStmt::Type type = stmt->type;
672 if(type == SuspendStmt::None) {
673 // This suspend has a implicit target, find it
674 type = in_generator ? SuspendStmt::Generator : SuspendStmt::Coroutine;
675 }
676
677 // Check that the target makes sense
678 if(!in_generator && type == SuspendStmt::Generator) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type.");
679
680 // Act appropriately
681 switch(type) {
682 case SuspendStmt::Generator: return make_generator_suspend(stmt);
683 case SuspendStmt::Coroutine: return make_coroutine_suspend(stmt);
684 default: abort();
685 }
686 }
687
688 Statement * SuspendKeyword::make_generator_suspend( SuspendStmt * stmt ) {
689 assert(in_generator);
690 // Target code is :
691 // gen.__generator_state = X;
692 // { THEN }
693 // return;
694 // __gen_X:;
695
696 // Save the location and delete the old statement, we only need the location from this point on
697 auto loc = stmt->location;
698
699 // Build the label and get its index
700 auto label = make_label();
701
702 // Create the context saving statement
703 auto save = new ExprStmt( new UntypedExpr(
704 new NameExpr( "?=?" ),
705 {
706 new UntypedMemberExpr(
707 new NameExpr("__generator_state"),
708 new VariableExpr( in_generator )
709 ),
710 new ConstantExpr(
711 Constant::from_int( label.idx )
712 )
713 }
714 ));
715 assert(save->expr);
716 save->location = loc;
717 stmtsToAddBefore.push_back( save );
718
719 // if we have a then add it here
720 auto then = stmt->then;
721 stmt->then = nullptr;
722 delete stmt;
723 if(then) stmtsToAddBefore.push_back( then );
724
725 // Create the return statement
726 auto ret = new ReturnStmt( nullptr );
727 ret->location = loc;
728 stmtsToAddBefore.push_back( ret );
729
730 // Create the null statement with the created label
731 auto noop = new NullStmt({ label.obj });
732 noop->location = loc;
733
734 // Return the null statement to take the place of the previous statement
735 return noop;
736 }
737
738 Statement * SuspendKeyword::make_coroutine_suspend( SuspendStmt * stmt ) {
739 if(stmt->then) SemanticError( stmt->location, "Compound statement following coroutines is not implemented.");
740
741 // Save the location and delete the old statement, we only need the location from this point on
742 auto loc = stmt->location;
743 delete stmt;
744
745 // Create the call expression
746 if(!decl_suspend) SemanticError( loc, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n");
747 auto expr = new UntypedExpr( VariableExpr::functionPointer( decl_suspend ) );
[e6cfa8ff]748 expr->location = loc;
[427854b]749
750 // Change this statement into a regular expr
751 assert(expr);
752 auto nstmt = new ExprStmt( expr );
[e6cfa8ff]753 nstmt->location = loc;
[427854b]754 return nstmt;
755 }
756
757
[64adb03]758 //=============================================================================================
759 // Mutex keyword implementation
760 //=============================================================================================
[97e3296]761
[2065609]762 void MutexKeyword::postvisit(FunctionDecl* decl) {
[102a58b]763
[db4d8e3]764 bool first = false;
765 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first );
[ceedde6]766 bool isDtor = CodeGen::isDestructor( decl->name );
[64adb03]767
[ceedde6]768 // Is this function relevant to monitors
769 if( mutexArgs.empty() ) {
770 // If this is the destructor for a monitor it must be mutex
771 if(isDtor) {
772 Type* ty = decl->get_functionType()->get_parameters().front()->get_type();
773
774 // If it's a copy, it's not a mutex
775 ReferenceType* rty = dynamic_cast< ReferenceType * >( ty );
776 if( ! rty ) return;
777
778 // If we are not pointing directly to a type, it's not a mutex
779 Type* base = rty->get_base();
780 if( dynamic_cast< ReferenceType * >( base ) ) return;
781 if( dynamic_cast< PointerType * >( base ) ) return;
782
783 // Check if its a struct
784 StructInstType * baseStruct = dynamic_cast< StructInstType * >( base );
785 if( !baseStruct ) return;
786
787 // Check if its a monitor
788 if(baseStruct->baseStruct->is_monitor() || baseStruct->baseStruct->is_thread())
789 SemanticError( decl, "destructors for structures declared as \"monitor\" must use mutex parameters\n" );
790 }
791 return;
792 }
[549c006]793
[ceedde6]794 // Monitors can't be constructed with mutual exclusion
795 if( CodeGen::isConstructor(decl->name) && !first ) SemanticError( decl, "constructors cannot have mutex parameters" );
[549c006]796
[ceedde6]797 // It makes no sense to have multiple mutex parameters for the destructor
[a16764a6]798 if( isDtor && mutexArgs.size() != 1 ) SemanticError( decl, "destructors can only have 1 mutex argument" );
[549c006]799
[ceedde6]800 // Make sure all the mutex arguments are monitors
[64adb03]801 for(auto arg : mutexArgs) {
802 validate( arg );
803 }
804
[ceedde6]805 // Check if we need to instrument the body
[64adb03]806 CompoundStmt* body = decl->get_statements();
807 if( ! body ) return;
808
[ceedde6]809 // Do we have the required headers
[a16764a6]810 if( !monitor_decl || !guard_decl || !dtor_guard_decl )
[73abe95]811 SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor.hfa>\n" );
[b32ada31]812
[ceedde6]813 // Instrument the body
[549c006]814 if( isDtor ) {
815 addDtorStatments( decl, body, mutexArgs );
816 }
817 else {
818 addStatments( decl, body, mutexArgs );
819 }
[64adb03]820 }
821
[2065609]822 void MutexKeyword::postvisit(StructDecl* decl) {
[102a58b]823
[ac2b598]824 if( decl->name == "$monitor" && decl->body ) {
[9243cc91]825 assert( !monitor_decl );
826 monitor_decl = decl;
827 }
[88d955f]828 else if( decl->name == "monitor_guard_t" && decl->body ) {
[ef42b143]829 assert( !guard_decl );
830 guard_decl = decl;
831 }
[88d955f]832 else if( decl->name == "monitor_dtor_guard_t" && decl->body ) {
[549c006]833 assert( !dtor_guard_decl );
834 dtor_guard_decl = decl;
835 }
[9243cc91]836 }
837
[db4d8e3]838 std::list<DeclarationWithType*> MutexKeyword::findMutexArgs( FunctionDecl* decl, bool & first ) {
[64adb03]839 std::list<DeclarationWithType*> mutexArgs;
840
[db4d8e3]841 bool once = true;
[64adb03]842 for( auto arg : decl->get_functionType()->get_parameters()) {
843 //Find mutex arguments
844 Type* ty = arg->get_type();
[615a096]845 if( ! ty->get_mutex() ) continue;
[64adb03]846
[db4d8e3]847 if(once) {first = true;}
848 once = false;
849
[64adb03]850 //Append it to the list
851 mutexArgs.push_back( arg );
852 }
853
854 return mutexArgs;
855 }
856
857 void MutexKeyword::validate( DeclarationWithType * arg ) {
858 Type* ty = arg->get_type();
859
860 //Makes sure it's not a copy
[870d1f0]861 ReferenceType* rty = dynamic_cast< ReferenceType * >( ty );
[a16764a6]862 if( ! rty ) SemanticError( arg, "Mutex argument must be of reference type " );
[64adb03]863
864 //Make sure the we are pointing directly to a type
[83a071f9]865 Type* base = rty->get_base();
[a16764a6]866 if( dynamic_cast< ReferenceType * >( base ) ) SemanticError( arg, "Mutex argument have exactly one level of indirection " );
867 if( dynamic_cast< PointerType * >( base ) ) SemanticError( arg, "Mutex argument have exactly one level of indirection " );
[64adb03]868
869 //Make sure that typed isn't mutex
[a16764a6]870 if( base->get_mutex() ) SemanticError( arg, "mutex keyword may only appear once per argument " );
[64adb03]871 }
872
[549c006]873 void MutexKeyword::addDtorStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
874 Type * arg_type = args.front()->get_type()->clone();
875 arg_type->set_mutex( false );
876
877 ObjectDecl * monitors = new ObjectDecl(
878 "__monitor",
[ba3706f]879 noStorageClasses,
[549c006]880 LinkageSpec::Cforall,
881 nullptr,
882 new PointerType(
883 noQualifiers,
884 new StructInstType(
885 noQualifiers,
886 monitor_decl
887 )
888 ),
889 new SingleInit( new UntypedExpr(
890 new NameExpr( "get_monitor" ),
[b81fd95]891 { new CastExpr( new VariableExpr( args.front() ), arg_type, false ) }
[549c006]892 ))
893 );
894
895 assert(generic_func);
896
897 //in reverse order :
[2bf7ef6]898 // monitor_dtor_guard_t __guard = { __monitors, func };
[549c006]899 body->push_front(
[ba3706f]900 new DeclStmt( new ObjectDecl(
[549c006]901 "__guard",
[ba3706f]902 noStorageClasses,
[549c006]903 LinkageSpec::Cforall,
904 nullptr,
905 new StructInstType(
906 noQualifiers,
907 dtor_guard_decl
908 ),
909 new ListInit(
910 {
911 new SingleInit( new AddressExpr( new VariableExpr( monitors ) ) ),
[b81fd95]912 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) )
[549c006]913 },
914 noDesignators,
915 true
916 )
917 ))
918 );
919
[ac2b598]920 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
[ba3706f]921 body->push_front( new DeclStmt( monitors) );
[549c006]922 }
923
[97e3296]924 void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
[9243cc91]925 ObjectDecl * monitors = new ObjectDecl(
926 "__monitors",
[ba3706f]927 noStorageClasses,
[9243cc91]928 LinkageSpec::Cforall,
929 nullptr,
930 new ArrayType(
931 noQualifiers,
932 new PointerType(
933 noQualifiers,
934 new StructInstType(
935 noQualifiers,
936 monitor_decl
937 )
938 ),
939 new ConstantExpr( Constant::from_ulong( args.size() ) ),
940 false,
941 false
942 ),
943 new ListInit(
[bd41764]944 map_range < std::list<Initializer*> > ( args, [](DeclarationWithType * var ){
[cb0e6de]945 Type * type = var->get_type()->clone();
946 type->set_mutex( false );
[9243cc91]947 return new SingleInit( new UntypedExpr(
948 new NameExpr( "get_monitor" ),
[b81fd95]949 { new CastExpr( new VariableExpr( var ), type, false ) }
[9243cc91]950 ) );
951 })
952 )
953 );
954
[97e3296]955 assert(generic_func);
956
[2bf7ef6]957 // in reverse order :
[97e3296]958 // monitor_guard_t __guard = { __monitors, #, func };
[64adb03]959 body->push_front(
[ba3706f]960 new DeclStmt( new ObjectDecl(
[64adb03]961 "__guard",
[ba3706f]962 noStorageClasses,
[64adb03]963 LinkageSpec::Cforall,
964 nullptr,
965 new StructInstType(
966 noQualifiers,
[ef42b143]967 guard_decl
[64adb03]968 ),
969 new ListInit(
970 {
[9243cc91]971 new SingleInit( new VariableExpr( monitors ) ),
[97e3296]972 new SingleInit( new ConstantExpr( Constant::from_ulong( args.size() ) ) ),
[b81fd95]973 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) )
[ef42b143]974 },
975 noDesignators,
976 true
[64adb03]977 )
978 ))
979 );
980
[ac2b598]981 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
[ba3706f]982 body->push_front( new DeclStmt( monitors) );
[64adb03]983 }
[bd4d011]984
985 //=============================================================================================
986 // General entry routine
987 //=============================================================================================
[549c006]988 void ThreadStarter::previsit( StructDecl * decl ) {
[ac2b598]989 if( decl->name == "$thread" && decl->body ) {
[549c006]990 assert( !thread_decl );
991 thread_decl = decl;
992 }
993 }
994
[2065609]995 void ThreadStarter::postvisit(FunctionDecl * decl) {
[9f5ecf5]996 if( ! CodeGen::isConstructor(decl->name) ) return;
[bd4d011]997
[549c006]998 Type * typeof_this = InitTweak::getTypeofThis(decl->type);
999 StructInstType * ctored_type = dynamic_cast< StructInstType * >( typeof_this );
1000 if( ctored_type && ctored_type->baseStruct == thread_decl ) {
1001 thread_ctor_seen = true;
1002 }
1003
[bd4d011]1004 DeclarationWithType * param = decl->get_functionType()->get_parameters().front();
[ce8c12f]1005 auto type = dynamic_cast< StructInstType * >( InitTweak::getPointerBase( param->get_type() ) );
[bd4d011]1006 if( type && type->get_baseStruct()->is_thread() ) {
[549c006]1007 if( !thread_decl || !thread_ctor_seen ) {
[73abe95]1008 SemanticError( type->get_baseStruct()->location, "thread keyword requires threads to be in scope, add #include <thread.hfa>");
[549c006]1009 }
1010
[bd4d011]1011 addStartStatement( decl, param );
1012 }
1013 }
1014
1015 void ThreadStarter::addStartStatement( FunctionDecl * decl, DeclarationWithType * param ) {
1016 CompoundStmt * stmt = decl->get_statements();
1017
1018 if( ! stmt ) return;
1019
[bf2438c]1020 stmt->push_back(
[bd4d011]1021 new ExprStmt(
1022 new UntypedExpr(
1023 new NameExpr( "__thrd_start" ),
[09f357ec]1024 { new VariableExpr( param ), new NameExpr("main") }
[bd4d011]1025 )
1026 )
1027 );
1028 }
[68fe077a]1029};
[6b0b624]1030
1031// Local Variables: //
1032// mode: c //
1033// tab-width: 4 //
1034// End: //
Note: See TracBrowser for help on using the repository browser.