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
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// 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 :
13// Update Count : 10
14//
15
16#include "Concurrency/Keywords.h"
17
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
36
37class Attribute;
38
39namespace Concurrency {
40 //=============================================================================================
41 // Pass declarations
42 //=============================================================================================
43
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 //
53 class ConcurrentSueKeyword : public WithDeclsToAdd {
54 public:
55
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 ) :
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 ) {}
58
59 virtual ~ConcurrentSueKeyword() {}
60
61 Declaration * postmutate( StructDecl * decl );
62 DeclarationWithType * postmutate( FunctionDecl * decl );
63
64 void handle( StructDecl * );
65 FunctionDecl * forwardDeclare( StructDecl * );
66 ObjectDecl * addField( StructDecl * );
67 void addRoutines( ObjectDecl *, FunctionDecl * );
68
69 virtual bool is_target( StructDecl * decl ) = 0;
70
71 Expression * postmutate( KeywordCastExpr * cast );
72
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;
78 bool needs_main;
79 AggregateDecl::Aggregate cast_target;
80
81 StructDecl * type_decl = nullptr;
82 FunctionDecl * dtor_decl = nullptr;
83 };
84
85
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;
91 // => $thread __thrd_d;
92 // }; };
93 // static inline $thread * get_thread( MyThread * this ) { return &this->__thrd_d; }
94 //
95 class ThreadKeyword final : public ConcurrentSueKeyword {
96 public:
97
98 ThreadKeyword() : ConcurrentSueKeyword(
99 "$thread",
100 "__thrd",
101 "get_thread",
102 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
103 true,
104 AggregateDecl::Thread
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 ) {
113 PassVisitor< ThreadKeyword > impl;
114 mutateAll( translationUnit, impl );
115 }
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;
123 // => $coroutine __cor_d;
124 // }; };
125 // static inline $coroutine * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
126 //
127 class CoroutineKeyword final : public ConcurrentSueKeyword {
128 public:
129
130 CoroutineKeyword() : ConcurrentSueKeyword(
131 "$coroutine",
132 "__cor",
133 "get_coroutine",
134 "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
135 true,
136 AggregateDecl::Coroutine
137 )
138 {}
139
140 virtual ~CoroutineKeyword() {}
141
142 virtual bool is_target( StructDecl * decl ) override final { return decl->is_coroutine(); }
143
144 static void implement( std::list< Declaration * > & translationUnit ) {
145 PassVisitor< CoroutineKeyword > impl;
146 mutateAll( translationUnit, impl );
147 }
148 };
149
150
151
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;
157 // => $monitor __mon_d;
158 // }; };
159 // static inline $monitor * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
160 //
161 class MonitorKeyword final : public ConcurrentSueKeyword {
162 public:
163
164 MonitorKeyword() : ConcurrentSueKeyword(
165 "$monitor",
166 "__mon",
167 "get_monitor",
168 "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
169 false,
170 AggregateDecl::Monitor
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 ) {
179 PassVisitor< MonitorKeyword > impl;
180 mutateAll( translationUnit, impl );
181 }
182 };
183
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
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 ) {
258 // $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
259 // monitor_guard_t __guard = { __monitors, 2 };
260 // /*Some code*/ => /*Some code*/
261 // } }
262 //
263 class MutexKeyword final {
264 public:
265
266 void postvisit( FunctionDecl * decl );
267 void postvisit( StructDecl * decl );
268
269 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first );
270 void validate( DeclarationWithType * );
271 void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
272 void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
273
274 static void implement( std::list< Declaration * > & translationUnit ) {
275 PassVisitor< MutexKeyword > impl;
276 acceptAll( translationUnit, impl );
277 }
278
279 private:
280 StructDecl* monitor_decl = nullptr;
281 StructDecl* guard_decl = nullptr;
282 StructDecl* dtor_guard_decl = nullptr;
283
284 static std::unique_ptr< Type > generic_func;
285 };
286
287 std::unique_ptr< Type > MutexKeyword::generic_func = std::unique_ptr< Type >(
288 new FunctionType(
289 noQualifiers,
290 true
291 )
292 );
293
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 ) {
297 // $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
298 // monitor_guard_t __guard = { __monitors, 2 };
299 // /*Some code*/ => /*Some code*/
300 // } }
301 //
302 class ThreadStarter final {
303 public:
304
305 void postvisit( FunctionDecl * decl );
306 void previsit ( StructDecl * decl );
307
308 void addStartStatement( FunctionDecl * decl, DeclarationWithType * param );
309
310 static void implement( std::list< Declaration * > & translationUnit ) {
311 PassVisitor< ThreadStarter > impl;
312 acceptAll( translationUnit, impl );
313 }
314
315 private :
316 bool thread_ctor_seen = false;
317 StructDecl * thread_decl = nullptr;
318 };
319
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 );
327 GeneratorKeyword ::implement( translationUnit );
328 SuspendKeyword ::implement( translationUnit );
329 }
330
331 void implementMutexFuncs( std::list< Declaration * > & translationUnit ) {
332 MutexKeyword ::implement( translationUnit );
333 }
334
335 void implementThreadStarter( std::list< Declaration * > & translationUnit ) {
336 ThreadStarter ::implement( translationUnit );
337 }
338
339 //=============================================================================================
340 // Generic keyword implementation
341 //=============================================================================================
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
353 Declaration * ConcurrentSueKeyword::postmutate(StructDecl * decl) {
354 if( decl->name == type_name && decl->body ) {
355 assert( !type_decl );
356 type_decl = decl;
357 }
358 else if ( is_target(decl) ) {
359 handle( decl );
360 }
361 return decl;
362 }
363
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
382 Expression * ConcurrentSueKeyword::postmutate( KeywordCastExpr * cast ) {
383 if ( cast_target == cast->target ) {
384 // convert (thread &)t to ($thread &)*get_thread(t), etc.
385 if( !type_decl ) SemanticError( cast, context_error );
386 if( !dtor_decl ) SemanticError( cast, context_error );
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;
391 }
392 return cast;
393 }
394
395
396 void ConcurrentSueKeyword::handle( StructDecl * decl ) {
397 if( ! decl->body ) return;
398
399 if( !type_decl ) SemanticError( decl, context_error );
400 if( !dtor_decl ) SemanticError( decl, context_error );
401
402 FunctionDecl * func = forwardDeclare( decl );
403 ObjectDecl * field = addField( decl );
404 addRoutines( field, func );
405 }
406
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
414 FunctionType * get_type = new FunctionType( noQualifiers, false );
415 ObjectDecl * this_decl = new ObjectDecl(
416 "this",
417 noStorageClasses,
418 LinkageSpec::Cforall,
419 nullptr,
420 new ReferenceType(
421 noQualifiers,
422 new StructInstType(
423 noQualifiers,
424 decl
425 )
426 ),
427 nullptr
428 );
429
430 get_type->get_parameters().push_back( this_decl->clone() );
431 get_type->get_returnVals().push_back(
432 new ObjectDecl(
433 "ret",
434 noStorageClasses,
435 LinkageSpec::Cforall,
436 nullptr,
437 new PointerType(
438 noQualifiers,
439 new StructInstType(
440 noQualifiers,
441 type_decl
442 )
443 ),
444 nullptr
445 )
446 );
447 fixupGenerics(get_type, decl);
448
449 FunctionDecl * get_decl = new FunctionDecl(
450 getter_name,
451 Type::Static,
452 LinkageSpec::Cforall,
453 get_type,
454 nullptr,
455 { new Attribute("const") },
456 Type::Inline
457 );
458
459 FunctionDecl * main_decl = nullptr;
460
461 if( needs_main ) {
462 FunctionType * main_type = new FunctionType( noQualifiers, false );
463
464 main_type->get_parameters().push_back( this_decl->clone() );
465
466 main_decl = new FunctionDecl(
467 "main",
468 noStorageClasses,
469 LinkageSpec::Cforall,
470 main_type,
471 nullptr
472 );
473 fixupGenerics(main_type, decl);
474 }
475
476 delete this_decl;
477
478 declsToAddBefore.push_back( forward );
479 if( needs_main ) declsToAddBefore.push_back( main_decl );
480 declsToAddBefore.push_back( get_decl );
481
482 return get_decl;
483 }
484
485 ObjectDecl * ConcurrentSueKeyword::addField( StructDecl * decl ) {
486 ObjectDecl * field = new ObjectDecl(
487 field_name,
488 noStorageClasses,
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
503 void ConcurrentSueKeyword::addRoutines( ObjectDecl * field, FunctionDecl * func ) {
504 CompoundStmt * statement = new CompoundStmt();
505 statement->push_back(
506 new ReturnStmt(
507 new AddressExpr(
508 new MemberExpr(
509 field,
510 new CastExpr(
511 new VariableExpr( func->get_functionType()->get_parameters().front() ),
512 func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone(),
513 false
514 )
515 )
516 )
517 )
518 );
519
520 FunctionDecl * get_decl = func->clone();
521
522 get_decl->set_statements( statement );
523
524 declsToAddAfter.push_back( get_decl );
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;
538
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;
554 }
555
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 ) );
748 expr->location = loc;
749
750 // Change this statement into a regular expr
751 assert(expr);
752 auto nstmt = new ExprStmt( expr );
753 nstmt->location = loc;
754 return nstmt;
755 }
756
757
758 //=============================================================================================
759 // Mutex keyword implementation
760 //=============================================================================================
761
762 void MutexKeyword::postvisit(FunctionDecl* decl) {
763
764 bool first = false;
765 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first );
766 bool isDtor = CodeGen::isDestructor( decl->name );
767
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 }
793
794 // Monitors can't be constructed with mutual exclusion
795 if( CodeGen::isConstructor(decl->name) && !first ) SemanticError( decl, "constructors cannot have mutex parameters" );
796
797 // It makes no sense to have multiple mutex parameters for the destructor
798 if( isDtor && mutexArgs.size() != 1 ) SemanticError( decl, "destructors can only have 1 mutex argument" );
799
800 // Make sure all the mutex arguments are monitors
801 for(auto arg : mutexArgs) {
802 validate( arg );
803 }
804
805 // Check if we need to instrument the body
806 CompoundStmt* body = decl->get_statements();
807 if( ! body ) return;
808
809 // Do we have the required headers
810 if( !monitor_decl || !guard_decl || !dtor_guard_decl )
811 SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor.hfa>\n" );
812
813 // Instrument the body
814 if( isDtor ) {
815 addDtorStatments( decl, body, mutexArgs );
816 }
817 else {
818 addStatments( decl, body, mutexArgs );
819 }
820 }
821
822 void MutexKeyword::postvisit(StructDecl* decl) {
823
824 if( decl->name == "$monitor" && decl->body ) {
825 assert( !monitor_decl );
826 monitor_decl = decl;
827 }
828 else if( decl->name == "monitor_guard_t" && decl->body ) {
829 assert( !guard_decl );
830 guard_decl = decl;
831 }
832 else if( decl->name == "monitor_dtor_guard_t" && decl->body ) {
833 assert( !dtor_guard_decl );
834 dtor_guard_decl = decl;
835 }
836 }
837
838 std::list<DeclarationWithType*> MutexKeyword::findMutexArgs( FunctionDecl* decl, bool & first ) {
839 std::list<DeclarationWithType*> mutexArgs;
840
841 bool once = true;
842 for( auto arg : decl->get_functionType()->get_parameters()) {
843 //Find mutex arguments
844 Type* ty = arg->get_type();
845 if( ! ty->get_mutex() ) continue;
846
847 if(once) {first = true;}
848 once = false;
849
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
861 ReferenceType* rty = dynamic_cast< ReferenceType * >( ty );
862 if( ! rty ) SemanticError( arg, "Mutex argument must be of reference type " );
863
864 //Make sure the we are pointing directly to a type
865 Type* base = rty->get_base();
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 " );
868
869 //Make sure that typed isn't mutex
870 if( base->get_mutex() ) SemanticError( arg, "mutex keyword may only appear once per argument " );
871 }
872
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",
879 noStorageClasses,
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" ),
891 { new CastExpr( new VariableExpr( args.front() ), arg_type, false ) }
892 ))
893 );
894
895 assert(generic_func);
896
897 //in reverse order :
898 // monitor_dtor_guard_t __guard = { __monitors, func };
899 body->push_front(
900 new DeclStmt( new ObjectDecl(
901 "__guard",
902 noStorageClasses,
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 ) ) ),
912 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) )
913 },
914 noDesignators,
915 true
916 )
917 ))
918 );
919
920 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
921 body->push_front( new DeclStmt( monitors) );
922 }
923
924 void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
925 ObjectDecl * monitors = new ObjectDecl(
926 "__monitors",
927 noStorageClasses,
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(
944 map_range < std::list<Initializer*> > ( args, [](DeclarationWithType * var ){
945 Type * type = var->get_type()->clone();
946 type->set_mutex( false );
947 return new SingleInit( new UntypedExpr(
948 new NameExpr( "get_monitor" ),
949 { new CastExpr( new VariableExpr( var ), type, false ) }
950 ) );
951 })
952 )
953 );
954
955 assert(generic_func);
956
957 // in reverse order :
958 // monitor_guard_t __guard = { __monitors, #, func };
959 body->push_front(
960 new DeclStmt( new ObjectDecl(
961 "__guard",
962 noStorageClasses,
963 LinkageSpec::Cforall,
964 nullptr,
965 new StructInstType(
966 noQualifiers,
967 guard_decl
968 ),
969 new ListInit(
970 {
971 new SingleInit( new VariableExpr( monitors ) ),
972 new SingleInit( new ConstantExpr( Constant::from_ulong( args.size() ) ) ),
973 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) )
974 },
975 noDesignators,
976 true
977 )
978 ))
979 );
980
981 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
982 body->push_front( new DeclStmt( monitors) );
983 }
984
985 //=============================================================================================
986 // General entry routine
987 //=============================================================================================
988 void ThreadStarter::previsit( StructDecl * decl ) {
989 if( decl->name == "$thread" && decl->body ) {
990 assert( !thread_decl );
991 thread_decl = decl;
992 }
993 }
994
995 void ThreadStarter::postvisit(FunctionDecl * decl) {
996 if( ! CodeGen::isConstructor(decl->name) ) return;
997
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
1004 DeclarationWithType * param = decl->get_functionType()->get_parameters().front();
1005 auto type = dynamic_cast< StructInstType * >( InitTweak::getPointerBase( param->get_type() ) );
1006 if( type && type->get_baseStruct()->is_thread() ) {
1007 if( !thread_decl || !thread_ctor_seen ) {
1008 SemanticError( type->get_baseStruct()->location, "thread keyword requires threads to be in scope, add #include <thread.hfa>");
1009 }
1010
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
1020 stmt->push_back(
1021 new ExprStmt(
1022 new UntypedExpr(
1023 new NameExpr( "__thrd_start" ),
1024 { new VariableExpr( param ), new NameExpr("main") }
1025 )
1026 )
1027 );
1028 }
1029};
1030
1031// Local Variables: //
1032// mode: c //
1033// tab-width: 4 //
1034// End: //
Note: See TracBrowser for help on using the repository browser.