source: src/Concurrency/Keywords.cc @ 18fe0fe

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 18fe0fe was ab8c6a6, checked in by Andrew Beach <ajbeach@…>, 4 years ago

Thread Cancellation, a test for it and a required fix to Specialization.

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