Changes in / [63be3387:b77f0e1]


Ignore:
Files:
2 added
27 deleted
72 edited

Legend:

Unmodified
Added
Removed
  • benchmark/io/http/worker.hfa

    r63be3387 rb77f0e1  
    22
    33#include <iofwd.hfa>
    4 #include <containers/lockfree.hfa>
     4#include <queueLockFree.hfa>
    55#include <thread.hfa>
    66
  • doc/theses/mike_brooks_MMath/programs/hello-md.cfa

    r63be3387 rb77f0e1  
    11#include "array.hfa"
     2
     3
     4trait ix( C &, E &, ztype(N) ) {
     5    E & ?[?]( C &, ptrdiff_t );
     6    void __taglen( tag(C), tag(N) );
     7};
     8
     9forall( ztype(Zn), ztype(S), Timmed &, Tbase & )
     10void __taglen( tag(arpk(Zn, S, Timmed, Tbase)), tag(Zn) ) {}
    211
    312
     
    2938
    3039
    31 
    32 
    33 
    34 
    35 
    36 
    37 
    38 
    39 
    40 forall( [N] )
     40forall( ztype( N ) )
    4141void print1d_cstyle( array(float, N) & c );
    4242
    43 forall( [N], C & | ar( C, float, N ) )
     43forall( C &, ztype( N ) | ix( C, float, N ) )
    4444void print1d( C & c );
    4545
     
    5858
    5959
    60 forall( [N] )
     60forall( ztype( N ) )
    6161void print1d_cstyle( array(float, N) & c ) {
    62     for( i; N ) {
     62    for( i; z(N) ) {
    6363        printf("%.1f  ", c[i]);
    6464    }
     
    7878
    7979
    80 forall( [N], C & | ar( C, float, N ) )
     80forall( C &, ztype( N ) | ix( C, float, N ) )
    8181void print1d( C & c ) {
    82     for( i; N ) {
     82    for( i; z(N) ) {
    8383        printf("%.1f  ", c[i]);
    8484    }
     
    9999
    100100
    101 void fill( array(float, 5, 7) & a ) {
     101void fill( array(float, Z(5), Z(7)) & a ) {
    102102    for ( i; (ptrdiff_t) 5 ) {
    103103        for ( j; 7 ) {
    104             a[i,j] = 1.0 * i + 0.1 * j;
    105             printf("%.1f  ", a[i,j]);
     104            a[[i,j]] = 1.0 * i + 0.1 * j;
     105            printf("%.1f  ", a[[i,j]]);
    106106        }
    107107        printf("\n");
     
    118118
    119119
    120 array( float, 5, 7 ) a;
     120array( float, Z(5), Z(7) ) a;
    121121fill(a);
    122122/*
     
    148148
    149149
    150 print1d( a[ 2, all ] );  // 2.0  2.1  2.2  2.3  2.4  2.5  2.6
    151 print1d( a[ all, 3 ] );  // 0.3  1.3  2.3  3.3  4.3
     150print1d( a[[ 2, all ]] );  // 2.0  2.1  2.2  2.3  2.4  2.5  2.6
     151print1d( a[[ all, 3 ]] );  // 0.3  1.3  2.3  3.3  4.3
    152152
    153153
    154154
    155 print1d_cstyle( a[ 2, all ] );
     155print1d_cstyle( a[[ 2, all ]] );
    156156
    157157
     
    161161
    162162
    163 #ifdef SHOW_ERROR_1
     163#ifdef SHOWERR1
    164164
    165 print1d_cstyle( a[ all, 2 ] );  // bad
     165print1d_cstyle( a[[ all, 2 ]] );  // bad
    166166
    167167#endif
  • doc/theses/thierry_delisle_PhD/thesis/text/front.tex

    r63be3387 rb77f0e1  
    161161Thanks to Andrew Beach, Michael Brooks, Colby Parsons, Mubeen Zulfiqar, Fangren Yu and Jiada Liang for their work on the \CFA project as well as all the discussions which have helped me concretize the ideas in this thesis.
    162162
    163 Finally, I acknowledge that this has been possible thanks to the financial help offered by the David R. Cheriton School of Computer Science, the corporate partnership with Huawei Ltd. and the Natural Sciences and Engineering Research Council.
     163Finally, I acknowledge that this has been possible thanks to the financial help offered by the David R. Cheriton School of Computer Science and the corporate partnership with Huawei Ltd.
    164164\cleardoublepage
    165165
  • libcfa/src/Makefile.am

    r63be3387 rb77f0e1  
    6262        containers/array.hfa \
    6363        containers/list.hfa \
    64         containers/lockfree.hfa \
     64        containers/queueLockFree.hfa \
     65        containers/stackLockFree.hfa \
    6566        containers/string_sharectx.hfa \
    6667        containers/vector2.hfa \
     
    111112        concurrency/invoke.h \
    112113        concurrency/future.hfa \
    113         concurrency/once.hfa \
    114114        concurrency/kernel/fwd.hfa \
    115115        concurrency/mutex_stmt.hfa
     
    127127
    128128thread_libsrc = ${inst_thread_headers_src} ${inst_thread_headers_src:.hfa=.cfa} \
    129         interpose_thread.cfa \
    130129        bits/signal.hfa \
    131130        concurrency/clib/cfathread.cfa \
     
    146145        concurrency/stats.cfa \
    147146        concurrency/stats.hfa \
    148         concurrency/stats.hfa \
    149         concurrency/pthread.cfa
     147        concurrency/stats.hfa
    150148
    151149else
  • libcfa/src/bits/containers.hfa

    r63be3387 rb77f0e1  
    152152
    153153                void append( __queue(T) & this, T * val ) with(this) {
    154                         verify(get_next( *val ) == 0p);
    155154                        verify(this.tail != 0p);
    156155                        verify(*this.tail == 1p);
  • libcfa/src/bits/defs.hfa

    r63be3387 rb77f0e1  
    3030#ifdef __cforall
    3131#define __cfa_anonymous_object(x) inline struct x
     32#define __cfa_dlink(x) inline dlink(x)
    3233#else
    3334#define __cfa_anonymous_object(x) struct x __cfa_anonymous_object
     35#define __cfa_dlink(x) struct { struct x * next; struct x * back; } __dlink_substitute
    3436#endif
    3537
  • libcfa/src/concurrency/clib/cfathread.cfa

    r63be3387 rb77f0e1  
    172172
    173173                pthread_attr_t attr;
    174                 if (int ret = __cfaabi_pthread_attr_init(&attr); 0 != ret) {
     174                if (int ret = pthread_attr_init(&attr); 0 != ret) {
    175175                        abort | "failed to create master epoll thread attr: " | ret | strerror(ret);
    176176                }
    177177
    178                 if (int ret = __cfaabi_pthread_create(&master_poller, &attr, master_epoll, 0p); 0 != ret) {
     178                if (int ret = pthread_create(&master_poller, &attr, master_epoll, 0p); 0 != ret) {
    179179                        abort | "failed to create master epoll thread: " | ret | strerror(ret);
    180180                }
  • libcfa/src/concurrency/invoke.h

    r63be3387 rb77f0e1  
    146146
    147147        // Link lists fields
    148         // instrusive link field for threads in the ready-queue
     148        // instrusive link field for threads
    149149        struct __thread_desc_link {
    150150                struct thread$ * next;
    151151                volatile unsigned long long ts;
    152152        };
    153 
    154         // Link lists fields
    155         // instrusive link field for threads in the user_link/cltr_link
    156         struct __thread_user_link {
    157                 #ifdef __cforall
    158                         inline dlink(thread$);
    159                 #else
    160                         struct thread$ * next; struct thread$ * back;
    161                 #endif
    162         };
    163         _Static_assert(sizeof(struct __thread_user_link) == 2 * sizeof(struct thread$ *), "__thread_user_link should be consistent in C and Cforall");
    164153
    165154        struct thread$ {
     
    170159                // Link lists fields
    171160                // instrusive link field for threads
    172                 struct __thread_desc_link rdy_link;
     161                struct __thread_desc_link link;
    173162
    174163                // current execution status for coroutine
     
    206195                struct __monitor_group_t monitors;
    207196
    208                 // intrusive link fields, used for locks, monitors and any user defined data structure
    209                 // default link fields for dlist
    210                 struct __thread_user_link user_link;
    211 
    212                 // secondary intrusive link fields, used for global cluster list
    213                 // default link fields for dlist
    214                 struct __thread_user_link cltr_link;
     197                // used to put threads on dlist data structure
     198                __cfa_dlink(thread$);
     199
     200                struct {
     201                        struct thread$ * next;
     202                        struct thread$ * prev;
     203                } node;
    215204
    216205                // used to store state between clh lock/unlock
     
    225214
    226215                #if defined( __CFA_WITH_VERIFY__ )
    227                         struct processor * volatile executing;
    228216                        void * canary;
    229217                #endif
    230218        };
    231 
     219        #ifdef __cforall
     220                P9_EMBEDDED( thread$, dlink(thread$) )
     221        #endif
    232222        // Wrapper for gdb
    233223        struct cfathread_thread_t { struct thread$ debug; };
     
    241231        #ifdef __cforall
    242232        extern "Cforall" {
    243                 static inline thread$ * volatile & ?`next ( thread$ * this ) {
    244                         return this->user_link.next;
    245                 }
    246233
    247234                static inline thread$ *& get_next( thread$ & this ) __attribute__((const)) {
    248                         return this.user_link.next;
    249                 }
    250 
    251                 static inline tytagref( dlink(thread$), dlink(thread$) ) ?`inner( thread$ & this ) {
    252                         dlink(thread$) & b = this.user_link;
    253                         tytagref( dlink(thread$), dlink(thread$) ) result = { b };
    254                         return result;
    255                 }
    256 
    257                 static inline tytagref(struct __thread_user_link, dlink(thread$)) ?`inner( struct thread$ & this ) {
    258                         struct __thread_user_link & ib = this.cltr_link;
    259                         dlink(thread$) & b = ib`inner;
    260                         tytagref(struct __thread_user_link, dlink(thread$)) result = { b };
    261                         return result;
    262                 }
    263 
    264                 P9_EMBEDDED(struct __thread_user_link, dlink(thread$))
     235                        return this.link.next;
     236                }
     237
     238                static inline [thread$ *&, thread$ *& ] __get( thread$ & this ) __attribute__((const)) {
     239                        return this.node.[next, prev];
     240                }
    265241
    266242                static inline void ?{}(__monitor_group_t & this) {
  • libcfa/src/concurrency/io.cfa

    r63be3387 rb77f0e1  
    610610                if( we ) {
    611611                        sigval_t value = { PREEMPT_IO };
    612                         __cfaabi_pthread_sigqueue(ctx->proc->kernel_thread, SIGUSR1, value);
     612                        pthread_sigqueue(ctx->proc->kernel_thread, SIGUSR1, value);
    613613                }
    614614
     
    639639                }
    640640        }
     641
     642        #if defined(CFA_WITH_IO_URING_IDLE)
     643                bool __kernel_read(struct processor * proc, io_future_t & future, iovec & iov, int fd) {
     644                        io_context$ * ctx = proc->io.ctx;
     645                        /* paranoid */ verify( ! __preemption_enabled() );
     646                        /* paranoid */ verify( proc == __cfaabi_tls.this_processor );
     647                        /* paranoid */ verify( ctx );
     648
     649                        __u32 idx;
     650                        struct io_uring_sqe * sqe;
     651
     652                        // We can proceed to the fast path
     653                        if( !__alloc(ctx, &idx, 1) ) {
     654                                /* paranoid */ verify( false ); // for now check if this happens, next time just abort the sleep.
     655                                return false;
     656                        }
     657
     658                        // Allocation was successful
     659                        __fill( &sqe, 1, &idx, ctx );
     660
     661                        sqe->user_data = (uintptr_t)&future;
     662                        sqe->flags = 0;
     663                        sqe->fd = fd;
     664                        sqe->off = 0;
     665                        sqe->ioprio = 0;
     666                        sqe->fsync_flags = 0;
     667                        sqe->__pad2[0] = 0;
     668                        sqe->__pad2[1] = 0;
     669                        sqe->__pad2[2] = 0;
     670
     671                        #if defined(CFA_HAVE_IORING_OP_READ)
     672                                sqe->opcode = IORING_OP_READ;
     673                                sqe->addr = (uint64_t)iov.iov_base;
     674                                sqe->len = iov.iov_len;
     675                        #elif defined(CFA_HAVE_READV) && defined(CFA_HAVE_IORING_OP_READV)
     676                                sqe->opcode = IORING_OP_READV;
     677                                sqe->addr = (uintptr_t)&iov;
     678                                sqe->len = 1;
     679                        #else
     680                                #error CFA_WITH_IO_URING_IDLE but none of CFA_HAVE_READV, CFA_HAVE_IORING_OP_READV or CFA_HAVE_IORING_OP_READ defined
     681                        #endif
     682
     683                        asm volatile("": : :"memory");
     684
     685                        /* paranoid */ verify( sqe->user_data == (uintptr_t)&future );
     686                        __submit_only( ctx, &idx, 1 );
     687
     688                        /* paranoid */ verify( proc == __cfaabi_tls.this_processor );
     689                        /* paranoid */ verify( ! __preemption_enabled() );
     690
     691                        return true;
     692                }
     693
     694                void __cfa_io_idle( struct processor * proc ) {
     695                        iovec iov;
     696                        __atomic_acquire( &proc->io.ctx->cq.lock );
     697
     698                        __attribute__((used)) volatile bool was_reset = false;
     699
     700                        with( proc->idle_wctx) {
     701
     702                                // Do we already have a pending read
     703                                if(available(*ftr)) {
     704                                        // There is no pending read, we need to add one
     705                                        reset(*ftr);
     706
     707                                        iov.iov_base = rdbuf;
     708                                        iov.iov_len  = sizeof(eventfd_t);
     709                                        __kernel_read(proc, *ftr, iov, evfd );
     710                                        ftr->result = 0xDEADDEAD;
     711                                        *((eventfd_t *)rdbuf) = 0xDEADDEADDEADDEAD;
     712                                        was_reset = true;
     713                                }
     714                        }
     715
     716                        if( !__atomic_load_n( &proc->do_terminate, __ATOMIC_SEQ_CST ) ) {
     717                                __ioarbiter_flush( *proc->io.ctx );
     718                                proc->idle_wctx.sleep_time = rdtscl();
     719                                ioring_syscsll( *proc->io.ctx, 1, IORING_ENTER_GETEVENTS);
     720                        }
     721
     722                        ready_schedule_lock();
     723                        __cfa_do_drain( proc->io.ctx, proc->cltr );
     724                        ready_schedule_unlock();
     725
     726                        asm volatile ("" :: "m" (was_reset));
     727                }
     728        #endif
    641729#endif
  • libcfa/src/concurrency/io/setup.cfa

    r63be3387 rb77f0e1  
    3434        bool __cfa_io_flush( processor * proc ) { return false; }
    3535        bool __cfa_io_drain( processor * proc ) __attribute__((nonnull (1))) { return false; }
     36        void __cfa_io_idle ( processor * ) __attribute__((nonnull (1))) {}
    3637        void __cfa_io_stop ( processor * proc ) {}
    3738
     
    316317        }
    317318
     319//=============================================================================================
     320// I/O Context Sleep
     321//=============================================================================================
     322        // static inline void __epoll_ctl(io_context$ & ctx, int op, const char * error) {
     323        //      struct epoll_event ev;
     324        //      ev.events = EPOLLIN | EPOLLONESHOT;
     325        //      ev.data.u64 = (__u64)&ctx;
     326        //      int ret = epoll_ctl(iopoll.epollfd, op, ctx.efd, &ev);
     327        //      if (ret < 0) {
     328        //              abort( "KERNEL ERROR: EPOLL %s - (%d) %s\n", error, (int)errno, strerror(errno) );
     329        //      }
     330        // }
     331
     332        // static void __epoll_register(io_context$ & ctx) {
     333        //      __epoll_ctl(ctx, EPOLL_CTL_ADD, "ADD");
     334        // }
     335
     336        // static void __epoll_unregister(io_context$ & ctx) {
     337        //      // Read the current epoch so we know when to stop
     338        //      size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST);
     339
     340        //      // Remove the fd from the iopoller
     341        //      __epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE");
     342
     343        //      // Notify the io poller thread of the shutdown
     344        //      iopoll.run = false;
     345        //      sigval val = { 1 };
     346        //      pthread_sigqueue( iopoll.thrd, SIGUSR1, val );
     347
     348        //      // Make sure all this is done
     349        //      __atomic_thread_fence(__ATOMIC_SEQ_CST);
     350
     351        //      // Wait for the next epoch
     352        //      while(curr == iopoll.epoch && !iopoll.stopped) Pause();
     353        // }
     354
     355        // void __ioctx_prepare_block(io_context$ & ctx) {
     356        //      __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Re-arming io poller %d (%p)\n", ctx.fd, &ctx);
     357        //      __epoll_ctl(ctx, EPOLL_CTL_MOD, "REARM");
     358        // }
     359
    318360
    319361//=============================================================================================
  • libcfa/src/concurrency/kernel.cfa

    r63be3387 rb77f0e1  
    138138extern bool __cfa_io_drain( processor * proc ) __attribute__((nonnull (1)));
    139139extern bool __cfa_io_flush( processor * ) __attribute__((nonnull (1)));
    140 
     140extern void __cfa_io_idle( processor * ) __attribute__((nonnull (1)));
     141
     142#if defined(CFA_WITH_IO_URING_IDLE)
     143        extern bool __kernel_read(processor * proc, io_future_t & future, iovec &, int fd);
     144#endif
    141145
    142146extern void __disable_interrupts_hard();
     
    158162        verify(this);
    159163
     164        /* paranoid */ verify( this->idle_wctx.ftr   != 0p );
     165        /* paranoid */ verify( this->idle_wctx.rdbuf != 0p );
     166
     167        // used for idle sleep when io_uring is present
     168        // mark it as already fulfilled so we know if there is a pending request or not
     169        this->idle_wctx.ftr->self.ptr = 1p;
     170
    160171        __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this);
    161172        #if !defined(__CFA_NO_STATISTICS__)
     
    280291        /* paranoid */ verify( ! __preemption_enabled() );
    281292        /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted);
    282         /* paranoid */ verifyf( thrd_dst->rdy_link.next == 0p, "Expected null got %p", thrd_dst->rdy_link.next );
     293        /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next );
    283294        __builtin_prefetch( thrd_dst->context.SP );
    284295
     
    310321                /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->curr_cor == proc_cor || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); // add escape condition if we are setting up the processor
    311322                /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->curr_cor == proc_cor || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); // add escape condition if we are setting up the processor
    312                 /* paranoid */ verify( __atomic_exchange_n( &thrd_dst->executing, this, __ATOMIC_SEQ_CST) == 0p );
    313323                /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary );
    314324
     
    322332
    323333                /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary );
    324                 /* paranoid */ verify( __atomic_exchange_n( &thrd_dst->executing, 0p, __ATOMIC_SEQ_CST) == this );
    325334                /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too large.\n", thrd_dst );
    326335                /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too small.\n", thrd_dst );
    327                 /* paranoid */ verify( thrd_dst->state != Halted );
    328336                /* paranoid */ verify( thrd_dst->context.SP );
     337                /* paranoid */ verify( thrd_dst->curr_cluster == this->cltr );
    329338                /* paranoid */ verify( kernelTLS().this_thread == thrd_dst );
    330339                /* paranoid */ verify( ! __preemption_enabled() );
     
    443452                                        "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted );
    444453        /* paranoid */ #endif
    445         /* paranoid */ verifyf( thrd->rdy_link.next == 0p, "Expected null got %p", thrd->rdy_link.next );
     454        /* paranoid */ verifyf( thrd->link.next == 0p, "Expected null got %p", thrd->link.next );
    446455        /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary );
    447456
     
    591600                /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) < ((uintptr_t)__get_stack(thrd->curr_cor)->base ), "ERROR : thread$ %p has been corrupted.\n StackPointer too small.\n", thrd );
    592601
     602                thrd->state = Halting;
    593603                if( TICKET_RUNNING != thrd->ticket ) { abort( "Thread terminated with pending unpark" ); }
    594604                if( thrd != this->owner ) { abort( "Thread internal monitor has incorrect owner" ); }
    595605                if( this->recursion != 1) { abort( "Thread internal monitor has unbalanced recursion" ); }
    596 
    597                 thrd->state = Halting;
    598                 thrd->ticket = TICKET_DEAD;
    599606
    600607                // Leave the thread
     
    617624                // If that is the case, abandon the preemption.
    618625                bool preempted = false;
    619                 if(thrd->rdy_link.next == 0p) {
     626                if(thrd->link.next == 0p) {
    620627                        preempted = true;
    621628                        thrd->preempted = reason;
     
    719726
    720727
    721         #if !defined(__CFA_NO_STATISTICS__)
    722                 if(this->print_halts) {
    723                         __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl());
    724                 }
    725         #endif
    726 
    727         __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd);
    728 
    729         {
    730                 eventfd_t val;
    731                 ssize_t ret = read( this->idle_wctx.evfd, &val, sizeof(val) );
    732                 if(ret < 0) {
    733                         switch((int)errno) {
    734                         case EAGAIN:
    735                         #if EAGAIN != EWOULDBLOCK
    736                                 case EWOULDBLOCK:
    737                         #endif
    738                         case EINTR:
    739                                 // No need to do anything special here, just assume it's a legitimate wake-up
    740                                 break;
    741                         default:
    742                                 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );
     728        #if !defined(CFA_WITH_IO_URING_IDLE)
     729                #if !defined(__CFA_NO_STATISTICS__)
     730                        if(this->print_halts) {
     731                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl());
    743732                        }
    744                 }
    745         }
    746 
    747         #if !defined(__CFA_NO_STATISTICS__)
    748                 if(this->print_halts) {
    749                         __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl());
    750                 }
     733                #endif
     734
     735                __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd);
     736
     737                {
     738                        eventfd_t val;
     739                        ssize_t ret = read( this->idle_wctx.evfd, &val, sizeof(val) );
     740                        if(ret < 0) {
     741                                switch((int)errno) {
     742                                case EAGAIN:
     743                                #if EAGAIN != EWOULDBLOCK
     744                                        case EWOULDBLOCK:
     745                                #endif
     746                                case EINTR:
     747                                        // No need to do anything special here, just assume it's a legitimate wake-up
     748                                        break;
     749                                default:
     750                                        abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );
     751                                }
     752                        }
     753                }
     754
     755                #if !defined(__CFA_NO_STATISTICS__)
     756                        if(this->print_halts) {
     757                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl());
     758                        }
     759                #endif
     760        #else
     761                __cfa_io_idle( this );
    751762        #endif
    752763}
     
    764775                insert_first(this.idles, proc);
    765776
    766                 // update the pointer to the head wait context, which should now point to this proc.
    767777                __atomic_store_n(&this.fdw, &proc.idle_wctx, __ATOMIC_SEQ_CST);
    768778        unlock( this );
     
    781791
    782792                {
    783                         // update the pointer to the head wait context
    784793                        struct __fd_waitctx * wctx = 0;
    785794                        if(!this.idles`isEmpty) wctx = &this.idles`first.idle_wctx;
  • libcfa/src/concurrency/kernel.hfa

    r63be3387 rb77f0e1  
    6464        // 1 - means the proc should wake-up immediately
    6565        // FD - means the proc is going asleep and should be woken by writing to the FD.
    66         //      The FD value should always be the evfd field just below.
    6766        volatile int sem;
    6867
     
    7069        int evfd;
    7170
    72         // Used for debugging, should be removed eventually.
     71        // buffer into which the proc will read from evfd
     72        // unused if not using io_uring for idle sleep
     73        void * rdbuf;
     74
     75        // future use to track the read of the eventfd
     76        // unused if not using io_uring for idle sleep
     77        io_future_t * ftr;
     78
    7379        volatile unsigned long long wake__time;
    7480        volatile unsigned long long sleep_time;
     
    154160// P9_EMBEDDED( processor, dlink(processor) )
    155161static inline tytagref( dlink(processor), dlink(processor) ) ?`inner( processor & this ) {
    156         dlink(processor) & b = this.link;
    157         tytagref( dlink(processor), dlink(processor) ) result = { b };
    158         return result;
     162    dlink(processor) & b = this.link;
     163    tytagref( dlink(processor), dlink(processor) ) result = { b };
     164    return result;
    159165}
    160166
     
    250256        // List of threads
    251257        __spinlock_t thread_list_lock;
    252         dlist(struct thread$, struct __thread_user_link) threads;
     258        __dllist_t(struct thread$) threads;
    253259        unsigned int nthreads;
    254260
     
    263269                io_context_params params;
    264270        } io;
    265 
    266         struct {
    267                 struct processor ** procs;
    268                 unsigned cnt;
    269         } managed;
    270271
    271272        #if !defined(__CFA_NO_STATISTICS__)
     
    297298static inline struct cluster   * active_cluster  () { return publicTLS_get( this_processor )->cltr; }
    298299
    299 // set the number of internal processors
    300 // these processors are in addition to any explicitly declared processors
    301 unsigned set_concurrency( cluster & this, unsigned new_count );
    302 
    303300#if !defined(__CFA_NO_STATISTICS__)
    304301        void print_stats_now( cluster & this, int flags );
  • libcfa/src/concurrency/kernel/cluster.cfa

    r63be3387 rb77f0e1  
    483483
    484484        // We add a boat-load of assertions here because the anchor code is very fragile
    485         /* paranoid */ _Static_assert( offsetof( thread$, rdy_link ) == nested_offsetof(__intrusive_lane_t, l.anchor) );
    486         /* paranoid */ verify( offsetof( thread$, rdy_link ) == nested_offsetof(__intrusive_lane_t, l.anchor) );
    487         /* paranoid */ verify( ((uintptr_t)( mock_head(this) ) + offsetof( thread$, rdy_link )) == (uintptr_t)(&this.l.anchor) );
    488         /* paranoid */ verify( &mock_head(this)->rdy_link.next == &this.l.anchor.next );
    489         /* paranoid */ verify( &mock_head(this)->rdy_link.ts   == &this.l.anchor.ts   );
    490         /* paranoid */ verify( mock_head(this)->rdy_link.next == 0p );
    491         /* paranoid */ verify( mock_head(this)->rdy_link.ts   == MAX );
     485        /* paranoid */ _Static_assert( offsetof( thread$, link ) == nested_offsetof(__intrusive_lane_t, l.anchor) );
     486        /* paranoid */ verify( offsetof( thread$, link ) == nested_offsetof(__intrusive_lane_t, l.anchor) );
     487        /* paranoid */ verify( ((uintptr_t)( mock_head(this) ) + offsetof( thread$, link )) == (uintptr_t)(&this.l.anchor) );
     488        /* paranoid */ verify( &mock_head(this)->link.next == &this.l.anchor.next );
     489        /* paranoid */ verify( &mock_head(this)->link.ts   == &this.l.anchor.ts   );
     490        /* paranoid */ verify( mock_head(this)->link.next == 0p );
     491        /* paranoid */ verify( mock_head(this)->link.ts   == MAX );
    492492        /* paranoid */ verify( mock_head(this) == this.l.prev );
    493493        /* paranoid */ verify( __alignof__(__intrusive_lane_t) == 64 );
  • libcfa/src/concurrency/kernel/private.hfa

    r63be3387 rb77f0e1  
    2020#endif
    2121
    22 #include <signal.h>
    23 
    2422#include "kernel.hfa"
    2523#include "thread.hfa"
     
    4139}
    4240
     41// Defines whether or not we *want* to use io_uring_enter as the idle_sleep blocking call
     42// #define CFA_WANT_IO_URING_IDLE
     43
     44// Defines whether or not we *can* use io_uring_enter as the idle_sleep blocking call
     45#if defined(CFA_WANT_IO_URING_IDLE) && defined(CFA_HAVE_LINUX_IO_URING_H)
     46        #if defined(CFA_HAVE_IORING_OP_READ) || (defined(CFA_HAVE_READV) && defined(CFA_HAVE_IORING_OP_READV))
     47                #define CFA_WITH_IO_URING_IDLE
     48        #endif
     49#endif
     50
    4351// #define READYQ_USE_LINEAR_AVG
    4452#define READYQ_USE_LOGDBL_AVG
     
    5563#endif
    5664
    57 extern "C" {
    58         __attribute__((visibility("protected"))) int __cfaabi_pthread_create(pthread_t *_thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
    59         __attribute__((visibility("protected"))) int __cfaabi_pthread_join(pthread_t _thread, void **retval);
    60         __attribute__((visibility("protected"))) pthread_t __cfaabi_pthread_self(void);
    61         __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_init(pthread_attr_t *attr);
    62         __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_destroy(pthread_attr_t *attr);
    63         __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_setstack( pthread_attr_t *attr, void *stackaddr, size_t stacksize );
    64         __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_getstacksize( const pthread_attr_t *attr, size_t *stacksize );
    65         __attribute__((visibility("protected"))) int __cfaabi_pthread_sigqueue(pthread_t _thread, int sig, const union sigval value);
    66         __attribute__((visibility("protected"))) int __cfaabi_pthread_sigmask( int how, const sigset_t *set, sigset_t *oset);
    67 }
    68 
    6965//-----------------------------------------------------------------------------
    7066// Scheduler
     
    157153#define TICKET_RUNNING ( 0) // thread is running
    158154#define TICKET_UNBLOCK ( 1) // thread should ignore next block
    159 #define TICKET_DEAD    (0xDEAD) // thread should never be unparked
    160155
    161156//-----------------------------------------------------------------------------
  • libcfa/src/concurrency/kernel/startup.cfa

    r63be3387 rb77f0e1  
    1616#define __cforall_thread__
    1717#define _GNU_SOURCE
    18 
    19 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
    2018
    2119// C Includes
     
    115113KERNEL_STORAGE(thread$,              mainThread);
    116114KERNEL_STORAGE(__stack_t,            mainThreadCtx);
     115// KERNEL_STORAGE(__scheduler_RWLock_t, __scheduler_lock);
     116KERNEL_STORAGE(eventfd_t,            mainIdleEventFd);
     117KERNEL_STORAGE(io_future_t,          mainIdleFuture);
    117118#if !defined(__CFA_NO_STATISTICS__)
    118119KERNEL_STORAGE(__stats_t, mainProcStats);
     
    221222                ( this.runner ){};
    222223                init( this, "Main Processor", *mainCluster, 0p );
    223                 kernel_thread = __cfaabi_pthread_self();
     224                kernel_thread = pthread_self();
    224225
    225226                runner{ &this };
     
    231232        mainProcessor = (processor *)&storage_mainProcessor;
    232233        (*mainProcessor){};
     234
     235        mainProcessor->idle_wctx.rdbuf = &storage_mainIdleEventFd;
     236        mainProcessor->idle_wctx.ftr   = (io_future_t*)&storage_mainIdleFuture;
     237        /* paranoid */ verify( sizeof(storage_mainIdleEventFd) == sizeof(eventfd_t) );
    233238
    234239        __cfa_io_start( mainProcessor );
     
    278283}
    279284
    280 extern "C"{
    281         void pthread_delete_kernel_threads_();
    282 }
    283 
    284 
    285285static void __kernel_shutdown(void) {
    286286        if(!cfa_main_returned) return;
    287 
    288         //delete kernel threads for pthread_concurrency
    289         pthread_delete_kernel_threads_();
    290 
    291287        /* paranoid */ verify( __preemption_enabled() );
    292288        disable_interrupts();
     
    331327
    332328                /* paranoid */ verify( this.do_terminate == true );
    333                 __cfadbg_print_safe(runtime_core, "Kernel : destroyed main processor context %p\n", &runner);
     329                __cfaabi_dbg_print_safe("Kernel : destroyed main processor context %p\n", &runner);
    334330        }
    335331
     
    377373        register_tls( proc );
    378374
     375        // used for idle sleep when io_uring is present
     376        io_future_t future;
     377        eventfd_t idle_buf;
     378        proc->idle_wctx.ftr = &future;
     379        proc->idle_wctx.rdbuf = &idle_buf;
     380
     381
    379382        // SKULLDUGGERY: We want to create a context for the processor coroutine
    380383        // which is needed for the 2-step context switch. However, there is no reason
     
    385388        (proc->runner){ proc, &info };
    386389
    387         __cfadbg_print_safe(runtime_core, "Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);
     390        __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);
    388391
    389392        //Set global state
     
    511514        self_mon.recursion = 1;
    512515        self_mon_p = &self_mon;
    513         rdy_link.next = 0p;
    514         rdy_link.ts   = MAX;
     516        link.next = 0p;
     517        link.ts   = MAX;
    515518        preferred = ready_queue_new_preferred();
    516519        last_proc = 0p;
    517520        random_state = __global_random_mask ? __global_random_prime : __global_random_prime ^ rdtscl();
    518521        #if defined( __CFA_WITH_VERIFY__ )
    519                 executing = 0p;
    520522                canary = 0x0D15EA5E0D15EA5Ep;
    521523        #endif
    522524
     525        node.next = 0p;
     526        node.prev = 0p;
    523527        doregister(curr_cluster, this);
    524528
     
    643647        #endif
    644648
    645         threads{};
     649        threads{ __get };
    646650
    647651        io.arbiter = create();
    648652        io.params = io_params;
    649 
    650         managed.procs = 0p;
    651         managed.cnt = 0;
    652653
    653654        doregister(this);
     
    666667
    667668void ^?{}(cluster & this) libcfa_public {
    668         set_concurrency( this, 0 );
    669 
    670669        destroy(this.io.arbiter);
    671670
     
    723722        lock      (cltr->thread_list_lock __cfaabi_dbg_ctx2);
    724723        cltr->nthreads += 1;
    725         insert_first(cltr->threads, thrd);
     724        push_front(cltr->threads, thrd);
    726725        unlock    (cltr->thread_list_lock);
    727726}
     
    729728void unregister( cluster * cltr, thread$ & thrd ) {
    730729        lock  (cltr->thread_list_lock __cfaabi_dbg_ctx2);
    731         {
    732                 tytagref( dlink(thread$), dlink(thread$) ) ?`inner( thread$ & this ) = void;
    733                 with( DLINK_VIA( thread$, struct __thread_user_link ) )
    734                         remove( thrd );
    735                 cltr->nthreads -= 1;
    736         }
     730        remove(cltr->threads, thrd );
     731        cltr->nthreads -= 1;
    737732        unlock(cltr->thread_list_lock);
    738733}
     
    782777        pthread_attr_t attr;
    783778
    784         check( __cfaabi_pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
     779        check( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
    785780
    786781        size_t stacksize = max( PTHREAD_STACK_MIN, DEFAULT_STACK_SIZE );
     
    809804        #endif
    810805
    811         check( __cfaabi_pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" );
    812         check( __cfaabi_pthread_create( pthread, &attr, start, arg ), "pthread_create" );
     806        check( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" );
     807        check( pthread_create( pthread, &attr, start, arg ), "pthread_create" );
    813808        return stack;
    814809}
    815810
    816811void __destroy_pthread( pthread_t pthread, void * stack, void ** retval ) {
    817         int err = __cfaabi_pthread_join( pthread, retval );
     812        int err = pthread_join( pthread, retval );
    818813        if( err != 0 ) abort("KERNEL ERROR: joining pthread %p caused error %s\n", (void*)pthread, strerror(err));
    819814
     
    821816                pthread_attr_t attr;
    822817
    823                 check( __cfaabi_pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
     818                check( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
    824819
    825820                size_t stacksize;
    826821                // default stack size, normally defined by shell limit
    827                 check( __cfaabi_pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" );
     822                check( pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" );
    828823                assert( stacksize >= PTHREAD_STACK_MIN );
    829824                stacksize += __page_size;
     
    843838}
    844839
    845 unsigned set_concurrency( cluster & this, unsigned new ) libcfa_public {
    846         unsigned old = this.managed.cnt;
    847 
    848         __cfadbg_print_safe(runtime_core, "Kernel : resizing cluster from %u to %u\n", old, (unsigned)new);
    849 
    850         // Delete all the old unneeded procs
    851         if(old > new) for(i; (unsigned)new ~ old) {
    852                 __cfadbg_print_safe(runtime_core, "Kernel : destroying %u\n", i);
    853                 delete( this.managed.procs[i] );
    854         }
    855 
    856         // Allocate new array (uses realloc and memcpies the data)
    857         this.managed.procs = alloc( new, this.managed.procs`realloc );
    858         this.managed.cnt = new;
    859 
    860         // Create the desired new procs
    861         if(old < new) for(i; old ~ new) {
    862                 __cfadbg_print_safe(runtime_core, "Kernel : constructing %u\n", i);
    863                 (*(this.managed.procs[i] = alloc())){ this };
    864         }
    865 
    866         // return the old count
    867         return old;
    868 }
    869 
    870840#if defined(__CFA_WITH_VERIFY__)
    871841static bool verify_fwd_bck_rng(void) {
  • libcfa/src/concurrency/locks.hfa

    r63be3387 rb77f0e1  
    2121
    2222#include "bits/weakso_locks.hfa"
    23 #include "containers/lockfree.hfa"
     23#include "containers/queueLockFree.hfa"
    2424#include "containers/list.hfa"
    2525
     
    498498}
    499499
    500 static inline size_t on_wait(simple_owner_lock & this) with(this) {
     500static inline size_t on_wait(simple_owner_lock & this) with(this) { 
    501501        lock( lock __cfaabi_dbg_ctx2 );
    502502        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
  • libcfa/src/concurrency/monitor.cfa

    r63be3387 rb77f0e1  
    122122
    123123                // Some one else has the monitor, wait in line for it
    124                 /* paranoid */ verify( thrd->user_link.next == 0p );
     124                /* paranoid */ verify( thrd->link.next == 0p );
    125125                append( this->entry_queue, thrd );
    126                 /* paranoid */ verify( thrd->user_link.next == 1p );
     126                /* paranoid */ verify( thrd->link.next == 1p );
    127127
    128128                unlock( this->lock );
     
    233233
    234234                // Some one else has the monitor, wait in line for it
    235                 /* paranoid */ verify( thrd->user_link.next == 0p );
     235                /* paranoid */ verify( thrd->link.next == 0p );
    236236                append( this->entry_queue, thrd );
    237                 /* paranoid */ verify( thrd->user_link.next == 1p );
     237                /* paranoid */ verify( thrd->link.next == 1p );
    238238                unlock( this->lock );
    239239
     
    791791        thread$ * new_owner = pop_head( this->entry_queue );
    792792        /* paranoid */ verifyf( !this->owner || active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    793         /* paranoid */ verify( !new_owner || new_owner->user_link.next == 0p );
     793        /* paranoid */ verify( !new_owner || new_owner->link.next == 0p );
    794794        __set_owner( this, new_owner );
    795795
     
    935935        __queue_t(thread$) & entry_queue = monitors[0]->entry_queue;
    936936
    937         #if defined( __CFA_WITH_VERIFY__ )
    938                 thread$ * last = 0p;
    939         #endif
    940937        // For each thread in the entry-queue
    941938        for(    thread$ ** thrd_it = &entry_queue.head;
    942939                (*thrd_it) != 1p;
    943                 thrd_it = &get_next(**thrd_it)
     940                thrd_it = &(*thrd_it)->link.next
    944941        ) {
    945                 thread$ * curr = *thrd_it;
    946 
    947                 /* paranoid */ verifyf( !last || last->user_link.next == curr, "search not making progress, from %p (%p) to %p", last, last->user_link.next, curr );
    948                 /* paranoid */ verifyf( curr != last, "search not making progress, from %p to %p", last, curr );
    949 
    950942                // For each acceptable check if it matches
    951943                int i = 0;
     
    954946                for( __acceptable_t * it = begin; it != end; it++, i++ ) {
    955947                        // Check if we have a match
    956                         if( *it == curr->monitors ) {
     948                        if( *it == (*thrd_it)->monitors ) {
    957949
    958950                                // If we have a match return it
     
    961953                        }
    962954                }
    963 
    964                 #if defined( __CFA_WITH_VERIFY__ )
    965                         last = curr;
    966                 #endif
    967955        }
    968956
     
    10371025
    10381026                // Some one else has the monitor, wait in line for it
    1039                 /* paranoid */ verify( thrd->user_link.next == 0p );
     1027                /* paranoid */ verify( thrd->link.next == 0p );
    10401028                append( this->entry_queue, thrd );
    1041                 /* paranoid */ verify( thrd->user_link.next == 1p );
     1029                /* paranoid */ verify( thrd->link.next == 1p );
    10421030
    10431031                unlock( this->lock );
  • libcfa/src/concurrency/preemption.cfa

    r63be3387 rb77f0e1  
    352352        sigset_t oldset;
    353353        int ret;
    354         ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
     354        ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
    355355        if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    356356
     
    385385        sigaddset( &mask, sig );
    386386
    387         if ( __cfaabi_pthread_sigmask( SIG_UNBLOCK, &mask, 0p ) == -1 ) {
     387        if ( pthread_sigmask( SIG_UNBLOCK, &mask, 0p ) == -1 ) {
    388388            abort( "internal error, pthread_sigmask" );
    389389        }
     
    396396        sigaddset( &mask, sig );
    397397
    398         if ( __cfaabi_pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
     398        if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
    399399                abort( "internal error, pthread_sigmask" );
    400400        }
     
    404404static void preempt( processor * this ) {
    405405        sigval_t value = { PREEMPT_NORMAL };
    406         __cfaabi_pthread_sigqueue( this->kernel_thread, SIGUSR1, value );
     406        pthread_sigqueue( this->kernel_thread, SIGUSR1, value );
    407407}
    408408
     
    415415        sigset_t oldset;
    416416        int ret;
    417         ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
     417        ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
    418418        if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    419419
     
    434434        sigset_t oldset;
    435435        int ret;
    436         ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
     436        ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
    437437        if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    438438
     
    505505        sigval val;
    506506        val.sival_int = 0;
    507         __cfaabi_pthread_sigqueue( alarm_thread, SIGALRM, val );
     507        pthread_sigqueue( alarm_thread, SIGALRM, val );
    508508
    509509        // Wait for the preemption thread to finish
     
    579579        static_assert( sizeof( sigset_t ) == sizeof( cxt->uc_sigmask ), "Expected cxt->uc_sigmask to be of sigset_t" );
    580580        #endif
    581         if ( __cfaabi_pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), 0p ) == -1 ) {
     581        if ( pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), 0p ) == -1 ) {
    582582                abort( "internal error, sigprocmask" );
    583583        }
     
    607607        sigset_t mask;
    608608        sigfillset(&mask);
    609         if ( __cfaabi_pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
     609        if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
    610610            abort( "internal error, pthread_sigmask" );
    611611        }
  • libcfa/src/concurrency/ready_subqueue.hfa

    r63be3387 rb77f0e1  
    2525static inline thread$ * mock_head(const __intrusive_lane_t & this) {
    2626        thread$ * rhead = (thread$ *)(
    27                 (uintptr_t)( &this.l.anchor ) - __builtin_offsetof( thread$, rdy_link )
     27                (uintptr_t)( &this.l.anchor ) - __builtin_offsetof( thread$, link )
    2828        );
    2929        return rhead;
     
    3434static inline void push( __intrusive_lane_t & this, thread$ * node ) {
    3535        /* paranoid */ verify( this.l.lock );
    36         /* paranoid */ verify( node->rdy_link.next == 0p );
    37         /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts, __ATOMIC_RELAXED) == MAX  );
    38         /* paranoid */ verify( this.l.prev->rdy_link.next == 0p );
    39         /* paranoid */ verify( __atomic_load_n(&this.l.prev->rdy_link.ts, __ATOMIC_RELAXED)   == MAX  );
     36        /* paranoid */ verify( node->link.next == 0p );
     37        /* paranoid */ verify( __atomic_load_n(&node->link.ts, __ATOMIC_RELAXED) == MAX  );
     38        /* paranoid */ verify( this.l.prev->link.next == 0p );
     39        /* paranoid */ verify( __atomic_load_n(&this.l.prev->link.ts, __ATOMIC_RELAXED)   == MAX  );
    4040        if( this.l.anchor.next == 0p ) {
    4141                /* paranoid */ verify( this.l.anchor.next == 0p );
     
    5151
    5252        // Get the relevant nodes locally
    53         this.l.prev->rdy_link.next = node;
    54         __atomic_store_n(&this.l.prev->rdy_link.ts, rdtscl(), __ATOMIC_RELAXED);
     53        this.l.prev->link.next = node;
     54        __atomic_store_n(&this.l.prev->link.ts, rdtscl(), __ATOMIC_RELAXED);
    5555        this.l.prev = node;
    5656        #if !defined(__CFA_NO_STATISTICS__)
     
    7070        // Get the relevant nodes locally
    7171        thread$ * node = this.l.anchor.next;
    72         this.l.anchor.next = node->rdy_link.next;
    73         __atomic_store_n(&this.l.anchor.ts, __atomic_load_n(&node->rdy_link.ts, __ATOMIC_RELAXED), __ATOMIC_RELAXED);
     72        this.l.anchor.next = node->link.next;
     73        __atomic_store_n(&this.l.anchor.ts, __atomic_load_n(&node->link.ts, __ATOMIC_RELAXED), __ATOMIC_RELAXED);
    7474        bool is_empty = this.l.anchor.next == 0p;
    75         node->rdy_link.next = 0p;
    76         __atomic_store_n(&node->rdy_link.ts, ULLONG_MAX, __ATOMIC_RELAXED);
     75        node->link.next = 0p;
     76        __atomic_store_n(&node->link.ts, ULLONG_MAX, __ATOMIC_RELAXED);
    7777        #if !defined(__CFA_NO_STATISTICS__)
    7878                this.l.cnt--;
     
    8383
    8484        unsigned long long ats = __atomic_load_n(&this.l.anchor.ts, __ATOMIC_RELAXED);
    85         /* paranoid */ verify( node->rdy_link.next == 0p );
    86         /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts , __ATOMIC_RELAXED) == MAX );
    87         /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts , __ATOMIC_RELAXED) != 0   );
     85        /* paranoid */ verify( node->link.next == 0p );
     86        /* paranoid */ verify( __atomic_load_n(&node->link.ts , __ATOMIC_RELAXED) == MAX );
     87        /* paranoid */ verify( __atomic_load_n(&node->link.ts , __ATOMIC_RELAXED) != 0   );
    8888        /* paranoid */ verify( ats != 0 );
    8989        /* paranoid */ verify( (ats == MAX) == is_empty );
  • libcfa/src/concurrency/thread.cfa

    r63be3387 rb77f0e1  
    4444        self_mon_p = &self_mon;
    4545        curr_cluster = &cl;
    46         rdy_link.next = 0p;
    47         rdy_link.ts   = MAX;
     46        link.next = 0p;
     47        link.ts   = MAX;
    4848        preferred = ready_queue_new_preferred();
    4949        last_proc = 0p;
    5050        random_state = __global_random_mask ? __global_random_prime : __global_random_prime ^ rdtscl();
    5151        #if defined( __CFA_WITH_VERIFY__ )
    52                 executing = 0p;
    5352                canary = 0x0D15EA5E0D15EA5Ep;
    5453        #endif
     54
     55        node.next = 0p;
     56        node.prev = 0p;
    5557
    5658        clh_node = malloc( );
     
    175177
    176178//-----------------------------------------------------------------------------
    177 bool migrate( thread$ * thrd, struct cluster & cl ) {
    178 
    179         monitor$ * tmon = get_monitor(thrd);
    180         monitor$ * __monitors[] = { tmon };
    181         monitor_guard_t __guard = { __monitors, 1 };
    182 
    183 
    184         {
    185                 // if nothing needs to be done, return false
    186                 if( thrd->curr_cluster == &cl ) return false;
    187 
    188                 // are we migrating ourself?
    189                 const bool local = thrd == active_thread();
    190 
    191                 /* paranoid */ verify( !local || &cl != active_cluster() );
    192                 /* paranoid */ verify( !local || thrd->curr_cluster == active_cluster() );
    193                 /* paranoid */ verify( !local || thrd->curr_cluster == active_processor()->cltr );
    194                 /* paranoid */ verify( local || tmon->signal_stack.top->owner->waiting_thread == thrd );
    195                 /* paranoid */ verify( local || tmon->signal_stack.top );
    196 
    197                 // make sure we aren't interrupted while doing this
    198                 // not as important if we aren't local
    199                 disable_interrupts();
    200 
    201                 // actually move the thread
    202                 unregister( thrd->curr_cluster, *thrd );
    203                 thrd->curr_cluster = &cl;
    204                 doregister( thrd->curr_cluster, *thrd );
    205 
    206                 // restore interrupts
    207                 enable_interrupts();
    208 
    209                 // if this is the local thread, we are still running on the old cluster
    210                 if(local) yield();
    211 
    212                 /* paranoid */ verify( !local || &cl == active_cluster() );
    213                 /* paranoid */ verify( !local || thrd->curr_cluster == active_cluster() );
    214                 /* paranoid */ verify( !local || thrd->curr_cluster == active_processor()->cltr );
    215                 /* paranoid */ verify(  local || tmon->signal_stack.top );
    216                 /* paranoid */ verify(  local || tmon->signal_stack.top->owner->waiting_thread == thrd );
    217 
    218                 return true;
    219         }
    220 }
    221 
    222 //-----------------------------------------------------------------------------
    223179#define GENERATOR LCG
    224180
  • libcfa/src/concurrency/thread.hfa

    r63be3387 rb77f0e1  
    132132
    133133//----------
    134 // misc
    135 bool migrate( thread$ * thrd, struct cluster & cl );
    136 
    137 forall( T & | is_thread(T) )
    138 static inline bool migrate( T & mutex thrd, struct cluster & cl ) { return migrate( &(thread&)thrd, cl ); }
    139 
    140 
    141 //----------
    142134// prng
    143135static inline {
  • libcfa/src/containers/array.hfa

    r63be3387 rb77f0e1  
    1 #pragma once
    2 
    31#include <assert.h>
    42
     
    2018    // About the choice of integral types offered as subscript overloads:
    2119    // Intent is to cover these use cases:
    22     //    a[0]                                                // i : zero_t
    23     //    a[1]                                                // i : one_t
    24     //    a[2]                                                // i : int
    2520    //    float foo( ptrdiff_t i ) { return a[i]; }           // i : ptrdiff_t
    26     //    float foo( size_t i ) { return a[i]; }              // i : size_t
    2721    //    forall( [N] ) ... for( i; N ) { total += a[i]; }    // i : typeof( sizeof(42) )
    2822    //    for( i; 5 ) { total += a[i]; }                      // i : int
    29     //
    3023    // It gets complicated by:
    3124    // -  CFA does overloading on concrete types, like int and unsigned int, not on typedefed
     
    3528    //    should give them type size_t.
    3629    //
    37     //                          gcc -m32         cfa -m32 given bug         gcc -m64 (and cfa)
     30    //                          gcc -m32         cfa -m32 given bug         gcc -m64
    3831    // ptrdiff_t                int              int                        long int
    3932    // size_t                   unsigned int     unsigned int               unsigned long int
    4033    // typeof( sizeof(42) )     unsigned int     unsigned long int          unsigned long int
    4134    // int                      int              int                        int
    42     //
    43     // So the solution must support types {zero_t, one_t, int, unsigned int, long int, unsigned long int}
    44     //
    45     // The solution cannot rely on implicit conversions (e.g. just have one overload for ptrdiff_t)
    46     // because assertion satisfaction requires types to match exacly.  Both higher-dimensional
    47     // subscripting and operations on slices use asserted subscript operators.  The test case
    48     // array-container/array-sbscr-cases covers the combinations.  Mike beleives that commenting out
    49     // any of the current overloads leads to one of those cases failing, either on 64- or 32-bit.
    50     // Mike is open to being shown a smaller set of overloads that still passes the test.
    51 
    52     static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, zero_t ) {
    53         assert( 0 < N );
    54         return (Timmed &) a.strides[0];
    55     }
    56 
    57     static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, one_t ) {
    58         assert( 1 < N );
    59         return (Timmed &) a.strides[1];
    60     }
    6135
    6236    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, int i ) {
     
    10377        return N;
    10478    }
    105 
    106     static inline void __taglen( tag(arpk(N, S, Timmed, Tbase)), tag(N) ) {}
    10779
    10880    // workaround #226 (and array relevance thereof demonstrated in mike102/otype-slow-ndims.cfa)
     
    184156#endif
    185157
    186 // Available for users to work around Trac #265
    187 // If `a[...0...]` isn't working, try `a[...ix0...]` instead.
    188 
    189 #define ix0 ((ptrdiff_t)0)
    190 
    191 
    192 
    193158//
    194159// Rotation
     
    220185//
    221186
    222 // desired:
    223 // trait ar(A &, Tv &, [N]) {
    224 //     Tv& ?[?]( A&, zero_t );
    225 //     Tv& ?[?]( A&, one_t  );
    226 //     Tv& ?[?]( A&, int    );
    227 //                   ...
    228 //     size_t ?`len( A& );
    229 //     void __taglen( tag(C), tag(N) );
    230 // };
    231 
    232 // working around N's not being accepted as arguments to traits
    233 
    234 #define ar(A, Tv, N) {                 \
    235     Tv& ?[?]( A&, zero_t );            \
    236     Tv& ?[?]( A&, one_t );             \
    237     Tv& ?[?]( A&, int );               \
    238     Tv& ?[?]( A&, unsigned int );      \
    239     Tv& ?[?]( A&, long int );          \
    240     Tv& ?[?]( A&, unsigned long int ); \
    241     size_t ?`len( A& );                \
    242     void __taglen( tag(A), tag(N) );   \
    243 }
     187trait ar(A &, Tv &) {
     188    Tv& ?[?]( A&, ptrdiff_t );
     189    size_t ?`len( A& );
     190};
  • libcfa/src/heap.cfa

    r63be3387 rb77f0e1  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct 30 20:56:20 2022
    13 // Update Count     : 1584
     12// Last Modified On : Thu Oct 13 22:21:52 2022
     13// Update Count     : 1557
    1414//
    1515
     
    4343
    4444#define FASTLOOKUP                                                                              // use O(1) table lookup from allocation size to bucket size
     45#define RETURNSPIN                                                                              // toggle spinlock / lockfree stack
    4546#define OWNERSHIP                                                                               // return freed memory to owner thread
    46 #define RETURNSPIN                                                                              // toggle spinlock / lockfree queue
    47 #if ! defined( OWNERSHIP ) && defined( RETURNSPIN )
    48 #warning "RETURNSPIN is ignored without OWNERSHIP; suggest commenting out RETURNSPIN"
    49 #endif // ! OWNERSHIP && RETURNSPIN
    5047
    5148#define CACHE_ALIGN 64
     
    112109
    113110
    114 //######################### Helpers #########################
    115 
    116 
    117 // generic Bsearchl does not inline, so substitute with hand-coded binary-search.
    118 inline __attribute__((always_inline))
    119 static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) {
    120         size_t l = 0, m, h = dim;
    121         while ( l < h ) {
    122                 m = (l + h) / 2;
    123                 if ( (unsigned int &)(vals[m]) < key ) {                // cast away const
    124                         l = m + 1;
    125                 } else {
    126                         h = m;
    127                 } // if
    128         } // while
    129         return l;
    130 } // Bsearchl
     111//######################### Spin Lock #########################
    131112
    132113
     
    225206
    226207
     208#define SPINLOCK 0
     209#define LOCKFREE 1
     210#define BUCKETLOCK SPINLOCK
     211#if BUCKETLOCK == SPINLOCK
     212#elif BUCKETLOCK == LOCKFREE
     213#include <stackLockFree.hfa>
     214#else
     215        #error undefined lock type for bucket lock
     216#endif // LOCKFREE
     217
    227218// Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage.
    228219// Break recursion by hardcoding number of buckets and statically checking number is correct after bucket array defined.
     
    241232                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    242233                                                                size_t blockSize;               // size for munmap (must overlay alignment)
     234                                                                #if BUCKETLOCK == SPINLOCK
    243235                                                                Storage * next;                 // freed block points to next freed block of same size
     236                                                                #endif // SPINLOCK
    244237                                                        };
    245238                                                        size_t size;                            // allocation size in bytes
    246239                                                };
     240                                                #if BUCKETLOCK == LOCKFREE
     241                                                Link(Storage) next;                             // freed block points next freed block of same size (double-wide)
     242                                                #endif // LOCKFREE
    247243                                        };
    248244                                } real; // RealHeader
     
    263259        struct __attribute__(( aligned (8) )) FreeHeader {
    264260                size_t blockSize __attribute__(( aligned(8) )); // size of allocations on this list
     261                #if BUCKETLOCK == SPINLOCK
    265262                #ifdef OWNERSHIP
    266263                #ifdef RETURNSPIN
     
    269266                Storage * returnList;                                                   // other thread return list
    270267                #endif // OWNERSHIP
    271 
    272268                Storage * freeList;                                                             // thread free list
     269                #else
     270                StackLF(Storage) freeList;
     271                #endif // BUCKETLOCK
    273272                Heap * homeManager;                                                             // heap owner (free storage to bucket, from bucket to heap)
    274273        }; // FreeHeader
     
    291290        #endif // __STATISTICS__
    292291}; // Heap
     292
     293#if BUCKETLOCK == LOCKFREE
     294inline __attribute__((always_inline))
     295static {
     296        Link(Heap.Storage) * ?`next( Heap.Storage * this ) { return &this->header.kind.real.next; }
     297        void ?{}( Heap.FreeHeader & ) {}
     298        void ^?{}( Heap.FreeHeader & ) {}
     299} // distribution
     300#endif // LOCKFREE
    293301
    294302
     
    377385
    378386
     387// generic Bsearchl does not inline, so substitute with hand-coded binary-search.
     388inline __attribute__((always_inline))
     389static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) {
     390        size_t l = 0, m, h = dim;
     391        while ( l < h ) {
     392                m = (l + h) / 2;
     393                if ( (unsigned int &)(vals[m]) < key ) {                // cast away const
     394                        l = m + 1;
     395                } else {
     396                        h = m;
     397                } // if
     398        } // while
     399        return l;
     400} // Bsearchl
     401
     402
    379403void heapMasterCtor() with( heapMaster ) {
    380404        // Singleton pattern to initialize heap master
     
    385409        __map_prot = PROT_READ | PROT_WRITE | PROT_EXEC;
    386410
    387         extLock = 0;
    388         mgrLock = 0;
     411        ?{}( extLock );
     412        ?{}( mgrLock );
    389413
    390414        char * end = (char *)sbrk( 0 );
     
    473497                                #ifdef OWNERSHIP
    474498                                #ifdef RETURNSPIN
    475                                 freeLists[j].returnLock = 0;
     499                                ?{}( freeLists[j].returnLock );
     500                                #endif // RETURNSPIN
    476501                                freeLists[j].returnList = 0p;
    477                                 #endif // RETURNSPIN
    478502                                #endif // OWNERSHIP
    479 
    480503                                freeLists[j].freeList = 0p;
    481504                                freeLists[j].homeManager = heap;
    482505                                freeLists[j].blockSize = bucketSizes[j];
    483506                        } // for
    484 
     507       
    485508                        heapBuffer = 0p;
    486509                        heapReserve = 0;
     
    499522        if ( unlikely( ! heapMasterBootFlag ) ) heapMasterCtor();
    500523
    501         lock( heapMaster.mgrLock );                                                     // protect heapMaster counters
     524        lock( heapMaster.mgrLock );             // protect heapMaster counters
    502525
    503526        // get storage for heap manager
     
    687710        // find the closest bucket size less than or equal to the mmapStart size
    688711        maxBucketsUsed = Bsearchl( mmapStart, bucketSizes, NoBucketSizes ); // binary search
    689 
    690712        verify( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    691713        verify( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
     
    810832
    811833                size_t increase = ceiling2( size > heapExpand ? size : heapExpand, libAlign() );
     834                // Do not call abort or strerror( errno ) as they may call malloc.
    812835                if ( unlikely( sbrk( increase ) == (void *)-1 ) ) {     // failed, no memory ?
    813836                        unlock( extLock );
    814                         abort( NO_MEMORY_MSG, size );                           // give up
     837                        abort( NO_MEMORY_MSG, size );                           // no memory
    815838                } // if
    816839
     
    948971                #endif // __STATISTICS__
    949972
     973                // Spin until the lock is acquired for this particular size of block.
     974
     975                #if BUCKETLOCK == SPINLOCK
    950976                block = freeHead->freeList;                                             // remove node from stack
     977                #else
     978                block = pop( freeHead->freeList );
     979                #endif // BUCKETLOCK
    951980                if ( unlikely( block == 0p ) ) {                                // no free block ?
    952                         // Freelist for this size is empty, so check return list (OWNERSHIP), carve it out of the heap, if there
    953                         // is enough left, or get some more heap storage and carve it off.
    954981                        #ifdef OWNERSHIP
    955                         if ( unlikely( freeHead->returnList ) ) {       // race, get next time if lose race
    956                                 #ifdef RETURNSPIN
    957                                 lock( freeHead->returnLock );
    958                                 block = freeHead->returnList;
    959                                 freeHead->returnList = 0p;
    960                                 unlock( freeHead->returnLock );
    961                                 #else
    962                                 block = __atomic_exchange_n( &freeHead->returnList, 0p, __ATOMIC_SEQ_CST );
    963                                 #endif // RETURNSPIN
    964 
    965                                 verify( block );
    966                                 #ifdef __STATISTICS__
    967                                 stats.return_pulls += 1;
    968                                 #endif // __STATISTICS__
    969 
    970                                 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
    971 
    972                                 freeHead->freeList = block->header.kind.real.next; // merge returnList into freeHead
    973                         } else {
     982                        // Freelist for that size is empty, so carve it out of the heap, if there is enough left, or get some more
     983                        // and then carve it off.
     984                        #ifdef RETURNSPIN
     985                        #if BUCKETLOCK == SPINLOCK
     986                        lock( freeHead->returnLock );
     987                        block = freeHead->returnList;
     988                        freeHead->returnList = 0p;
     989                        unlock( freeHead->returnLock );
     990                        #else
     991                        block = __atomic_exchange_n( &freeHead->returnList, nullptr, __ATOMIC_SEQ_CST );
     992                        #endif // RETURNSPIN
     993
     994                        if ( likely( block == 0p ) ) {                  // return list also empty?
    974995                        #endif // OWNERSHIP
    975996                                // Do not leave kernel thread as manager_extend accesses heapManager.
     
    9811002
    9821003                                #ifdef __CFA_DEBUG__
    983                                 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first SCRUB_SIZE bytes.
     1004                                // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024 bytes.
    9841005                                memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) );
    9851006                                #endif // __CFA_DEBUG__
     1007                        #endif // BUCKETLOCK
    9861008                        #ifdef OWNERSHIP
     1009                        } else {                                                                        // merge returnList into freeHead
     1010                                #ifdef __STATISTICS__
     1011                                stats.return_pulls += 1;
     1012                                #endif // __STATISTICS__
     1013
     1014                                // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
     1015
     1016                                freeHead->freeList = block->header.kind.real.next;
    9871017                        } // if
    9881018                        #endif // OWNERSHIP
     
    9961026  if ( unlikely( size > ULONG_MAX - __page_size ) ) return 0p;
    9971027                tsize = ceiling2( tsize, __page_size );                 // must be multiple of page size
    998 
    9991028                #ifdef __STATISTICS__
    10001029                stats.counters[STAT_NAME].alloc += tsize;
     
    10131042                        if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory
    10141043                        // Do not call strerror( errno ) as it may call malloc.
    1015                         abort( "**** Error **** attempt to allocate large object (> %zu) of size %zu bytes and mmap failed with errno %d.",
    1016                                    size, heapMaster.mmapStart, errno );
     1044                        abort( "**** Error **** attempt to allocate large object (> %zu) of size %zu bytes and mmap failed with errno %d.", size, heapMaster.mmapStart, errno );
    10171045                } // if
    10181046                block->header.kind.real.blockSize = MarkMmappedBit( tsize ); // storage size for munmap
    10191047
    10201048                #ifdef __CFA_DEBUG__
    1021                 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first SCRUB_SIZE bytes. The
    1022                 // rest of the storage set to 0 by mmap.
     1049                // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024 bytes.  The rest of
     1050                // the storage set to 0 by mmap.
    10231051                memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) );
    10241052                #endif // __CFA_DEBUG__
     
    10981126                #endif // __CFA_DEBUG__
    10991127
    1100                 #ifdef OWNERSHIP
    11011128                if ( likely( heapManager == freeHead->homeManager ) ) { // belongs to this thread
    11021129                        header->kind.real.next = freeHead->freeList; // push on stack
     
    11051132                        verify( heapManager );
    11061133
     1134                        #ifdef OWNERSHIP
    11071135                        #ifdef RETURNSPIN
    11081136                        lock( freeHead->returnLock );
     
    11131141                        header->kind.real.next = freeHead->returnList; // link new node to top node
    11141142                        // CAS resets header->kind.real.next = freeHead->returnList on failure
    1115                         while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, (Heap.Storage *)header,
     1143                        while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, header,
    11161144                                                                                                   false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) );
    11171145                        #endif // RETURNSPIN
    1118                 } // if
    1119 
    1120                 #else                                                                                   // no OWNERSHIP
    1121 
    1122                 // kind.real.home is address in owner thread's freeLists, so compute the equivalent position in this thread's freeList.
    1123                 freeHead = &freeLists[ClearStickyBits( (Heap.FreeHeader *)(header->kind.real.home) ) - &freeHead->homeManager->freeLists[0]];
    1124                 header->kind.real.next = freeHead->freeList;    // push on stack
    1125                 freeHead->freeList = (Heap.Storage *)header;
    1126                 #endif // ! OWNERSHIP
    1127 
    1128                 #ifdef __U_STATISTICS__
    1129                 stats.return_pushes += 1;
    1130                 stats.return_storage_request += rsize;
    1131                 stats.return_storage_alloc += size;
    1132                 #endif // __U_STATISTICS__
    1133 
    1134                 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
     1146
     1147                        #else                                                                           // no OWNERSHIP
     1148
     1149                        freeHead = &heap->freeLists[ClearStickyBits( header->kind.real.home ) - &freeHead->homeManager->freeLists[0]];
     1150                        header->kind.real.next = freeHead->freeList; // push on stack
     1151                        freeHead->freeList = (Heap.Storage *)header;
     1152                        #endif // ! OWNERSHIP
     1153
     1154                        #ifdef __U_STATISTICS__
     1155                        stats.return_pushes += 1;
     1156                        stats.return_storage_request += rsize;
     1157                        stats.return_storage_alloc += size;
     1158                        #endif // __U_STATISTICS__
     1159
     1160                        // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.
     1161                } // if
    11351162        } // if
    11361163
     
    11591186                #endif // __STATISTICS__
    11601187
     1188                #if BUCKETLOCK == SPINLOCK
    11611189                for ( Heap.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
     1190                #else
     1191                        for(;;) {
     1192//              for ( Heap.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
     1193//              for ( Heap.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
     1194//                      Heap.Storage * temp = p->header.kind.real.next.top; // FIX ME: direct assignent fails, initialization works`
     1195//                      typeof(p) temp = (( p )`next)->top;                     // FIX ME: direct assignent fails, initialization works`
     1196//                      p = temp;
     1197                #endif // BUCKETLOCK
    11621198                        total += size;
    11631199                        #ifdef __STATISTICS__
  • libcfa/src/interpose.cfa

    r63be3387 rb77f0e1  
    4242
    4343typedef void (* generic_fptr_t)(void);
    44 static generic_fptr_t do_interpose_symbol( void * library, const char symbol[], const char version[] ) {
    45         const char * error;
    46 
    47         union { generic_fptr_t fptr; void * ptr; } originalFunc;
    48 
    49         #if defined( _GNU_SOURCE )
    50                 if ( version ) {
    51                         originalFunc.ptr = dlvsym( library, symbol, version );
    52                 } else {
    53                         originalFunc.ptr = dlsym( library, symbol );
    54                 }
    55         #else
    56                 originalFunc.ptr = dlsym( library, symbol );
    57         #endif // _GNU_SOURCE
    58 
    59         error = dlerror();
    60         if ( error ) abort( "interpose_symbol : internal error, %s\n", error );
    61 
    62         return originalFunc.fptr;
    63 }
    64 
    6544static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
    6645        const char * error;
    6746
    6847        static void * library;
    69         static void * pthread_library;
    7048        if ( ! library ) {
    7149                #if defined( RTLD_NEXT )
     
    8058                #endif
    8159        } // if
    82         if ( ! pthread_library ) {
    83                 #if defined( RTLD_NEXT )
    84                         pthread_library = RTLD_NEXT;
    85                 #else
    86                         // missing RTLD_NEXT => must hard-code library name, assuming libstdc++
    87                         pthread_library = dlopen( "libpthread.so", RTLD_LAZY );
    88                         error = dlerror();
    89                         if ( error ) {
    90                                 abort( "interpose_symbol : failed to open libpthread, %s\n", error );
    91                         }
    92                 #endif
    93         } // if
    94 
    95         return do_interpose_symbol(library, symbol, version);
     60
     61        union { generic_fptr_t fptr; void * ptr; } originalFunc;
     62
     63        #if defined( _GNU_SOURCE )
     64                if ( version ) {
     65                        originalFunc.ptr = dlvsym( library, symbol, version );
     66                } else {
     67                        originalFunc.ptr = dlsym( library, symbol );
     68                }
     69        #else
     70                originalFunc.ptr = dlsym( library, symbol );
     71        #endif // _GNU_SOURCE
     72
     73        error = dlerror();
     74        if ( error ) abort( "interpose_symbol : internal error, %s\n", error );
     75
     76        return originalFunc.fptr;
    9677}
    9778
     
    11697
    11798extern "C" {
    118         void __cfathreadabi_interpose_startup( generic_fptr_t (*do_interpose_symbol)( void * library, const char symbol[], const char version[] ) ) __attribute__((weak));
    11999        void __cfaabi_interpose_startup( void ) {
    120100                const char *version = 0p;
     
    128108                INTERPOSE_LIBC( exit , version );
    129109#pragma GCC diagnostic pop
    130 
    131                 if(__cfathreadabi_interpose_startup) __cfathreadabi_interpose_startup( do_interpose_symbol );
    132110
    133111                // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because
  • src/AST/Convert.cpp

    r63be3387 rb77f0e1  
    234234                }
    235235                return declWithTypePostamble( decl, node );
    236         }
    237 
    238         // InlineMemberDecl vanish after EnumAndPointerDecay pass so no necessary to implement NewToOld
    239         const ast::DeclWithType * visit( const ast::InlineMemberDecl * node ) override final { 
    240                 assert( false );
    241                 (void) node;
    242                 return nullptr;
    243236        }
    244237
     
    16211614                        { old->get_funcSpec().val }
    16221615                );
     1616                decl->enumInLine = old->enumInLine;
    16231617                cache.emplace(old, decl);
    16241618                assert(cache.find( old ) != cache.end());
     
    18651859                decl->uniqueId   = old->uniqueId;
    18661860                decl->storage    = { old->storageClasses.val };
    1867 
    1868                 this->node = decl;
    1869         }
    1870 
    1871         virtual void visit( const InlineMemberDecl * old ) override final {
    1872                 if ( inCache( old ) ) {
    1873                         return;
    1874                 }
    1875                 auto&& type = GET_ACCEPT_1(type, Type);
    1876                 auto&& attr = GET_ACCEPT_V(attributes, Attribute);
    1877 
    1878                 auto decl = new ast::InlineMemberDecl(
    1879                         old->location,
    1880                         old->name,
    1881                         type,
    1882                         { old->get_storageClasses().val },
    1883                         { old->linkage.val },
    1884                         std::move(attr),
    1885                         { old->get_funcSpec().val }
    1886                 );
    1887                 cache.emplace(old, decl);
    1888                 assert(cache.find( old ) != cache.end());
    1889                 decl->scopeLevel = old->scopeLevel;
    1890                 decl->mangleName = old->mangleName;
    1891                 decl->isDeleted  = old->isDeleted;
    1892                 decl->asmName    = GET_ACCEPT_1(asmName, Expr);
    1893                 decl->uniqueId   = old->uniqueId;
    1894                 decl->extension  = old->extension;
    18951861
    18961862                this->node = decl;
  • src/AST/Decl.hpp

    r63be3387 rb77f0e1  
    105105        ptr<Init> init;
    106106        ptr<Expr> bitfieldWidth;
     107        bool enumInLine = false; // enum inline is not a real object declaration.
     108        // It is a place holder for a set of enum value (ObjectDecl)
     109        bool importValue = false; // if the value copied from somewhere else
    107110
    108111        ObjectDecl( const CodeLocation & loc, const std::string & name, const Type * type,
     
    397400};
    398401
    399 /// Static Assertion `_Static_assert( ... , ... );`
    400402class StaticAssertDecl : public Decl {
    401403public:
     
    409411private:
    410412        StaticAssertDecl * clone() const override { return new StaticAssertDecl( *this ); }
    411         MUTATE_FRIEND
    412 };
    413 
    414 /// Inline Member Declaration `inline TypeName;`
    415 class InlineMemberDecl final : public DeclWithType {
    416 public:
    417         ptr<Type> type;
    418 
    419         InlineMemberDecl( const CodeLocation & loc, const std::string & name, const Type * type,
    420                 Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
    421                 std::vector< ptr<Attribute> > && attrs = {}, Function::Specs fs = {} )
    422         : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), type( type ) {}
    423 
    424         const Type * get_type() const override { return type; }
    425         void set_type( const Type * ty ) override { type = ty; }
    426 
    427         const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
    428 private:
    429         InlineMemberDecl * clone() const override { return new InlineMemberDecl{ *this }; }
    430413        MUTATE_FRIEND
    431414};
  • src/AST/Fwd.hpp

    r63be3387 rb77f0e1  
    3737class DirectiveDecl;
    3838class StaticAssertDecl;
    39 class InlineMemberDecl;
    4039
    4140class Stmt;
  • src/AST/Pass.hpp

    r63be3387 rb77f0e1  
    141141        const ast::DirectiveDecl *    visit( const ast::DirectiveDecl        * ) override final;
    142142        const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) override final;
    143         const ast::DeclWithType *     visit( const ast::InlineMemberDecl     * ) override final;
    144143        const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) override final;
    145144        const ast::Stmt *             visit( const ast::ExprStmt             * ) override final;
  • src/AST/Pass.impl.hpp

    r63be3387 rb77f0e1  
    617617                                maybe_accept( node, &FunctionDecl::returns );
    618618                                maybe_accept( node, &FunctionDecl::type );
    619                                 maybe_accept( node, &FunctionDecl::attributes );
    620619                                // First remember that we are now within a function.
    621620                                ValueGuard< bool > oldInFunction( inFunction );
     
    626625                                atFunctionTop = true;
    627626                                maybe_accept( node, &FunctionDecl::stmts );
     627                                maybe_accept( node, &FunctionDecl::attributes );
    628628                        }
    629629                }
     
    800800
    801801        VISIT_END( StaticAssertDecl, node );
    802 }
    803 
    804 //--------------------------------------------------------------------------
    805 // InlineMemberDecl
    806 template< typename core_t >
    807 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::InlineMemberDecl * node ) {
    808         VISIT_START( node );
    809 
    810         if ( __visit_children() ) {
    811                 {
    812                         guard_symtab guard { *this };
    813                         maybe_accept( node, &InlineMemberDecl::type );
    814                 }
    815         }
    816 
    817         VISIT_END( DeclWithType, node );
    818802}
    819803
  • src/AST/Print.cpp

    r63be3387 rb77f0e1  
    398398        virtual const ast::Decl * visit( const ast::StructDecl * node ) override final {
    399399                print(node);
    400                 return node;
    401         }
    402 
    403         virtual const ast::DeclWithType * visit( const ast::InlineMemberDecl * node ) override final {
    404                 os << "inline ";
    405                 if ( ! node->name.empty() ) os << node->name;
    406 
    407400                return node;
    408401        }
  • src/AST/Type.cpp

    r63be3387 rb77f0e1  
    147147// --- TypeInstType
    148148
    149 bool TypeInstType::operator==( const TypeInstType & other ) const {
    150         return base == other.base
    151                 && formal_usage == other.formal_usage
    152                 && expr_id == other.expr_id;
    153 }
    154 
    155149TypeInstType::TypeInstType( const TypeDecl * b,
    156150        CV::Qualifiers q, std::vector<ptr<Attribute>> && as )
     
    163157
    164158bool TypeInstType::isComplete() const { return base->sized; }
    165 
    166 std::string TypeInstType::TypeEnvKey::typeString() const {
    167         return std::string("_") + std::to_string(formal_usage)
    168                 + "_" + std::to_string(expr_id) + "_" + base->name;
    169 }
    170 
    171 bool TypeInstType::TypeEnvKey::operator==(
    172                 const TypeInstType::TypeEnvKey & other ) const {
    173         return base == other.base
    174                 && formal_usage == other.formal_usage
    175                 && expr_id == other.expr_id;
    176 }
    177 
    178 bool TypeInstType::TypeEnvKey::operator<(
    179                 const TypeInstType::TypeEnvKey & other ) const {
    180         // TypeEnvKey ordering is an arbitrary total ordering.
    181         // It doesn't mean anything but allows for a sorting.
    182         if ( base < other.base ) {
    183                 return true;
    184         } else if ( other.base < base ) {
    185                 return false;
    186         } else if ( formal_usage < other.formal_usage ) {
    187                 return true;
    188         } else if ( other.formal_usage < formal_usage ) {
    189                 return false;
    190         } else {
    191                 return expr_id < other.expr_id;
    192         }
    193 }
    194159
    195160// --- TupleType
  • src/AST/Type.hpp

    r63be3387 rb77f0e1  
    408408
    409409                TypeEnvKey() = default;
    410                 TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0)
    411                 : base(base), formal_usage(formal_usage), expr_id(expr_id) {}
    412                 TypeEnvKey(const TypeInstType & inst)
    413                 : base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {}
    414                 std::string typeString() const;
    415                 bool operator==(const TypeEnvKey & other) const;
    416                 bool operator<(const TypeEnvKey & other) const;
     410                TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0): base(base), formal_usage(formal_usage), expr_id(expr_id) {}
     411                TypeEnvKey(const TypeInstType & inst): base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {}
     412                std::string typeString() const { return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + base->name; }
     413                bool operator==(const TypeEnvKey & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
    417414        };
    418415
    419         bool operator==(const TypeInstType & other) const;
     416        bool operator==(const TypeInstType & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
    420417
    421418        TypeInstType(
  • src/AST/Visitor.hpp

    r63be3387 rb77f0e1  
    3333    virtual const ast::DirectiveDecl *    visit( const ast::DirectiveDecl        * ) = 0;
    3434    virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) = 0;
    35     virtual const ast::DeclWithType *     visit( const ast::InlineMemberDecl     * ) = 0;
    3635    virtual const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) = 0;
    3736    virtual const ast::Stmt *             visit( const ast::ExprStmt             * ) = 0;
  • src/Common/CodeLocationTools.cpp

    r63be3387 rb77f0e1  
    111111    macro(DirectiveDecl, DirectiveDecl) \
    112112    macro(StaticAssertDecl, StaticAssertDecl) \
    113     macro(InlineMemberDecl, DeclWithType) \
    114113    macro(CompoundStmt, CompoundStmt) \
    115114    macro(ExprStmt, Stmt) \
  • src/Common/PassVisitor.h

    r63be3387 rb77f0e1  
    8181        virtual void visit( StaticAssertDecl * assertDecl ) override final;
    8282        virtual void visit( const StaticAssertDecl * assertDecl ) override final;
    83         virtual void visit( InlineMemberDecl * valueDecl ) override final;
    84         virtual void visit( const InlineMemberDecl * valueDecl ) override final;
    8583
    8684        virtual void visit( CompoundStmt * compoundStmt ) override final;
     
    275273        virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) override final;
    276274        virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) override final;
    277         virtual DeclarationWithType * mutate( InlineMemberDecl * valueDecl ) override final;
    278275
    279276        virtual CompoundStmt * mutate( CompoundStmt * compoundStmt ) override final;
  • src/Common/PassVisitor.impl.h

    r63be3387 rb77f0e1  
    607607                        indexerAddId( &func );
    608608                        maybeMutate_impl( node->type, *this );
    609                         maybeMutate_impl( node->attributes, *this );
    610609                        // First remember that we are now within a function.
    611610                        ValueGuard< bool > oldInFunction( inFunction );
     
    616615                        atFunctionTop = true;
    617616                        maybeMutate_impl( node->statements, *this );
     617                        maybeMutate_impl( node->attributes, *this );
    618618                }
    619619        }
     
    10441044
    10451045        MUTATE_END( StaticAssertDecl, node );
    1046 }
    1047 
    1048 //--------------------------------------------------------------------------
    1049 // InlineMemberDecl
    1050 template< typename pass_type >
    1051 void PassVisitor< pass_type >::visit( InlineMemberDecl * node ) {
    1052         VISIT_START( node );
    1053 
    1054         maybeAccept_impl( node->type, *this );
    1055 
    1056         VISIT_END( node );
    1057 }
    1058 
    1059 template< typename pass_type >
    1060 void PassVisitor< pass_type >::visit( const InlineMemberDecl * node ) {
    1061         VISIT_START( node );
    1062 
    1063         maybeAccept_impl( node->type, *this );
    1064 
    1065         VISIT_END( node );
    1066 }
    1067 
    1068 template< typename pass_type >
    1069 DeclarationWithType * PassVisitor< pass_type >::mutate( InlineMemberDecl * node ) {
    1070         MUTATE_START( node );
    1071 
    1072         maybeMutate_impl( node->type, *this );
    1073 
    1074         MUTATE_END( DeclarationWithType, node );
    10751046}
    10761047
  • src/Common/utility.h

    r63be3387 rb77f0e1  
    452452
    453453// -----------------------------------------------------------------------------
    454 // Helper struct and function to support:
    455 // for ( auto val : group_iterate( container1, container2, ... ) ) { ... }
    456 // This iteraters through multiple containers of the same size.
    457 
    458 template<typename... Args>
    459 class group_iterate_t {
    460         using Iterables = std::tuple<Args...>;
    461         Iterables iterables;
    462 
    463         // Getting the iterator and value types this way preserves const.
    464         template<size_t I> using Iter = decltype(std::get<I>(iterables).begin());
    465         template<size_t I> using Data = decltype(*std::get<I>(iterables).begin());
    466         template<typename> struct base_iterator;
    467 
    468         // This inner template puts the sequence of `0, 1, ... sizeof...(Args)-1`
    469         // into a pack. These are the indexes into the tuples, so unpacking can
    470         // go over each element of the tuple.
    471         // The std::integer_sequence is just used to build that sequence.
    472         // A library reference will probably explain it better than I can.
    473         template<std::size_t... Indices>
    474         struct base_iterator<std::integer_sequence<std::size_t, Indices...>> {
    475                 using value_type = std::tuple< Data<Indices>... >;
    476                 std::tuple<Iter<Indices>...> iterators;
    477 
    478                 base_iterator( Iter<Indices>... is ) : iterators( is... ) {}
    479                 base_iterator operator++() {
    480                         return base_iterator( ++std::get<Indices>( iterators )... );
     454// Helper struct and function to support
     455// for ( val : group_iterate( container1, container2, ... ) ) {}
     456// syntax to have a for each that iterates multiple containers of the same length
     457// TODO: update to use variadic arguments
     458
     459template< typename T1, typename T2 >
     460struct group_iterate_t {
     461private:
     462        std::tuple<T1, T2> args;
     463public:
     464        group_iterate_t( bool skipBoundsCheck, const T1 & v1, const T2 & v2 ) : args(v1, v2) {
     465                assertf(skipBoundsCheck || v1.size() == v2.size(), "group iteration requires containers of the same size: <%zd, %zd>.", v1.size(), v2.size());
     466        };
     467
     468        typedef std::tuple<decltype(*std::get<0>(args).begin()), decltype(*std::get<1>(args).begin())> value_type;
     469        typedef decltype(std::get<0>(args).begin()) T1Iter;
     470        typedef decltype(std::get<1>(args).begin()) T2Iter;
     471
     472        struct iterator {
     473                typedef std::tuple<T1Iter, T2Iter> IterTuple;
     474                IterTuple it;
     475                iterator( T1Iter i1, T2Iter i2 ) : it( i1, i2 ) {}
     476                iterator operator++() {
     477                        return iterator( ++std::get<0>(it), ++std::get<1>(it) );
    481478                }
    482                 bool operator!=( const base_iterator& other ) const {
    483                         return iterators != other.iterators;
    484                 }
    485                 value_type operator*() const {
    486                         return std::tie( *std::get<Indices>( iterators )... );
    487                 }
    488 
    489                 static base_iterator make_begin( Iterables & data ) {
    490                         return base_iterator( std::get<Indices>( data ).begin()... );
    491                 }
    492                 static base_iterator make_end( Iterables & data ) {
    493                         return base_iterator( std::get<Indices>( data ).end()... );
    494                 }
     479                bool operator!=( const iterator &other ) const { return it != other.it; }
     480                value_type operator*() const { return std::tie( *std::get<0>(it), *std::get<1>(it) ); }
    495481        };
    496482
    497 public:
    498         group_iterate_t( const Args &... args ) : iterables( args... ) {}
    499 
    500         using iterator = base_iterator<decltype(
    501                 std::make_integer_sequence<std::size_t, sizeof...(Args)>())>;
    502 
    503         iterator begin() { return iterator::make_begin( iterables ); }
    504         iterator end() { return iterator::make_end( iterables ); }
    505 };
    506 
    507 // Helpers for the bounds checks (the non-varatic part of group_iterate):
    508 static inline void runGroupBoundsCheck(size_t size0, size_t size1) {
    509         assertf( size0 == size1,
    510                 "group iteration requires containers of the same size: <%zd, %zd>.",
    511                 size0, size1 );
    512 }
    513 
    514 static inline void runGroupBoundsCheck(size_t size0, size_t size1, size_t size2) {
    515         assertf( size0 == size1 && size1 == size2,
    516                 "group iteration requires containers of the same size: <%zd, %zd, %zd>.",
    517                 size0, size1, size2 );
    518 }
    519 
    520 /// Performs bounds check to ensure that all arguments are of the same length.
     483        iterator begin() { return iterator( std::get<0>(args).begin(), std::get<1>(args).begin() ); }
     484        iterator end() { return iterator( std::get<0>(args).end(), std::get<1>(args).end() ); }
     485};
     486
     487/// performs bounds check to ensure that all arguments are of the same length.
    521488template< typename... Args >
    522489group_iterate_t<Args...> group_iterate( Args &&... args ) {
    523         runGroupBoundsCheck( args.size()... );
    524         return group_iterate_t<Args...>( std::forward<Args>( args )... );
    525 }
    526 
    527 /// Does not perform a bounds check - requires user to ensure that iteration terminates when appropriate.
     490        return group_iterate_t<Args...>(false, std::forward<Args>( args )...);
     491}
     492
     493/// does not perform a bounds check - requires user to ensure that iteration terminates when appropriate.
    528494template< typename... Args >
    529495group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) {
    530         return group_iterate_t<Args...>( std::forward<Args>( args )... );
     496        return group_iterate_t<Args...>(true, std::forward<Args>( args )...);
    531497}
    532498
  • src/GenPoly/Box.cc

    r63be3387 rb77f0e1  
    5858namespace GenPoly {
    5959        namespace {
    60                 FunctionType *makeAdapterType( FunctionType const *adaptee, const TyVarMap &tyVars );
     60                FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars );
    6161
    6262                class BoxPass {
     
    6868                /// Adds layout-generation functions to polymorphic types.
    6969                class LayoutFunctionBuilder final : public WithDeclsToAdd, public WithVisitorRef<LayoutFunctionBuilder>, public WithShortCircuiting {
     70                        // Current level of nested functions:
     71                        unsigned int functionNesting = 0;
    7072                public:
     73                        void previsit( FunctionDecl *functionDecl );
    7174                        void previsit( StructDecl *structDecl );
    7275                        void previsit( UnionDecl *unionDecl );
     
    97100                        void passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes );
    98101                        /// passes extra type parameters into a polymorphic function application
    99                         /// Returns an iterator to the first argument after the added
    100                         /// arguments, which are added at the beginning.
    101                         std::list< Expression *>::iterator passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, const TyVarMap &exprTyVars );
     102                        void passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
    102103                        /// wraps a function application with a new temporary for the out-parameter return value
    103                         /// The new out-parameter is the new first parameter.
    104                         Expression *addRetParam( ApplicationExpr *appExpr, Type *retType );
     104                        Expression *addRetParam( ApplicationExpr *appExpr, Type *retType, std::list< Expression *>::iterator &arg );
     105                        /// Replaces all the type parameters of a generic type with their concrete equivalents under the current environment
     106                        void replaceParametersWithConcrete( ApplicationExpr *appExpr, std::list< Expression* >& params );
     107                        /// Replaces a polymorphic type with its concrete equivalant under the current environment (returns itself if concrete).
     108                        /// If `doClone` is set to false, will not clone interior types
     109                        Type *replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone = true );
    105110                        /// wraps a function application returning a polymorphic type with a new temporary for the out-parameter return value
    106                         Expression *addDynRetParam( ApplicationExpr *appExpr, Type *polyType );
    107                         /// Converts a function call into a call of the adapter with the
    108                         /// original function as the first argument (all other arguments
    109                         /// are pushed back). May adjust return value.
    110                         Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function );
    111                         /// Modifies the `arg`, replacing it with a boxed expression
    112                         /// that matches `formal` under the current TyVarMap.
    113                         void boxParam( Expression *&arg, Type *formal, const TyVarMap &exprTyVars );
    114                         /// Box an argument of `appExpr` for each parameter in `function`
    115                         /// starting at `arg`.
    116                         /// `exprTyVars` is the function's type variables.
    117                         void boxParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *function, const TyVarMap &exprTyVars );
    118                         /// Boxes each assertion and inserts them into `appExpr` at
    119                         /// `arg`. `exprTyVars` is the function's type variables.
    120                         void addInferredParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *functionType, const TyVarMap &tyVars );
     111                        Expression *addDynRetParam( ApplicationExpr *appExpr, Type *polyType, std::list< Expression *>::iterator &arg );
     112                        Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
     113                        void boxParam( Type *formal, Expression *&arg, const TyVarMap &exprTyVars );
     114                        void boxParams( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
     115                        void addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars );
    121116                        /// Stores assignment operators from assertion list in local map of assignment operations
    122117                        void passAdapters( ApplicationExpr *appExpr, FunctionType *functionType, const TyVarMap &exprTyVars );
    123                         /// Creates an adapter definition from `adaptee` to `realType`, using
    124                         /// `mangleName` as the base name for the adapter. `tyVars` is the map of
    125                         /// type variables for the function type of the adapted expression.
    126                         FunctionDecl *makeAdapter( FunctionType const *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars );
     118                        FunctionDecl *makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars );
    127119                        /// Replaces intrinsic operator functions with their arithmetic desugaring
    128120                        Expression *handleIntrinsics( ApplicationExpr *appExpr );
     
    190182                        ObjectDecl *makeVar( const std::string &name, Type *type, Initializer *init = 0 );
    191183                        /// returns true if the type has a dynamic layout; such a layout will be stored in appropriately-named local variables when the function returns
    192                         bool findGeneric( Type const *ty );
     184                        bool findGeneric( Type *ty );
    193185                        /// adds type parameters to the layout call; will generate the appropriate parameters if needed
    194186                        void addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams );
     
    229221        } // anonymous namespace
    230222
     223        /// version of mutateAll with special handling for translation unit so you can check the end of the prelude when debugging
     224        template< typename MutatorType >
     225        inline void mutateTranslationUnit( std::list< Declaration* > &translationUnit, MutatorType &mutator ) {
     226                bool seenIntrinsic = false;
     227                SemanticErrorException errors;
     228                for ( typename std::list< Declaration* >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) {
     229                        try {
     230                                if ( *i ) {
     231                                        if ( (*i)->get_linkage() == LinkageSpec::Intrinsic ) {
     232                                                seenIntrinsic = true;
     233                                        } else if ( seenIntrinsic ) {
     234                                                seenIntrinsic = false; // break on this line when debugging for end of prelude
     235                                        }
     236
     237                                        *i = dynamic_cast< Declaration* >( (*i)->acceptMutator( mutator ) );
     238                                        assert( *i );
     239                                } // if
     240                        } catch( SemanticErrorException &e ) {
     241                                errors.append( e );
     242                        } // try
     243                } // for
     244                if ( ! errors.isEmpty() ) {
     245                        throw errors;
     246                } // if
     247        }
     248
    231249        void box( std::list< Declaration *>& translationUnit ) {
    232250                PassVisitor<LayoutFunctionBuilder> layoutBuilder;
     
    245263        ////////////////////////////////// LayoutFunctionBuilder ////////////////////////////////////////////
    246264
     265        void LayoutFunctionBuilder::previsit( FunctionDecl *functionDecl ) {
     266                visit_children = false;
     267                maybeAccept( functionDecl->get_functionType(), *visitor );
     268                ++functionNesting;
     269                maybeAccept( functionDecl->get_statements(), *visitor );
     270                --functionNesting;
     271        }
     272
    247273        /// Get a list of type declarations that will affect a layout function
    248274        std::list< TypeDecl* > takeOtypeOnly( std::list< TypeDecl* > &decls ) {
    249275                std::list< TypeDecl * > otypeDecls;
    250276
    251                 for ( TypeDecl * const decl : decls ) {
    252                         if ( decl->isComplete() ) {
    253                                 otypeDecls.push_back( decl );
     277                for ( std::list< TypeDecl* >::const_iterator decl = decls.begin(); decl != decls.end(); ++decl ) {
     278                        if ( (*decl)->isComplete() ) {
     279                                otypeDecls.push_back( *decl );
    254280                        }
    255281                }
     
    262288                BasicType sizeAlignType( Type::Qualifiers(), BasicType::LongUnsignedInt );
    263289
    264                 for ( TypeDecl * const param : otypeParams ) {
    265                         TypeInstType paramType( Type::Qualifiers(), param->get_name(), param );
     290                for ( std::list< TypeDecl* >::const_iterator param = otypeParams.begin(); param != otypeParams.end(); ++param ) {
     291                        TypeInstType paramType( Type::Qualifiers(), (*param)->get_name(), *param );
    266292                        std::string paramName = mangleType( &paramType );
    267293                        layoutFnType->get_parameters().push_back( new ObjectDecl( sizeofName( paramName ), Type::StorageClasses(), LinkageSpec::Cforall, 0, sizeAlignType.clone(), 0 ) );
     
    271297
    272298        /// Builds a layout function declaration
    273         FunctionDecl *buildLayoutFunctionDecl( AggregateDecl *typeDecl, bool isInFunction, FunctionType *layoutFnType ) {
     299        FunctionDecl *buildLayoutFunctionDecl( AggregateDecl *typeDecl, unsigned int functionNesting, FunctionType *layoutFnType ) {
    274300                // Routines at global scope marked "static" to prevent multiple definitions is separate translation units
    275301                // because each unit generates copies of the default routines for each aggregate.
    276302                FunctionDecl *layoutDecl = new FunctionDecl( layoutofName( typeDecl ),
    277                                                                                                          isInFunction ? Type::StorageClasses() : Type::StorageClasses( Type::Static ),
     303                                                                                                         functionNesting > 0 ? Type::StorageClasses() : Type::StorageClasses( Type::Static ),
    278304                                                                                                         LinkageSpec::AutoGen, layoutFnType, new CompoundStmt(),
    279305                                                                                                         std::list< Attribute * >(), Type::FuncSpecifiers( Type::Inline ) );
    280306                layoutDecl->fixUniqueId();
    281307                return layoutDecl;
     308        }
     309
     310        /// Makes a unary operation
     311        Expression *makeOp( const std::string &name, Expression *arg ) {
     312                UntypedExpr *expr = new UntypedExpr( new NameExpr( name ) );
     313                expr->args.push_back( arg );
     314                return expr;
    282315        }
    283316
     
    347380
    348381                // build function decl
    349                 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( structDecl, isInFunction(), layoutFnType );
     382                FunctionDecl *layoutDecl = buildLayoutFunctionDecl( structDecl, functionNesting, layoutFnType );
    350383
    351384                // calculate struct layout in function body
     
    354387                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 0 ) ) ) );
    355388                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
    356                 for ( auto index_member : enumerate( structDecl->members ) ) {
    357                         DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( index_member.val );
     389                unsigned long n_members = 0;
     390                bool firstMember = true;
     391                for ( Declaration* member : structDecl->get_members() ) {
     392                        DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( member );
    358393                        assert( dwt );
    359394                        Type *memberType = dwt->get_type();
    360395
    361                         if ( 0 < index_member.idx ) {
     396                        if ( firstMember ) {
     397                                firstMember = false;
     398                        } else {
    362399                                // make sure all members after the first (automatically aligned at 0) are properly padded for alignment
    363400                                addStmt( layoutDecl->get_statements(), makeAlignTo( derefVar( sizeParam ), new AlignofExpr( memberType->clone() ) ) );
     
    365402
    366403                        // place current size in the current offset index
    367                         addExpr( layoutDecl->get_statements(), makeOp( "?=?", makeOp( "?[?]", new VariableExpr( offsetParam ), new ConstantExpr( Constant::from_ulong( index_member.idx ) ) ),
     404                        addExpr( layoutDecl->get_statements(), makeOp( "?=?", makeOp( "?[?]", new VariableExpr( offsetParam ), new ConstantExpr( Constant::from_ulong( n_members ) ) ),
    368405                                                                              derefVar( sizeParam ) ) );
     406                        ++n_members;
    369407
    370408                        // add member size to current size
     
    401439
    402440                // build function decl
    403                 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( unionDecl, isInFunction(), layoutFnType );
     441                FunctionDecl *layoutDecl = buildLayoutFunctionDecl( unionDecl, functionNesting, layoutFnType );
    404442
    405443                // calculate union layout in function body
    406444                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
    407445                addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) );
    408                 for ( Declaration * const member : unionDecl->members ) {
    409                         DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( member );
     446                for ( std::list< Declaration* >::const_iterator member = unionDecl->get_members().begin(); member != unionDecl->get_members().end(); ++member ) {
     447                        DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( *member );
    410448                        assert( dwt );
    411449                        Type *memberType = dwt->get_type();
     
    426464
    427465        namespace {
    428                 std::string makePolyMonoSuffix( FunctionType const * function, const TyVarMap &tyVars ) {
     466                std::string makePolyMonoSuffix( FunctionType * function, const TyVarMap &tyVars ) {
    429467                        std::stringstream name;
    430468
     
    435473                        // to take those polymorphic types as pointers. Therefore, there can be two different functions
    436474                        // with the same mangled name, so we need to further mangle the names.
    437                         for ( DeclarationWithType const * const ret : function->returnVals ) {
    438                                 if ( isPolyType( ret->get_type(), tyVars ) ) {
     475                        for ( std::list< DeclarationWithType *>::iterator retval = function->get_returnVals().begin(); retval != function->get_returnVals().end(); ++retval ) {
     476                                if ( isPolyType( (*retval)->get_type(), tyVars ) ) {
    439477                                        name << "P";
    440478                                } else {
     
    443481                        }
    444482                        name << "_";
    445                         for ( DeclarationWithType const * const arg : function->parameters ) {
    446                                 if ( isPolyType( arg->get_type(), tyVars ) ) {
     483                        std::list< DeclarationWithType *> &paramList = function->get_parameters();
     484                        for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) {
     485                                if ( isPolyType( (*arg)->get_type(), tyVars ) ) {
    447486                                        name << "P";
    448487                                } else {
     
    453492                }
    454493
    455                 std::string mangleAdapterName( FunctionType const * function, const TyVarMap &tyVars ) {
     494                std::string mangleAdapterName( FunctionType * function, const TyVarMap &tyVars ) {
    456495                        return SymTab::Mangler::mangle( function ) + makePolyMonoSuffix( function, tyVars );
    457496                }
     
    460499                        return "_adapter" + mangleName;
    461500                }
    462 
    463                 /// Replaces a polymorphic type with its concrete equivalant under the current environment (returns itself if concrete).
    464                 /// If `doClone` is set to false, will not clone interior types
    465                 Type *replaceWithConcrete( Type *type, TypeSubstitution const * env, bool doClone = true );
    466501
    467502                Pass1::Pass1() : tempNamer( "_temp" ) {}
     
    489524
    490525                                std::list< DeclarationWithType *> &paramList = functionType->parameters;
    491                                 std::list< FunctionType const *> functions;
    492                                 for ( TypeDecl * const tyVar : functionType->forall ) {
    493                                         for ( DeclarationWithType * const assert : tyVar->assertions ) {
    494                                                 findFunction( assert->get_type(), functions, scopeTyVars, needsAdapter );
     526                                std::list< FunctionType *> functions;
     527                                for ( Type::ForallList::iterator tyVar = functionType->forall.begin(); tyVar != functionType->forall.end(); ++tyVar ) {
     528                                        for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->assertions.begin(); assert != (*tyVar)->assertions.end(); ++assert ) {
     529                                                findFunction( (*assert)->get_type(), functions, scopeTyVars, needsAdapter );
    495530                                        } // for
    496531                                } // for
    497                                 for ( DeclarationWithType * const arg : paramList ) {
    498                                         findFunction( arg->get_type(), functions, scopeTyVars, needsAdapter );
     532                                for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) {
     533                                        findFunction( (*arg)->get_type(), functions, scopeTyVars, needsAdapter );
    499534                                } // for
    500535
    501                                 for ( FunctionType const * const funType : functions ) {
    502                                         std::string mangleName = mangleAdapterName( funType, scopeTyVars );
     536                                for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType ) {
     537                                        std::string mangleName = mangleAdapterName( *funType, scopeTyVars );
    503538                                        if ( adapters.find( mangleName ) == adapters.end() ) {
    504539                                                std::string adapterName = makeAdapterName( mangleName );
    505                                                 adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, nullptr, new PointerType( Type::Qualifiers(), makeAdapterType( funType, scopeTyVars ) ), nullptr ) ) );
     540                                                adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, nullptr, new PointerType( Type::Qualifiers(), makeAdapterType( *funType, scopeTyVars ) ), nullptr ) ) );
    506541                                        } // if
    507542                                } // for
     
    558593                }
    559594
    560                 std::list< Expression *>::iterator Pass1::passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, const TyVarMap &exprTyVars ) {
    561                         assert( env );
    562                         std::list< Expression *>::iterator arg = appExpr->args.begin();
     595                void Pass1::passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) {
    563596                        // pass size/align for type variables
    564                         for ( std::pair<std::string, TypeDecl::Data> const & tyParam : exprTyVars ) {
     597                        for ( TyVarMap::const_iterator tyParm = exprTyVars.begin(); tyParm != exprTyVars.end(); ++tyParm ) {
    565598                                ResolvExpr::EqvClass eqvClass;
    566                                 if ( tyParam.second.isComplete ) {
    567                                         Type *concrete = env->lookup( tyParam.first );
    568                                         // If there is an unbound type variable, it should have detected already.
    569                                         assertf( concrete, "Unbound type variable: %s in: %s",
    570                                                 toCString( tyParam.first ), toCString( *env ) );
    571 
    572                                         arg = appExpr->get_args().insert( arg, new SizeofExpr( concrete->clone() ) );
    573                                         arg++;
    574                                         arg = appExpr->get_args().insert( arg, new AlignofExpr( concrete->clone() ) );
    575                                         arg++;
     599                                assert( env );
     600                                if ( tyParm->second.isComplete ) {
     601                                        Type *concrete = env->lookup( tyParm->first );
     602                                        if ( concrete ) {
     603                                                arg = appExpr->get_args().insert( arg, new SizeofExpr( concrete->clone() ) );
     604                                                arg++;
     605                                                arg = appExpr->get_args().insert( arg, new AlignofExpr( concrete->clone() ) );
     606                                                arg++;
     607                                        } else {
     608                                                // xxx - should this be an assertion?
     609                                                SemanticError( appExpr, toString( *env, "\nunbound type variable: ", tyParm->first, " in application " ) );
     610                                        } // if
    576611                                } // if
    577612                        } // for
    578613
    579614                        // add size/align for generic types to parameter list
    580                         if ( ! appExpr->get_function()->result ) return arg;
     615                        if ( ! appExpr->get_function()->result ) return;
    581616                        FunctionType *funcType = getFunctionType( appExpr->get_function()->get_result() );
    582617                        assert( funcType );
    583618
    584                         // These iterators don't advance in unison.
    585619                        std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin();
    586620                        std::list< Expression* >::const_iterator fnArg = arg;
     
    589623                        // a polymorphic return type may need to be added to the argument list
    590624                        if ( polyRetType ) {
    591                                 Type *concRetType = replaceWithConcrete( polyRetType, env );
     625                                Type *concRetType = replaceWithConcrete( appExpr, polyRetType );
    592626                                passArgTypeVars( appExpr, polyRetType, concRetType, arg, exprTyVars, seenTypes );
    593627                                ++fnArg; // skip the return parameter in the argument list
     
    600634                                passArgTypeVars( appExpr, (*fnParm)->get_type(), argType, arg, exprTyVars, seenTypes );
    601635                        }
    602                         return arg;
    603636                }
    604637
     
    609642                }
    610643
    611                 Expression *Pass1::addRetParam( ApplicationExpr *appExpr, Type *retType ) {
     644                Expression *Pass1::addRetParam( ApplicationExpr *appExpr, Type *retType, std::list< Expression *>::iterator &arg ) {
    612645                        // Create temporary to hold return value of polymorphic function and produce that temporary as a result
    613646                        // using a comma expression.
     
    629662                                paramExpr = new AddressExpr( paramExpr );
    630663                        } // if
    631                         // Add argument to function call.
    632                         appExpr->args.push_front( paramExpr );
     664                        arg = appExpr->args.insert( arg, paramExpr ); // add argument to function call
     665                        arg++;
    633666                        // Build a comma expression to call the function and emulate a normal return.
    634667                        CommaExpr *commaExpr = new CommaExpr( appExpr, retExpr );
     
    638671                }
    639672
    640                 /// Replaces all the type parameters of a generic type with their concrete equivalents under the current environment
    641                 void replaceParametersWithConcrete( std::list< Expression* >& params, TypeSubstitution const * env ) {
    642                         for ( Expression * const param : params ) {
    643                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( param );
     673                void Pass1::replaceParametersWithConcrete( ApplicationExpr *appExpr, std::list< Expression* >& params ) {
     674                        for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
     675                                TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    644676                                assertf(paramType, "Aggregate parameters should be type expressions");
    645                                 paramType->set_type( replaceWithConcrete( paramType->get_type(), env, false ) );
    646                         }
    647                 }
    648 
    649                 // See forward definition.
    650                 Type *replaceWithConcrete( Type *type, TypeSubstitution const * env, bool doClone ) {
    651                         assert( env );
     677                                paramType->set_type( replaceWithConcrete( appExpr, paramType->get_type(), false ) );
     678                        }
     679                }
     680
     681                Type *Pass1::replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone ) {
    652682                        if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
    653683                                Type *concrete = env->lookup( typeInst->get_name() );
     
    660690                                        structType = structType->clone();
    661691                                }
    662                                 replaceParametersWithConcrete( structType->get_parameters(), env );
     692                                replaceParametersWithConcrete( appExpr, structType->get_parameters() );
    663693                                return structType;
    664694                        } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
     
    666696                                        unionType = unionType->clone();
    667697                                }
    668                                 replaceParametersWithConcrete( unionType->get_parameters(), env );
     698                                replaceParametersWithConcrete( appExpr, unionType->get_parameters() );
    669699                                return unionType;
    670700                        }
     
    672702                }
    673703
    674                 Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType ) {
    675                         Type *concrete = replaceWithConcrete( dynType, env );
     704                Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType, std::list< Expression *>::iterator &arg ) {
     705                        assert( env );
     706                        Type *concrete = replaceWithConcrete( appExpr, dynType );
    676707                        // add out-parameter for return value
    677                         return addRetParam( appExpr, concrete );
    678                 }
    679 
    680                 Expression *Pass1::applyAdapter( ApplicationExpr *appExpr, FunctionType *function ) {
     708                        return addRetParam( appExpr, concrete, arg );
     709                }
     710
     711                Expression *Pass1::applyAdapter( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars ) {
    681712                        Expression *ret = appExpr;
    682713//                      if ( ! function->get_returnVals().empty() && isPolyType( function->get_returnVals().front()->get_type(), tyVars ) ) {
    683                         if ( isDynRet( function, scopeTyVars ) ) {
    684                                 ret = addRetParam( appExpr, function->returnVals.front()->get_type() );
     714                        if ( isDynRet( function, tyVars ) ) {
     715                                ret = addRetParam( appExpr, function->returnVals.front()->get_type(), arg );
    685716                        } // if
    686                         std::string mangleName = mangleAdapterName( function, scopeTyVars );
     717                        std::string mangleName = mangleAdapterName( function, tyVars );
    687718                        std::string adapterName = makeAdapterName( mangleName );
    688719
     
    693724
    694725                        return ret;
     726                }
     727
     728                void Pass1::boxParam( Type *param, Expression *&arg, const TyVarMap &exprTyVars ) {
     729                        assertf( arg->result, "arg does not have result: %s", toString( arg ).c_str() );
     730                        if ( ! needsBoxing( param, arg->result, exprTyVars, env ) ) return;
     731
     732                        if ( arg->get_lvalue() ) {
     733                                // argument expression may be CFA lvalue, but not C lvalue -- apply generalizedLvalue transformations.
     734                                // if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( arg ) ) {
     735                                //      if ( dynamic_cast<ArrayType *>( varExpr->var->get_type() ) ){
     736                                //              // temporary hack - don't box arrays, because &arr is not the same as &arr[0]
     737                                //              return;
     738                                //      }
     739                                // }
     740                                arg =  generalizedLvalue( new AddressExpr( arg ) );
     741                                if ( ! ResolvExpr::typesCompatible( param, arg->get_result(), SymTab::Indexer() ) ) {
     742                                        // silence warnings by casting boxed parameters when the actual type does not match up with the formal type.
     743                                        arg = new CastExpr( arg, param->clone() );
     744                                }
     745                        } else {
     746                                // use type computed in unification to declare boxed variables
     747                                Type * newType = param->clone();
     748                                if ( env ) env->apply( newType );
     749                                ObjectDecl *newObj = ObjectDecl::newObject( tempNamer.newName(), newType, nullptr );
     750                                newObj->get_type()->get_qualifiers() = Type::Qualifiers(); // TODO: is this right???
     751                                stmtsToAddBefore.push_back( new DeclStmt( newObj ) );
     752                                UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) ); // TODO: why doesn't this just use initialization syntax?
     753                                assign->get_args().push_back( new VariableExpr( newObj ) );
     754                                assign->get_args().push_back( arg );
     755                                stmtsToAddBefore.push_back( new ExprStmt( assign ) );
     756                                arg = new AddressExpr( new VariableExpr( newObj ) );
     757                        } // if
    695758                }
    696759
     
    728791                }
    729792
    730                 void Pass1::boxParam( Expression *&arg, Type *param, const TyVarMap &exprTyVars ) {
    731                         assertf( arg->result, "arg does not have result: %s", toString( arg ).c_str() );
    732                         addCast( arg, param, exprTyVars );
    733                         if ( ! needsBoxing( param, arg->result, exprTyVars, env ) ) return;
    734 
    735                         if ( arg->get_lvalue() ) {
    736                                 // argument expression may be CFA lvalue, but not C lvalue -- apply generalizedLvalue transformations.
    737                                 // if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( arg ) ) {
    738                                 //      if ( dynamic_cast<ArrayType *>( varExpr->var->get_type() ) ){
    739                                 //              // temporary hack - don't box arrays, because &arr is not the same as &arr[0]
    740                                 //              return;
    741                                 //      }
    742                                 // }
    743                                 arg = generalizedLvalue( new AddressExpr( arg ) );
    744                                 if ( ! ResolvExpr::typesCompatible( param, arg->get_result(), SymTab::Indexer() ) ) {
    745                                         // silence warnings by casting boxed parameters when the actual type does not match up with the formal type.
    746                                         arg = new CastExpr( arg, param->clone() );
    747                                 }
    748                         } else {
    749                                 // use type computed in unification to declare boxed variables
    750                                 Type * newType = param->clone();
    751                                 if ( env ) env->apply( newType );
    752                                 ObjectDecl *newObj = makeTemporary( newType );
    753                                 // TODO: is this right??? (Why wouldn't it be?)
    754                                 newObj->get_type()->get_qualifiers() = Type::Qualifiers();
    755                                 // TODO: why doesn't this just use initialization syntax?
    756                                 // (Possibly to ensure code is run at the right time.)
    757                                 UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) );
    758                                 assign->get_args().push_back( new VariableExpr( newObj ) );
    759                                 assign->get_args().push_back( arg );
    760                                 stmtsToAddBefore.push_back( new ExprStmt( assign ) );
    761                                 arg = new AddressExpr( new VariableExpr( newObj ) );
    762                         } // if
    763                 }
    764 
    765                 void Pass1::boxParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *function, const TyVarMap &exprTyVars ) {
    766                         for ( DeclarationWithType * param : function->parameters ) {
    767                                 assertf( arg != appExpr->args.end(), "boxParams: missing argument for param %s to %s in %s", toString( param ).c_str(), toString( function ).c_str(), toString( appExpr ).c_str() );
    768                                 boxParam( *arg, param->get_type(), exprTyVars );
    769                                 ++arg;
     793                void Pass1::boxParams( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) {
     794                        for ( std::list< DeclarationWithType *>::const_iterator param = function->get_parameters().begin(); param != function->parameters.end(); ++param, ++arg ) {
     795                                assertf( arg != appExpr->args.end(), "boxParams: missing argument for param %s to %s in %s", toString( *param ).c_str(), toString( function ).c_str(), toString( appExpr ).c_str() );
     796                                addCast( *arg, (*param)->get_type(), exprTyVars );
     797                                boxParam( (*param)->get_type(), *arg, exprTyVars );
    770798                        } // for
    771799                }
    772800
    773                 void Pass1::addInferredParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *functionType, const TyVarMap &tyVars ) {
     801                void Pass1::addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars ) {
    774802                        std::list< Expression *>::iterator cur = arg;
    775                         for ( TypeDecl * const tyVar : functionType->forall ) {
    776                                 for ( DeclarationWithType * const assert : tyVar->assertions ) {
    777                                         InferredParams::const_iterator inferParam = appExpr->inferParams.find( assert->get_uniqueId() );
    778                                         assertf( inferParam != appExpr->inferParams.end(), "addInferredParams missing inferred parameter: %s in: %s", toString( assert ).c_str(), toString( appExpr ).c_str() );
     803                        for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {
     804                                for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->assertions.begin(); assert != (*tyVar)->assertions.end(); ++assert ) {
     805                                        InferredParams::const_iterator inferParam = appExpr->inferParams.find( (*assert)->get_uniqueId() );
     806                                        assertf( inferParam != appExpr->inferParams.end(), "addInferredParams missing inferred parameter: %s in: %s", toString( *assert ).c_str(), toString( appExpr ).c_str() );
    779807                                        Expression *newExpr = inferParam->second.expr->clone();
    780                                         boxParam( newExpr, assert->get_type(), tyVars );
     808                                        addCast( newExpr, (*assert)->get_type(), tyVars );
     809                                        boxParam( (*assert)->get_type(), newExpr, tyVars );
    781810                                        appExpr->get_args().insert( cur, newExpr );
    782811                                } // for
     
    795824                }
    796825
    797                 FunctionType *makeAdapterType( FunctionType const *adaptee, const TyVarMap &tyVars ) {
     826                FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars ) {
    798827                        // actually make the adapter type
    799828                        FunctionType *adapter = adaptee->clone();
     
    805834                }
    806835
    807                 Expression *makeAdapterArg(
    808                                 DeclarationWithType *param,
    809                                 DeclarationWithType const *arg,
    810                                 DeclarationWithType const *realParam,
    811                                 const TyVarMap &tyVars ) {
     836                Expression *makeAdapterArg( DeclarationWithType *param, DeclarationWithType *arg, DeclarationWithType *realParam, const TyVarMap &tyVars ) {
    812837                        assert( param );
    813838                        assert( arg );
    814                         if ( isPolyType( realParam->get_type(), tyVars )
    815                                         && ! isPolyType( arg->get_type() ) ) {
    816                                 UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
    817                                 deref->args.push_back( new CastExpr( new VariableExpr( param ), new PointerType( Type::Qualifiers(), arg->get_type()->clone() ) ) );
    818                                 deref->result = arg->get_type()->clone();
    819                                 return deref;
     839                        if ( isPolyType( realParam->get_type(), tyVars ) ) {
     840                                if ( ! isPolyType( arg->get_type() ) ) {
     841                                        UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
     842                                        deref->args.push_back( new CastExpr( new VariableExpr( param ), new PointerType( Type::Qualifiers(), arg->get_type()->clone() ) ) );
     843                                        deref->result = arg->get_type()->clone();
     844                                        return deref;
     845                                } // if
    820846                        } // if
    821847                        return new VariableExpr( param );
    822848                }
    823849
    824                 void addAdapterParams(
    825                                 ApplicationExpr *adapteeApp,
    826                                 std::list< DeclarationWithType *>::const_iterator arg,
    827                                 std::list< DeclarationWithType *>::const_iterator param,
    828                                 std::list< DeclarationWithType *>::const_iterator paramEnd,
    829                                 std::list< DeclarationWithType *>::const_iterator realParam,
    830                                 const TyVarMap &tyVars ) {
     850                void addAdapterParams( ApplicationExpr *adapteeApp, std::list< DeclarationWithType *>::iterator arg, std::list< DeclarationWithType *>::iterator param, std::list< DeclarationWithType *>::iterator paramEnd, std::list< DeclarationWithType *>::iterator realParam, const TyVarMap &tyVars ) {
    831851                        UniqueName paramNamer( "_p" );
    832852                        for ( ; param != paramEnd; ++param, ++arg, ++realParam ) {
     
    839859                }
    840860
    841                 FunctionDecl *Pass1::makeAdapter( FunctionType const *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) {
     861                FunctionDecl *Pass1::makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) {
    842862                        FunctionType *adapterType = makeAdapterType( adaptee, tyVars );
    843863                        adapterType = ScrubTyVars::scrub( adapterType, tyVars );
     
    856876                        Statement *bodyStmt;
    857877
    858                         for ( auto tys : group_iterate( realType->forall, adapterType->forall, adaptee->forall ) ) {
    859                                 TypeDecl * tyArg = std::get<0>( tys );
    860                                 TypeDecl * tyParam = std::get<1>( tys );
    861                                 TypeDecl * realTyParam = std::get<2>( tys );
    862                                 for ( auto asserts : group_iterate( tyArg->assertions, tyParam->assertions, realTyParam->assertions ) ) {
    863                                         DeclarationWithType * assertArg = std::get<0>( asserts );
    864                                         DeclarationWithType * assertParam = std::get<1>( asserts );
    865                                         DeclarationWithType * realAssertParam = std::get<2>( asserts );
    866                                         adapteeApp->args.push_back( makeAdapterArg( assertParam, assertArg, realAssertParam, tyVars ) );
     878                        Type::ForallList::iterator tyArg = realType->get_forall().begin();
     879                        Type::ForallList::iterator tyParam = adapterType->get_forall().begin();
     880                        Type::ForallList::iterator realTyParam = adaptee->get_forall().begin();
     881                        for ( ; tyParam != adapterType->get_forall().end(); ++tyArg, ++tyParam, ++realTyParam ) {
     882                                assert( tyArg != realType->get_forall().end() );
     883                                std::list< DeclarationWithType *>::iterator assertArg = (*tyArg)->get_assertions().begin();
     884                                std::list< DeclarationWithType *>::iterator assertParam = (*tyParam)->get_assertions().begin();
     885                                std::list< DeclarationWithType *>::iterator realAssertParam = (*realTyParam)->get_assertions().begin();
     886                                for ( ; assertParam != (*tyParam)->get_assertions().end(); ++assertArg, ++assertParam, ++realAssertParam ) {
     887                                        assert( assertArg != (*tyArg)->get_assertions().end() );
     888                                        adapteeApp->get_args().push_back( makeAdapterArg( *assertParam, *assertArg, *realAssertParam, tyVars ) );
    867889                                } // for
    868890                        } // for
    869891
    870                         std::list< DeclarationWithType *>::const_iterator arg = realType->parameters.begin();
    871                         std::list< DeclarationWithType *>::const_iterator param = adapterType->parameters.begin();
    872                         std::list< DeclarationWithType *>::const_iterator realParam = adaptee->parameters.begin();
     892                        std::list< DeclarationWithType *>::iterator arg = realType->get_parameters().begin();
     893                        std::list< DeclarationWithType *>::iterator param = adapterType->get_parameters().begin();
     894                        std::list< DeclarationWithType *>::iterator realParam = adaptee->get_parameters().begin();
    873895                        param++;                // skip adaptee parameter in the adapter type
    874896                        if ( realType->get_returnVals().empty() ) {
     
    876898                                addAdapterParams( adapteeApp, arg, param, adapterType->get_parameters().end(), realParam, tyVars );
    877899                                bodyStmt = new ExprStmt( adapteeApp );
    878                         } else if ( isDynType( adaptee->returnVals.front()->get_type(), tyVars ) ) {
     900                        } else if ( isDynType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) {
    879901                                // return type T
    880902                                if ( (*param)->get_name() == "" ) {
     
    901923                void Pass1::passAdapters( ApplicationExpr * appExpr, FunctionType * functionType, const TyVarMap & exprTyVars ) {
    902924                        // collect a list of function types passed as parameters or implicit parameters (assertions)
    903                         std::list<FunctionType const *> functions;
    904                         for ( TypeDecl * const tyVar : functionType->get_forall() ) {
    905                                 for ( DeclarationWithType * const assert : tyVar->get_assertions() ) {
    906                                         findFunction( assert->get_type(), functions, exprTyVars, needsAdapter );
     925                        std::list< DeclarationWithType *> &paramList = functionType->get_parameters();
     926                        std::list< FunctionType *> functions;
     927                        for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {
     928                                for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->get_assertions().begin(); assert != (*tyVar)->get_assertions().end(); ++assert ) {
     929                                        findFunction( (*assert)->get_type(), functions, exprTyVars, needsAdapter );
    907930                                } // for
    908931                        } // for
    909                         for ( DeclarationWithType * const arg : functionType->get_parameters() ) {
    910                                 findFunction( arg->get_type(), functions, exprTyVars, needsAdapter );
     932                        for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) {
     933                                findFunction( (*arg)->get_type(), functions, exprTyVars, needsAdapter );
    911934                        } // for
    912935
     
    915938                        std::set< std::string > adaptersDone;
    916939
    917                         for ( FunctionType const * const funType : functions ) {
    918                                 FunctionType *originalFunction = funType->clone();
    919                                 FunctionType *realFunction = funType->clone();
     940                        for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType ) {
     941                                FunctionType *originalFunction = (*funType)->clone();
     942                                FunctionType *realFunction = (*funType)->clone();
    920943                                std::string mangleName = SymTab::Mangler::mangle( realFunction );
    921944
     
    935958                                        if ( adapter == adapters.end() ) {
    936959                                                // adapter has not been created yet in the current scope, so define it
    937                                                 FunctionDecl *newAdapter = makeAdapter( funType, realFunction, mangleName, exprTyVars );
     960                                                FunctionDecl *newAdapter = makeAdapter( *funType, realFunction, mangleName, exprTyVars );
    938961                                                std::pair< AdapterIter, bool > answer = adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, newAdapter ) );
    939962                                                adapter = answer.first;
     
    949972
    950973                Expression *makeIncrDecrExpr( ApplicationExpr *appExpr, Type *polyType, bool isIncr ) {
    951                         NameExpr *opExpr = new NameExpr( ( isIncr ) ? "?+=?" : "?-=?" );
     974                        NameExpr *opExpr;
     975                        if ( isIncr ) {
     976                                opExpr = new NameExpr( "?+=?" );
     977                        } else {
     978                                opExpr = new NameExpr( "?-=?" );
     979                        } // if
    952980                        UntypedExpr *addAssign = new UntypedExpr( opExpr );
    953981                        if ( AddressExpr *address = dynamic_cast< AddressExpr *>( appExpr->get_args().front() ) ) {
     
    10921120                Expression *Pass1::postmutate( ApplicationExpr *appExpr ) {
    10931121                        // std::cerr << "mutate appExpr: " << InitTweak::getFunctionName( appExpr ) << std::endl;
    1094                         // for ( auto tyVar : scopeTyVars ) {
    1095                         //      std::cerr << tyVar.first << " ";
     1122                        // for ( TyVarMap::iterator i = scopeTyVars.begin(); i != scopeTyVars.end(); ++i ) {
     1123                        //      std::cerr << i->first << " ";
    10961124                        // }
    10971125                        // std::cerr << "\n";
     
    11061134
    11071135                        Expression *ret = appExpr;
     1136
     1137                        std::list< Expression *>::iterator arg = appExpr->get_args().begin();
    11081138                        std::list< Expression *>::iterator paramBegin = appExpr->get_args().begin();
    11091139
     
    11261156                                // std::cerr << "dynRetType: " << dynRetType << std::endl;
    11271157                                Type *concRetType = appExpr->get_result()->isVoid() ? nullptr : appExpr->get_result();
    1128                                 ret = addDynRetParam( appExpr, concRetType ); // xxx - used to use dynRetType instead of concRetType
     1158                                ret = addDynRetParam( appExpr, concRetType, arg ); // xxx - used to use dynRetType instead of concRetType
    11291159                        } else if ( needsAdapter( function, scopeTyVars ) && ! needsAdapter( function, exprTyVars) ) { // xxx - exprTyVars is used above...?
    11301160                                // xxx - the ! needsAdapter check may be incorrect. It seems there is some situation where an adapter is applied where it shouldn't be, and this fixes it for some cases. More investigation is needed.
     
    11341164                                // std::cerr << *env << std::endl;
    11351165                                // change the application so it calls the adapter rather than the passed function
    1136                                 ret = applyAdapter( appExpr, function );
     1166                                ret = applyAdapter( appExpr, function, arg, scopeTyVars );
    11371167                        } // if
    1138 
    1139                         Type *concRetType = replaceWithConcrete( dynRetType, env );
    1140                         std::list< Expression *>::iterator arg =
    1141                                 passTypeVars( appExpr, concRetType, exprTyVars ); // xxx - used to use dynRetType instead of concRetType; this changed so that the correct type paramaters are passed for return types (it should be the concrete type's parameters, not the formal type's)
    1142                         addInferredParams( appExpr, arg, function, exprTyVars );
    1143 
    1144                         // This needs to point at the original first argument.
    1145                         boxParams( appExpr, paramBegin, function, exprTyVars );
    1146 
     1168                        arg = appExpr->get_args().begin();
     1169
     1170                        Type *concRetType = replaceWithConcrete( appExpr, dynRetType );
     1171                        passTypeVars( appExpr, concRetType, arg, exprTyVars ); // xxx - used to use dynRetType instead of concRetType; this changed so that the correct type paramaters are passed for return types (it should be the concrete type's parameters, not the formal type's)
     1172                        addInferredParams( appExpr, function, arg, exprTyVars );
     1173
     1174                        arg = paramBegin;
     1175
     1176                        boxParams( appExpr, function, arg, exprTyVars );
    11471177                        passAdapters( appExpr, function, exprTyVars );
    11481178
     
    11501180                }
    11511181
    1152                 bool isPolyDeref( UntypedExpr const * expr, TyVarMap const & scopeTyVars, TypeSubstitution const * env ) {
     1182                Expression * Pass1::postmutate( UntypedExpr *expr ) {
    11531183                        if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) {
    1154                                 if ( auto name = dynamic_cast<NameExpr const *>( expr->function ) ) {
     1184                                if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) {
    11551185                                        if ( name->name == "*?" ) {
    1156                                                 return true;
     1186                                                Expression *ret = expr->args.front();
     1187                                                expr->args.clear();
     1188                                                delete expr;
     1189                                                return ret;
    11571190                                        } // if
    11581191                                } // if
    11591192                        } // if
    1160                         return false;
    1161                 }
    1162 
    1163                 Expression * Pass1::postmutate( UntypedExpr *expr ) {
    1164                         if ( isPolyDeref( expr, scopeTyVars, env ) ) {
    1165                                 Expression *ret = expr->args.front();
    1166                                 expr->args.clear();
    1167                                 delete expr;
    1168                                 return ret;
    1169                         }
    11701193                        return expr;
    11711194                }
     
    11771200                        bool needs = false;
    11781201                        if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->arg ) ) {
    1179                                 if ( isPolyDeref( expr, scopeTyVars, env ) ) {
    1180                                         if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->args.front() ) ) {
    1181                                                 assert( appExpr->function->result );
    1182                                                 FunctionType *function = getFunctionType( appExpr->function->result );
    1183                                                 assert( function );
    1184                                                 needs = needsAdapter( function, scopeTyVars );
     1202                                if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) {
     1203                                        if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) {
     1204                                                if ( name->name == "*?" ) {
     1205                                                        if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->args.front() ) ) {
     1206                                                                assert( appExpr->function->result );
     1207                                                                FunctionType *function = getFunctionType( appExpr->function->result );
     1208                                                                assert( function );
     1209                                                                needs = needsAdapter( function, scopeTyVars );
     1210                                                        } // if
     1211                                                } // if
    11851212                                        } // if
    11861213                                } // if
     
    12331260                void Pass2::addAdapters( FunctionType *functionType ) {
    12341261                        std::list< DeclarationWithType *> &paramList = functionType->parameters;
    1235                         std::list< FunctionType const *> functions;
    1236                         for ( DeclarationWithType * const arg : functionType->parameters ) {
    1237                                 Type *orig = arg->get_type();
     1262                        std::list< FunctionType *> functions;
     1263                        for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) {
     1264                                Type *orig = (*arg)->get_type();
    12381265                                findAndReplaceFunction( orig, functions, scopeTyVars, needsAdapter );
    1239                                 arg->set_type( orig );
     1266                                (*arg)->set_type( orig );
    12401267                        }
    12411268                        std::set< std::string > adaptersDone;
    1242                         for ( FunctionType const * const funType : functions ) {
    1243                                 std::string mangleName = mangleAdapterName( funType, scopeTyVars );
     1269                        for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType ) {
     1270                                std::string mangleName = mangleAdapterName( *funType, scopeTyVars );
    12441271                                if ( adaptersDone.find( mangleName ) == adaptersDone.end() ) {
    12451272                                        std::string adapterName = makeAdapterName( mangleName );
    12461273                                        // adapter may not be used in body, pass along with unused attribute.
    1247                                         paramList.push_front( new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), makeAdapterType( funType, scopeTyVars ) ), 0, { new Attribute( "unused" ) } ) );
     1274                                        paramList.push_front( new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), makeAdapterType( *funType, scopeTyVars ) ), 0, { new Attribute( "unused" ) } ) );
    12481275                                        adaptersDone.insert( adaptersDone.begin(), mangleName );
    12491276                                }
     
    13221349                        ObjectDecl newPtr( "", Type::StorageClasses(), LinkageSpec::C, 0,
    13231350                                           new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ), 0 );
    1324                         for ( TypeDecl * const tyParam : funcType->get_forall() ) {
     1351                        for ( Type::ForallList::const_iterator tyParm = funcType->get_forall().begin(); tyParm != funcType->get_forall().end(); ++tyParm ) {
    13251352                                ObjectDecl *sizeParm, *alignParm;
    13261353                                // add all size and alignment parameters to parameter list
    1327                                 if ( tyParam->isComplete() ) {
    1328                                         TypeInstType parmType( Type::Qualifiers(), tyParam->get_name(), tyParam );
     1354                                if ( (*tyParm)->isComplete() ) {
     1355                                        TypeInstType parmType( Type::Qualifiers(), (*tyParm)->get_name(), *tyParm );
    13291356                                        std::string parmName = mangleType( &parmType );
    13301357
     
    13401367                                }
    13411368                                // move all assertions into parameter list
    1342                                 for ( DeclarationWithType * const assert : tyParam->get_assertions() ) {
     1369                                for ( std::list< DeclarationWithType *>::iterator assert = (*tyParm)->get_assertions().begin(); assert != (*tyParm)->get_assertions().end(); ++assert ) {
    13431370                                        // assertion parameters may not be used in body, pass along with unused attribute.
    1344                                         assert->get_attributes().push_back( new Attribute( "unused" ) );
    1345                                         inferredParams.push_back( assert );
    1346                                 }
    1347                                 tyParam->get_assertions().clear();
     1371                                        (*assert)->get_attributes().push_back( new Attribute( "unused" ) );
     1372                                        inferredParams.push_back( *assert );
     1373                                }
     1374                                (*tyParm)->get_assertions().clear();
    13481375                        }
    13491376
    13501377                        // add size/align for generic parameter types to parameter list
    13511378                        std::set< std::string > seenTypes; // sizeofName for generic types we've seen
    1352                         for ( DeclarationWithType * const fnParam : funcType->get_parameters() ) {
    1353                                 Type *polyType = isPolyType( fnParam->get_type(), scopeTyVars );
     1379                        for ( std::list< DeclarationWithType* >::const_iterator fnParm = last; fnParm != funcType->get_parameters().end(); ++fnParm ) {
     1380                                Type *polyType = isPolyType( (*fnParm)->get_type(), scopeTyVars );
    13541381                                if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) {
    13551382                                        std::string typeName = mangleType( polyType );
     
    14551482
    14561483                        if(!expect_func_type) {
     1484                                GuardAction( [this]() {
     1485                                        knownLayouts.endScope();
     1486                                        knownOffsets.endScope();
     1487                                });
    14571488                                // If this is the first function type we see
    14581489                                // Then it's the type of the declaration and we care about it
    1459                                 GuardScope( *this );
     1490                                knownLayouts.beginScope();
     1491                                knownOffsets.beginScope();
    14601492                        }
    14611493
     
    14651497
    14661498                        // make sure that any type information passed into the function is accounted for
    1467                         for ( DeclarationWithType * const fnParam : funcType->get_parameters() ) {
     1499                        for ( std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin(); fnParm != funcType->get_parameters().end(); ++fnParm ) {
    14681500                                // condition here duplicates that in Pass2::mutate( FunctionType* )
    1469                                 Type *polyType = isPolyType( fnParam->get_type(), scopeTyVars );
     1501                                Type *polyType = isPolyType( (*fnParm)->get_type(), scopeTyVars );
    14701502                                if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) {
    14711503                                        knownLayouts.insert( mangleType( polyType ) );
     
    14751507
    14761508                /// converts polymorphic type T into a suitable monomorphic representation, currently: __attribute__((aligned(8)) char[size_T]
    1477                 Type * polyToMonoType( Type const * declType ) {
     1509                Type * polyToMonoType( Type * declType ) {
    14781510                        Type * charType = new BasicType( Type::Qualifiers(), BasicType::Kind::Char);
    14791511                        Expression * size = new NameExpr( sizeofName( mangleType(declType) ) );
     
    15401572                /// Finds the member in the base list that matches the given declaration; returns its index, or -1 if not present
    15411573                long findMember( DeclarationWithType *memberDecl, std::list< Declaration* > &baseDecls ) {
    1542                         for ( auto pair : enumerate( baseDecls ) ) {
    1543                                 Declaration * decl = pair.val;
    1544                                 size_t i = pair.idx;
    1545                                 if ( memberDecl->get_name() != decl->get_name() )
     1574                        long i = 0;
     1575                        for(std::list< Declaration* >::const_iterator decl = baseDecls.begin(); decl != baseDecls.end(); ++decl, ++i ) {
     1576                                if ( memberDecl->get_name() != (*decl)->get_name() )
    15461577                                        continue;
    15471578
    15481579                                if ( memberDecl->get_name().empty() ) {
    15491580                                        // plan-9 field: match on unique_id
    1550                                         if ( memberDecl->get_uniqueId() == decl->get_uniqueId() )
     1581                                        if ( memberDecl->get_uniqueId() == (*decl)->get_uniqueId() )
    15511582                                                return i;
    15521583                                        else
     
    15541585                                }
    15551586
    1556                                 DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( decl );
     1587                                DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( *decl );
    15571588
    15581589                                if ( memberDecl->get_mangleName().empty() || declWithType->get_mangleName().empty() ) {
     
    15721603
    15731604                /// Returns an index expression into the offset array for a type
    1574                 Expression *makeOffsetIndex( Type const *objectType, long i ) {
     1605                Expression *makeOffsetIndex( Type *objectType, long i ) {
    15751606                        ConstantExpr *fieldIndex = new ConstantExpr( Constant::from_ulong( i ) );
    15761607                        UntypedExpr *fieldOffset = new UntypedExpr( new NameExpr( "?[?]" ) );
     
    16651696
    16661697                void PolyGenericCalculator::addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams ) {
    1667                         for ( Type * const param : otypeParams ) {
    1668                                 if ( findGeneric( param ) ) {
     1698                        for ( std::list< Type* >::const_iterator param = otypeParams.begin(); param != otypeParams.end(); ++param ) {
     1699                                if ( findGeneric( *param ) ) {
    16691700                                        // push size/align vars for a generic parameter back
    1670                                         std::string paramName = mangleType( param );
     1701                                        std::string paramName = mangleType( *param );
    16711702                                        layoutCall->get_args().push_back( new NameExpr( sizeofName( paramName ) ) );
    16721703                                        layoutCall->get_args().push_back( new NameExpr( alignofName( paramName ) ) );
    16731704                                } else {
    1674                                         layoutCall->get_args().push_back( new SizeofExpr( param->clone() ) );
    1675                                         layoutCall->get_args().push_back( new AlignofExpr( param->clone() ) );
     1705                                        layoutCall->get_args().push_back( new SizeofExpr( (*param)->clone() ) );
     1706                                        layoutCall->get_args().push_back( new AlignofExpr( (*param)->clone() ) );
    16761707                                }
    16771708                        }
     
    16791710
    16801711                /// returns true if any of the otype parameters have a dynamic layout and puts all otype parameters in the output list
    1681                 bool findGenericParams( std::list< TypeDecl* > const &baseParams, std::list< Expression* > const &typeParams, std::list< Type* > &out ) {
     1712                bool findGenericParams( std::list< TypeDecl* > &baseParams, std::list< Expression* > &typeParams, std::list< Type* > &out ) {
    16821713                        bool hasDynamicLayout = false;
    16831714
    1684                         for ( auto paramPair : group_iterate( baseParams, typeParams ) ) {
    1685                                 TypeDecl * baseParam = std::get<0>( paramPair );
    1686                                 Expression * typeParam = std::get<1>( paramPair );
     1715                        std::list< TypeDecl* >::const_iterator baseParam = baseParams.begin();
     1716                        std::list< Expression* >::const_iterator typeParam = typeParams.begin();
     1717                        for ( ; baseParam != baseParams.end() && typeParam != typeParams.end(); ++baseParam, ++typeParam ) {
    16871718                                // skip non-otype parameters
    1688                                 if ( ! baseParam->isComplete() ) continue;
    1689                                 TypeExpr *typeExpr = dynamic_cast< TypeExpr* >( typeParam );
     1719                                if ( ! (*baseParam)->isComplete() ) continue;
     1720                                TypeExpr *typeExpr = dynamic_cast< TypeExpr* >( *typeParam );
    16901721                                assert( typeExpr && "all otype parameters should be type expressions" );
    16911722
     
    16941725                                if ( isPolyType( type ) ) hasDynamicLayout = true;
    16951726                        }
     1727                        assert( baseParam == baseParams.end() && typeParam == typeParams.end() );
    16961728
    16971729                        return hasDynamicLayout;
    16981730                }
    16991731
    1700                 bool PolyGenericCalculator::findGeneric( Type const *ty ) {
     1732                bool PolyGenericCalculator::findGeneric( Type *ty ) {
    17011733                        ty = replaceTypeInst( ty, env );
    17021734
    1703                         if ( auto typeInst = dynamic_cast< TypeInstType const * >( ty ) ) {
     1735                        if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( ty ) ) {
    17041736                                if ( scopeTyVars.find( typeInst->get_name() ) != scopeTyVars.end() ) {
    17051737                                        // NOTE assumes here that getting put in the scopeTyVars included having the layout variables set
     
    17071739                                }
    17081740                                return false;
    1709                         } else if ( auto structTy = dynamic_cast< StructInstType const * >( ty ) ) {
     1741                        } else if ( StructInstType *structTy = dynamic_cast< StructInstType* >( ty ) ) {
    17101742                                // check if this type already has a layout generated for it
    17111743                                std::string typeName = mangleType( ty );
     
    17141746                                // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
    17151747                                std::list< Type* > otypeParams;
    1716                                 if ( ! findGenericParams( *structTy->get_baseParameters(), structTy->parameters, otypeParams ) ) return false;
     1748                                if ( ! findGenericParams( *structTy->get_baseParameters(), structTy->get_parameters(), otypeParams ) ) return false;
    17171749
    17181750                                // insert local variables for layout and generate call to layout function
     
    17441776
    17451777                                return true;
    1746                         } else if ( auto unionTy = dynamic_cast< UnionInstType const * >( ty ) ) {
     1778                        } else if ( UnionInstType *unionTy = dynamic_cast< UnionInstType* >( ty ) ) {
    17471779                                // check if this type already has a layout generated for it
    17481780                                std::string typeName = mangleType( ty );
     
    17511783                                // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
    17521784                                std::list< Type* > otypeParams;
    1753                                 if ( ! findGenericParams( *unionTy->get_baseParameters(), unionTy->parameters, otypeParams ) ) return false;
     1785                                if ( ! findGenericParams( *unionTy->get_baseParameters(), unionTy->get_parameters(), otypeParams ) ) return false;
    17541786
    17551787                                // insert local variables for layout and generate call to layout function
     
    18491881                                        // build initializer list for offset array
    18501882                                        std::list< Initializer* > inits;
    1851                                         for ( Declaration * const member : baseMembers ) {
    1852                                                 DeclarationWithType *memberDecl = dynamic_cast< DeclarationWithType* >( member );
    1853                                                 assertf( memberDecl, "Requesting offset of Non-DWT member: %s", toString( member ).c_str() );
    1854                                                 inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) );
     1883                                        for ( std::list< Declaration* >::const_iterator member = baseMembers.begin(); member != baseMembers.end(); ++member ) {
     1884                                                if ( DeclarationWithType *memberDecl = dynamic_cast< DeclarationWithType* >( *member ) ) {
     1885                                                        inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) );
     1886                                                } else {
     1887                                                        assertf( false, "Requesting offset of Non-DWT member: %s", toString( *member ).c_str() );
     1888                                                }
    18551889                                        }
    18561890
     
    19311965// compile-command: "make install" //
    19321966// End: //
    1933 
  • src/GenPoly/FindFunction.cc

    r63be3387 rb77f0e1  
    2929        class FindFunction : public WithGuards, public WithVisitorRef<FindFunction>, public WithShortCircuiting {
    3030          public:
    31                 FindFunction( std::list< FunctionType const* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate );
     31                FindFunction( std::list< FunctionType* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate );
    3232
    3333                void premutate( FunctionType * functionType );
     
    3737                void handleForall( const Type::ForallList &forall );
    3838
    39                 std::list< FunctionType const * > & functions;
     39                std::list< FunctionType* > &functions;
    4040                TyVarMap tyVars;
    4141                bool replaceMode;
     
    4343        };
    4444
    45         void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
     45        void findFunction( Type *type, std::list< FunctionType* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
    4646                PassVisitor<FindFunction> finder( functions, tyVars, false, predicate );
    4747                type->acceptMutator( finder );
    4848        }
    4949
    50         void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
     50        void findAndReplaceFunction( Type *&type, std::list< FunctionType* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
    5151                PassVisitor<FindFunction> finder( functions, tyVars, true, predicate );
    5252                type = type->acceptMutator( finder );
    5353        }
    5454
    55         FindFunction::FindFunction( std::list< FunctionType const * > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate )
     55        FindFunction::FindFunction( std::list< FunctionType* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate )
    5656                : functions( functions ), tyVars( tyVars ), replaceMode( replaceMode ), predicate( predicate ) {
    5757        }
  • src/GenPoly/FindFunction.h

    r63be3387 rb77f0e1  
    2727
    2828        /// recursively walk `type`, placing all functions that match `predicate` under `tyVars` into `functions`
    29         void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
     29        void findFunction( Type *type, std::list< FunctionType* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
    3030        /// like `findFunction`, but also replaces the function type with void ()(void)
    31         void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
     31        void findAndReplaceFunction( Type *&type, std::list< FunctionType* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
    3232} // namespace GenPoly
    3333
  • src/GenPoly/GenPoly.cc

    r63be3387 rb77f0e1  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Oct 24 15:19:00 2022
    13 // Update Count     : 17
     12// Last Modified On : Fri Oct  7 15:25:00 2022
     13// Update Count     : 16
    1414//
    1515
     
    118118        }
    119119
    120         const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ) {
    121                 if ( ! env ) return type;
    122                 if ( auto typeInst = dynamic_cast< const TypeInstType* >( type ) ) {
    123                         Type *newType = env->lookup( typeInst->get_name() );
    124                         if ( newType ) return newType;
    125                 }
    126                 return type;
    127         }
    128 
    129120        const ast::Type * replaceTypeInst(const ast::Type * type, const ast::TypeSubstitution * env) {
    130121                if (!env) return type;
    131                 if ( auto typeInst = dynamic_cast<const ast::TypeInstType*>(type) ) {
     122                if (auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) {
    132123                        auto newType = env->lookup(typeInst);
    133124                        if (newType) return newType;
     
    203194
    204195        if ( auto inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
    205                 if ( typeVars.find( *inst ) != typeVars.end() ) return type;
     196                if ( typeVars.find( inst->typeString() ) != typeVars.end() ) return type;
    206197        } else if ( auto array = dynamic_cast< const ast::ArrayType * >( type ) ) {
    207198                return isPolyType( array->base, subst );
     
    236227
    237228        if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
    238                 auto var = typeVars.find( *inst );
     229                auto var = typeVars.find( inst->name );
    239230                if ( var != typeVars.end() && var->second.isComplete ) {
    240                         return inst;
     231
    241232                }
    242233        } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
     
    793784
    794785void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) {
    795         typeVars.insert( *type, ast::TypeDecl::Data( type->base ) );
     786        typeVars.insert( type->typeString(), ast::TypeDecl::Data( type->base ) );
    796787}
    797788
     
    825816        }
    826817
     818void printTypeVarMap( std::ostream &os, const TypeVarMap & typeVars ) {
     819        for ( auto const & pair : typeVars ) {
     820                os << pair.first << " (" << pair.second << ") ";
     821        } // for
     822        os << std::endl;
     823}
     824
    827825} // namespace GenPoly
    828826
  • src/GenPoly/GenPoly.h

    r63be3387 rb77f0e1  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Oct 24 15:18:00 2022
    13 // Update Count     : 11
     12// Last Modified On : Fri Oct  7 15:06:00 2022
     13// Update Count     : 9
    1414//
    1515
     
    2222#include "AST/Decl.hpp"           // for TypeDecl::Data
    2323#include "AST/Fwd.hpp"            // for ApplicationExpr, BaseInstType, Func...
    24 #include "AST/Type.hpp"           // for TypeInstType::TypeEnvKey
    2524#include "SymTab/Mangler.h"       // for Mangler
    2625#include "SynTree/Declaration.h"  // for TypeDecl::Data, AggregateDecl, Type...
     
    2928namespace GenPoly {
    3029
     30        // TODO Via some tricks this works for ast::TypeDecl::Data as well.
    3131        typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
    32         using TypeVarMap = ErasableScopedMap< ast::TypeInstType::TypeEnvKey, ast::TypeDecl::Data >;
     32        using TypeVarMap = ErasableScopedMap< std::string, ast::TypeDecl::Data >;
    3333
    3434        /// Replaces a TypeInstType by its referrent in the environment, if applicable
    3535        Type* replaceTypeInst( Type* type, const TypeSubstitution* env );
    36         const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env );
    37         const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * );
    3836
    3937        /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided
     
    5553        /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters
    5654        ReferenceToType *isDynRet( FunctionType *function );
    57         const ast::BaseInstType *isDynRet( const ast::FunctionType * func );
    5855
    5956        /// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type
     
    115112        /// Prints type variable map
    116113        void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap );
     114        void printTypeVarMap( std::ostream &os, const TypeVarMap & typeVars );
    117115
    118116        /// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType().
    119         inline std::string mangleType( const Type *ty ) { return SymTab::Mangler::mangleType( ty ); }
     117        inline std::string mangleType( Type *ty ) { return SymTab::Mangler::mangleType( ty ); }
    120118
    121119        /// Gets the name of the sizeof parameter for the type, given its mangled name
     
    130128        /// Gets the name of the layout function for a given aggregate type, given its declaration
    131129        inline std::string layoutofName( AggregateDecl *decl ) { return std::string( "_layoutof_" ) + decl->get_name(); }
    132         inline std::string layoutofName( ast::AggregateDecl const * decl ) {
    133                 return std::string( "_layoutof_" ) + decl->name;
    134         }
    135130
    136131} // namespace GenPoly
  • src/GenPoly/InstantiateGenericNew.cpp

    r63be3387 rb77f0e1  
    1010// Created On       : Tue Aug 16 10:51:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Oct 31 16:48:00 2022
    13 // Update Count     : 1
     12// Last Modified On : Tue Sep 13 16:03:00 2022
     13// Update Count     : 0
    1414//
    1515
     
    378378                //   Ptr(int) p;
    379379                //   int i;
    380                 // The original expression:
    381380                //   p.x = &i;
    382                 // Becomes the expression/declaration:
    383                 //   int *& _dtype_static_member_0;
    384                 //   (_dtype_static_member_0 = (int**)&p.x,
    385                 //    _dtype_static_member_0) = &i;
    386 
    387                 // The declaration is simple:
     381                // becomes
     382                //   int *& _dtype_static_member_0 = (int **)&p.x;
     383                //   _dtype_static_member_0 = &i;
    388384                static UniqueName tmpNamer( "_dtype_static_member_" );
     385                ast::Expr * init = new ast::CastExpr( location,
     386                        new ast::AddressExpr( location, memberExpr ),
     387                        new ast::PointerType( ast::deepCopy( concType ) ),
     388                        ast::ExplicitCast
     389                );
    389390                ast::ObjectDecl * tmp = new ast::ObjectDecl( location,
    390391                        tmpNamer.newName(),
    391392                        new ast::ReferenceType( concType ),
    392                         nullptr,
     393                        new ast::SingleInit( location, init ),
    393394                        ast::Storage::Classes(),
    394395                        ast::Linkage::C
    395396                );
    396397                stmtsToAddBefore.push_back( new ast::DeclStmt( location, tmp ) );
    397 
    398                 // The expression is more complex, uses references and reference /
    399                 // pointer parity. But breaking it up risks reordering.
    400                 return new ast::CommaExpr( location,
    401                         ast::UntypedExpr::createAssign( location,
    402                                 new ast::VariableExpr( location, tmp ),
    403                                 new ast::CastExpr( location,
    404                                         new ast::AddressExpr( location, memberExpr ),
    405                                         new ast::PointerType( ast::deepCopy( concType ) ),
    406                                         ast::ExplicitCast
    407                                 )
    408                         ),
    409                         new ast::VariableExpr( location, tmp )
    410                 );
     398                return new ast::VariableExpr( location, tmp );
    411399        } else {
    412400                // Here, it can simply add a cast to actual types.
     
    488476};
    489477
     478// I think this and the UnionInstType can be made into a template function.
    490479ast::Type const * GenericInstantiator::postvisit(
    491480                ast::StructInstType const * inst ) {
  • src/GenPoly/ScrubTyVars.cc

    r63be3387 rb77f0e1  
    2020#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::const_it...
    2121#include "ScrubTyVars.h"
    22 #include "SymTab/Mangler.h"             // for mangleType
     22#include "SymTab/Mangler.h"             // for mangle, typeMode
    2323#include "SynTree/Declaration.h"        // for TypeDecl, TypeDecl::Data, Typ...
    2424#include "SynTree/Expression.h"         // for Expression (ptr only), NameExpr
     
    195195        }
    196196
    197         auto typeVar = typeVars->find( *type );
     197        auto typeVar = typeVars->find( type->name );
    198198        if ( typeVar == typeVars->end() ) {
    199199                return type;
     
    227227        if ( dynType ) {
    228228                return new ast::NameExpr( expr->location,
    229                         sizeofName( Mangle::mangleType( dynType ) ) );
     229                        sizeofName( Mangle::mangle( dynType, Mangle::typeMode() ) ) );
    230230        } else {
    231231                return expr;
     
    237237        if ( dynType ) {
    238238                return new ast::NameExpr( expr->location,
    239                         alignofName( Mangle::mangleType( dynType ) ) );
     239                        alignofName( Mangle::mangle( dynType, Mangle::typeMode() ) ) );
    240240        } else {
    241241                return expr;
  • src/Parser/DeclarationNode.cc

    r63be3387 rb77f0e1  
    2727#include "SynTree/LinkageSpec.h"   // for Spec, linkageName, Cforall
    2828#include "SynTree/Attribute.h"     // for Attribute
    29 #include "SynTree/Declaration.h"   // for TypeDecl, ObjectDecl, InlineMemberDecl, Declaration
     29#include "SynTree/Declaration.h"   // for TypeDecl, ObjectDecl, Declaration
    3030#include "SynTree/Expression.h"    // for Expression, ConstantExpr
    3131#include "SynTree/Statement.h"     // for AsmStmt
     
    11651165                SemanticError( this, "invalid function specifier for " );
    11661166        } // if
    1167         if ( enumInLine ) {
    1168                 return new InlineMemberDecl( *name, storageClasses, linkage, nullptr );
    1169         } // if
    11701167        assertf( name, "ObjectDecl must a have name\n" );
    11711168        return (new ObjectDecl( *name, storageClasses, linkage, maybeBuild< Expression >( bitfieldWidth ), nullptr, maybeBuild< Initializer >( initializer ) ))->set_asmName( asmName )->set_extension( extension );
  • src/Parser/ExpressionNode.cc

    r63be3387 rb77f0e1  
    519519                }
    520520        }
    521         return new QualifiedNameExpr( newDecl, name->name );
     521        auto ret =  new QualifiedNameExpr( newDecl, name->name );
     522        if ( auto e = dynamic_cast<EnumDecl*>(newDecl) ) {
     523                auto enumInst = new EnumInstType( Type::Qualifiers(), e );
     524                auto obj = new ObjectDecl( name->name, Type::StorageClasses(), LinkageSpec::Cforall, nullptr, enumInst, nullptr );
     525        }
     526        return ret;
    522527}
    523528
  • src/Parser/ParseNode.h

    r63be3387 rb77f0e1  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Nov  2 21:27:07 2022
    13 // Update Count     : 939
     12// Last Modified On : Tue Oct 18 16:22:15 2022
     13// Update Count     : 937
    1414//
    1515
     
    168168        Ctor, Dtor,
    169169}; // OperKinds
    170 
    171 enum class EnumHiding { Visible, Hide };
    172170
    173171struct LabelNode {
  • src/Parser/TypeData.cc

    r63be3387 rb77f0e1  
    925925        for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ), ++members ) {
    926926                if ( cur->enumInLine ) {
    927                         // Do Nothing
    928                 } else if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) {
     927                        // Tell the compiler this is a inline value placeholder
     928                        ObjectDecl * member = dynamic_cast< ObjectDecl* >(* members);
     929                        member->enumInLine = true;
     930                }
     931                if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) {
    929932                        SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." );
    930933                } else if ( cur->has_enumeratorValue() ) {
  • src/Parser/parser.yy

    r63be3387 rb77f0e1  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Nov  2 21:31:21 2022
    13 // Update Count     : 5810
     12// Last Modified On : Fri Oct 14 14:04:43 2022
     13// Update Count     : 5751
    1414//
    1515
     
    278278
    279279// Types declaration for productions
    280 
    281280%union {
    282281        Token tok;
     
    291290        CondCtl * ifctl;
    292291        ForCtrl * fctl;
    293         OperKinds compop;
     292        enum OperKinds compop;
    294293        LabelNode * label;
    295294        InitializerNode * in;
     
    297296        std::string * str;
    298297        bool flag;
    299         EnumHiding hide;
    300298        CatchStmt::Kind catch_kind;
    301299        GenericExpr * genexpr;
     
    366364%type<constant> string_literal
    367365%type<str> string_literal_list
    368 
    369 %type<hide> hide_opt                                    visible_hide_opt
    370366
    371367// expressions
     
    25572553        | ENUM attribute_list_opt identifier
    25582554                { typedefTable.makeTypedef( *$3 ); }
    2559           hide_opt '{' enumerator_list comma_opt '}'
    2560           { $$ = DeclarationNode::newEnum( $3, $7, true, false )->addQualifiers( $2 ); }
     2555          '{' enumerator_list comma_opt '}'
     2556                { $$ = DeclarationNode::newEnum( $3, $6, true, false )->addQualifiers( $2 ); }
    25612557        | ENUM attribute_list_opt typedef_name                          // unqualified type name
    2562           hide_opt '{' enumerator_list comma_opt '}'
    2563                 { $$ = DeclarationNode::newEnum( $3->name, $6, true, false )->addQualifiers( $2 ); }
     2558          '{' enumerator_list comma_opt '}'
     2559                { $$ = DeclarationNode::newEnum( $3->name, $5, true, false )->addQualifiers( $2 ); }
    25642560        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
    25652561                {
     
    25782574                        typedefTable.makeTypedef( *$6 );
    25792575                }
    2580           hide_opt '{' enumerator_list comma_opt '}'
    2581                 {
    2582                         $$ = DeclarationNode::newEnum( $6, $11, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
     2576          '{' enumerator_list comma_opt '}'
     2577                {
     2578                        $$ = DeclarationNode::newEnum( $6, $10, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
    25832579                }
    25842580        | ENUM '(' ')' attribute_list_opt identifier attribute_list_opt
    2585           hide_opt '{' enumerator_list comma_opt '}'
    2586                 {
    2587                         $$ = DeclarationNode::newEnum( $5, $9, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 );
    2588                 }
    2589         | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt
    2590           hide_opt '{' enumerator_list comma_opt '}'
    2591                 {
    2592                         $$ = DeclarationNode::newEnum( $6->name, $10, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
    2593                 }
    2594         | ENUM '(' ')' attribute_list_opt typedef_name attribute_list_opt
    2595           hide_opt '{' enumerator_list comma_opt '}'
    2596                 {
    2597                         $$ = DeclarationNode::newEnum( $5->name, $9, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 );
     2581          '{' enumerator_list comma_opt '}'
     2582                {
     2583                        $$ = DeclarationNode::newEnum( $5, $8, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 );
     2584                }
     2585        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}'
     2586                {
     2587                        $$ = DeclarationNode::newEnum( $6->name, $9, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );
     2588                }
     2589        | ENUM '(' ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}'
     2590                {
     2591                        $$ = DeclarationNode::newEnum( $5->name, $8, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 );
    25982592                }
    25992593        | enum_type_nobody
    2600         ;
    2601 
    2602 hide_opt:
    2603         // empty
    2604                 { $$ = EnumHiding::Visible; }
    2605         | '!'
    2606                 { $$ = EnumHiding::Hide; }
    26072594        ;
    26082595
     
    26152602
    26162603enumerator_list:
    2617         visible_hide_opt identifier_or_type_name enumerator_value_opt
    2618                 { $$ = DeclarationNode::newEnumValueGeneric( $2, $3 ); }
     2604        identifier_or_type_name enumerator_value_opt
     2605                { $$ = DeclarationNode::newEnumValueGeneric( $1, $2 ); }
    26192606        | INLINE type_name
    26202607                { $$ = DeclarationNode::newEnumInLine( *$2->type->symbolic.name ); }
    2621         | enumerator_list ',' visible_hide_opt identifier_or_type_name enumerator_value_opt
    2622                 { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); }
     2608        | enumerator_list ',' identifier_or_type_name enumerator_value_opt
     2609                { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( $3, $4 ) ); }
    26232610        | enumerator_list ',' INLINE type_name enumerator_value_opt
    26242611                { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); }
    2625         ;
    2626 
    2627 visible_hide_opt:
    2628         hide_opt
    2629         | '^'
    2630                 { $$ = EnumHiding::Visible; }
    26312612        ;
    26322613
  • src/ResolvExpr/CommonType.cc

    r63be3387 rb77f0e1  
    991991                                add_qualifiers( result, type2->qualifiers );
    992992                        } else {
     993                                // xxx - does unifying a ref with typed enumInst makes sense?
    993994                                if (!dynamic_cast<const ast::EnumInstType *>(type2))
    994995                                        result = commonType( type2, ref, tenv, need, have, open, widen, symtab );
     
    10091010
    10101011                void postvisit( const ast::EnumInstType * enumInst ) {
     1012                        // reuse BasicType/EnumInstType common type by swapping
     1013                        // xxx - is this already handled by unify?
    10111014                        if (!dynamic_cast<const ast::EnumInstType *>(type2))
    10121015                                result = commonType( type2, enumInst, tenv, need, have, open, widen, symtab);
  • src/ResolvExpr/ConversionCost.cc

    r63be3387 rb77f0e1  
    720720                costCalc( baseType, dst, srcIsLvalue, symtab, env );
    721721        } else {
     722                (void)enumInstType;
    722723                static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
    723724                cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
  • src/ResolvExpr/SatisfyAssertions.cpp

    r63be3387 rb77f0e1  
    268268                ast::ptr< ast::Type > resType = cand.expr->result;
    269269                cand.env.apply( resType );
    270                 return Mangle::mangleType( resType );
     270                return Mangle::mangle( resType, Mangle::typeMode() );
    271271        }
    272272
  • src/SymTab/Mangler.cc

    r63be3387 rb77f0e1  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:40:29 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Oct 21 16:18:00 2022
    13 // Update Count     : 75
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Jan 11 21:56:06 2021
     13// Update Count     : 74
    1414//
    1515#include "Mangler.h"
     
    418418                        void postvisit( const ast::QualifiedType * qualType );
    419419
    420                         /// The result is the current constructed mangled name.
    421                         std::string result() const { return mangleName; }
     420                        std::string get_mangleName() { return mangleName; }
    422421                  private:
    423422                        std::string mangleName;         ///< Mangled name being constructed
     
    445444        } // namespace
    446445
     446
    447447        std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
    448                 return ast::Pass<Mangler_new>::read( decl, mode );
     448                ast::Pass<Mangler_new> mangler( mode );
     449                maybeAccept( decl, mangler );
     450                return mangler.core.get_mangleName();
    449451        }
    450452
     
    687689                                        } // for
    688690                                        for ( auto & assert : ptype->assertions ) {
    689                                                 assertionNames.push_back( ast::Pass<Mangler_new>::read(
    690                                                         assert->var.get(),
    691                                                         mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) );
     691                                                ast::Pass<Mangler_new> sub_mangler(
     692                                                        mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
     693                                                assert->var->accept( sub_mangler );
     694                                                assertionNames.push_back( sub_mangler.core.get_mangleName() );
    692695                                                acount++;
    693696                                        } // for
  • src/SymTab/Mangler.h

    r63be3387 rb77f0e1  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:44:03 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Oct 27 11:58:00 2022
    13 // Update Count     : 16
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat Jul 22 09:45:30 2017
     13// Update Count     : 15
    1414//
    1515
     
    2222
    2323#include "AST/Bitfield.hpp"
     24#include "AST/Fwd.hpp"
    2425#include "SynTree/SynTree.h"  // for Types
    2526#include "SynTree/Visitor.h"  // for Visitor, maybeAccept
     
    3233// * Currently name compression is not implemented.
    3334
    34 namespace ast {
    35         class Node;
    36 }
    3735namespace ResolvExpr {
    3836        class TypeEnvironment;
     
    103101        using Mode = bitfield<mangle_flags>;
    104102
    105         /// Mangle declaration name.
     103        static inline Mode typeMode() { return NoOverrideable | Type; }
     104
     105        /// Mangle declaration name
    106106        std::string mangle( const ast::Node * decl, Mode mode = {} );
    107 
    108         /// Most common mangle configuration for types.
    109         static inline std::string mangleType( const ast::Node * type ) {
    110                 return mangle( type, { NoOverrideable | Type } );
    111         }
    112107
    113108        namespace Encoding {
  • src/SymTab/Validate.cc

    r63be3387 rb77f0e1  
    4747#include <utility>                     // for pair
    4848
     49#include "AST/Chain.hpp"
     50#include "AST/Decl.hpp"
     51#include "AST/Node.hpp"
     52#include "AST/Pass.hpp"
     53#include "AST/SymbolTable.hpp"
     54#include "AST/Type.hpp"
     55#include "AST/TypeSubstitution.hpp"
    4956#include "CodeGen/CodeGenerator.h"     // for genName
    5057#include "CodeGen/OperatorTable.h"     // for isCtorDtor, isCtorDtorAssign
     
    13191326        }
    13201327
     1328namespace {
     1329        /// Replaces enum types by int, and function/array types in function parameter and return
     1330        /// lists by appropriate pointers
     1331        /*
     1332        struct EnumAndPointerDecay_new {
     1333                const ast::EnumDecl * previsit( const ast::EnumDecl * enumDecl ) {
     1334                        // set the type of each member of the enumeration to be EnumConstant
     1335                        for ( unsigned i = 0; i < enumDecl->members.size(); ++i ) {
     1336                                // build new version of object with EnumConstant
     1337                                ast::ptr< ast::ObjectDecl > obj =
     1338                                        enumDecl->members[i].strict_as< ast::ObjectDecl >();
     1339                                obj.get_and_mutate()->type =
     1340                                        new ast::EnumInstType{ enumDecl->name, ast::CV::Const };
     1341
     1342                                // set into decl
     1343                                ast::EnumDecl * mut = mutate( enumDecl );
     1344                                mut->members[i] = obj.get();
     1345                                enumDecl = mut;
     1346                        }
     1347                        return enumDecl;
     1348                }
     1349
     1350                static const ast::FunctionType * fixFunctionList(
     1351                        const ast::FunctionType * func,
     1352                        std::vector< ast::ptr< ast::DeclWithType > > ast::FunctionType::* field,
     1353                        ast::ArgumentFlag isVarArgs = ast::FixedArgs
     1354                ) {
     1355                        const auto & dwts = func->* field;
     1356                        unsigned nvals = dwts.size();
     1357                        bool hasVoid = false;
     1358                        for ( unsigned i = 0; i < nvals; ++i ) {
     1359                                func = ast::mutate_field_index( func, field, i, fixFunction( dwts[i], hasVoid ) );
     1360                        }
     1361
     1362                        // the only case in which "void" is valid is where it is the only one in the list
     1363                        if ( hasVoid && ( nvals > 1 || isVarArgs ) ) {
     1364                                SemanticError(
     1365                                        dwts.front()->location, func, "invalid type void in function type" );
     1366                        }
     1367
     1368                        // one void is the only thing in the list, remove it
     1369                        if ( hasVoid ) {
     1370                                func = ast::mutate_field(
     1371                                        func, field, std::vector< ast::ptr< ast::DeclWithType > >{} );
     1372                        }
     1373
     1374                        return func;
     1375                }
     1376
     1377                const ast::FunctionType * previsit( const ast::FunctionType * func ) {
     1378                        func = fixFunctionList( func, &ast::FunctionType::params, func->isVarArgs );
     1379                        return fixFunctionList( func, &ast::FunctionType::returns );
     1380                }
     1381        };
     1382
     1383        /// expand assertions from a trait instance, performing appropriate type variable substitutions
     1384        void expandAssertions(
     1385                const ast::TraitInstType * inst, std::vector< ast::ptr< ast::DeclWithType > > & out
     1386        ) {
     1387                assertf( inst->base, "Trait instance not linked to base trait: %s", toCString( inst ) );
     1388
     1389                // build list of trait members, substituting trait decl parameters for instance parameters
     1390                ast::TypeSubstitution sub{
     1391                        inst->base->params.begin(), inst->base->params.end(), inst->params.begin() };
     1392                // deliberately take ast::ptr by-value to ensure this does not mutate inst->base
     1393                for ( ast::ptr< ast::Decl > decl : inst->base->members ) {
     1394                        auto member = decl.strict_as< ast::DeclWithType >();
     1395                        sub.apply( member );
     1396                        out.emplace_back( member );
     1397                }
     1398        }
     1399
     1400        /// Associates forward declarations of aggregates with their definitions
     1401        class LinkReferenceToTypes_new final
     1402        : public ast::WithSymbolTable, public ast::WithGuards, public
     1403          ast::WithVisitorRef<LinkReferenceToTypes_new>, public ast::WithShortCircuiting {
     1404
     1405                // these maps of uses of forward declarations of types need to have the actual type
     1406                // declaration switched in * after * they have been traversed. To enable this in the
     1407                // ast::Pass framework, any node that needs to be so mutated has mutate() called on it
     1408                // before it is placed in the map, properly updating its parents in the usual traversal,
     1409                // then can have the actual mutation applied later
     1410                using ForwardEnumsType = std::unordered_multimap< std::string, ast::EnumInstType * >;
     1411                using ForwardStructsType = std::unordered_multimap< std::string, ast::StructInstType * >;
     1412                using ForwardUnionsType = std::unordered_multimap< std::string, ast::UnionInstType * >;
     1413
     1414                const CodeLocation & location;
     1415                const ast::SymbolTable * localSymtab;
     1416
     1417                ForwardEnumsType forwardEnums;
     1418                ForwardStructsType forwardStructs;
     1419                ForwardUnionsType forwardUnions;
     1420
     1421                /// true if currently in a generic type body, so that type parameter instances can be
     1422                /// renamed appropriately
     1423                bool inGeneric = false;
     1424
     1425        public:
     1426                /// contstruct using running symbol table
     1427                LinkReferenceToTypes_new( const CodeLocation & loc )
     1428                : location( loc ), localSymtab( &symtab ) {}
     1429
     1430                /// construct using provided symbol table
     1431                LinkReferenceToTypes_new( const CodeLocation & loc, const ast::SymbolTable & syms )
     1432                : location( loc ), localSymtab( &syms ) {}
     1433
     1434                const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
     1435                        // ensure generic parameter instances are renamed like the base type
     1436                        if ( inGeneric && typeInst->base ) {
     1437                                typeInst = ast::mutate_field(
     1438                                        typeInst, &ast::TypeInstType::name, typeInst->base->name );
     1439                        }
     1440
     1441                        if (
     1442                                auto typeDecl = dynamic_cast< const ast::TypeDecl * >(
     1443                                        localSymtab->lookupType( typeInst->name ) )
     1444                        ) {
     1445                                typeInst = ast::mutate_field( typeInst, &ast::TypeInstType::kind, typeDecl->kind );
     1446                        }
     1447
     1448                        return typeInst;
     1449                }
     1450
     1451                const ast::Type * postvisit( const ast::EnumInstType * inst ) {
     1452                        const ast::EnumDecl * decl = localSymtab->lookupEnum( inst->name );
     1453                        // not a semantic error if the enum is not found, just an implicit forward declaration
     1454                        if ( decl ) {
     1455                                inst = ast::mutate_field( inst, &ast::EnumInstType::base, decl );
     1456                        }
     1457                        if ( ! decl || ! decl->body ) {
     1458                                // forward declaration
     1459                                auto mut = mutate( inst );
     1460                                forwardEnums.emplace( inst->name, mut );
     1461                                inst = mut;
     1462                        }
     1463                        return inst;
     1464                }
     1465
     1466                void checkGenericParameters( const ast::BaseInstType * inst ) {
     1467                        for ( const ast::Expr * param : inst->params ) {
     1468                                if ( ! dynamic_cast< const ast::TypeExpr * >( param ) ) {
     1469                                        SemanticError(
     1470                                                location, inst, "Expression parameters for generic types are currently "
     1471                                                "unsupported: " );
     1472                                }
     1473                        }
     1474                }
     1475
     1476                const ast::StructInstType * postvisit( const ast::StructInstType * inst ) {
     1477                        const ast::StructDecl * decl = localSymtab->lookupStruct( inst->name );
     1478                        // not a semantic error if the struct is not found, just an implicit forward declaration
     1479                        if ( decl ) {
     1480                                inst = ast::mutate_field( inst, &ast::StructInstType::base, decl );
     1481                        }
     1482                        if ( ! decl || ! decl->body ) {
     1483                                // forward declaration
     1484                                auto mut = mutate( inst );
     1485                                forwardStructs.emplace( inst->name, mut );
     1486                                inst = mut;
     1487                        }
     1488                        checkGenericParameters( inst );
     1489                        return inst;
     1490                }
     1491
     1492                const ast::UnionInstType * postvisit( const ast::UnionInstType * inst ) {
     1493                        const ast::UnionDecl * decl = localSymtab->lookupUnion( inst->name );
     1494                        // not a semantic error if the struct is not found, just an implicit forward declaration
     1495                        if ( decl ) {
     1496                                inst = ast::mutate_field( inst, &ast::UnionInstType::base, decl );
     1497                        }
     1498                        if ( ! decl || ! decl->body ) {
     1499                                // forward declaration
     1500                                auto mut = mutate( inst );
     1501                                forwardUnions.emplace( inst->name, mut );
     1502                                inst = mut;
     1503                        }
     1504                        checkGenericParameters( inst );
     1505                        return inst;
     1506                }
     1507
     1508                const ast::Type * postvisit( const ast::TraitInstType * traitInst ) {
     1509                        // handle other traits
     1510                        const ast::TraitDecl * traitDecl = localSymtab->lookupTrait( traitInst->name );
     1511                        if ( ! traitDecl )       {
     1512                                SemanticError( location, "use of undeclared trait " + traitInst->name );
     1513                        }
     1514                        if ( traitDecl->params.size() != traitInst->params.size() ) {
     1515                                SemanticError( location, traitInst, "incorrect number of trait parameters: " );
     1516                        }
     1517                        traitInst = ast::mutate_field( traitInst, &ast::TraitInstType::base, traitDecl );
     1518
     1519                        // need to carry over the "sized" status of each decl in the instance
     1520                        for ( unsigned i = 0; i < traitDecl->params.size(); ++i ) {
     1521                                auto expr = traitInst->params[i].as< ast::TypeExpr >();
     1522                                if ( ! expr ) {
     1523                                        SemanticError(
     1524                                                traitInst->params[i].get(), "Expression parameters for trait instances "
     1525                                                "are currently unsupported: " );
     1526                                }
     1527
     1528                                if ( auto inst = expr->type.as< ast::TypeInstType >() ) {
     1529                                        if ( traitDecl->params[i]->sized && ! inst->base->sized ) {
     1530                                                // traitInst = ast::mutate_field_index(
     1531                                                //      traitInst, &ast::TraitInstType::params, i,
     1532                                                //      ...
     1533                                                // );
     1534                                                ast::TraitInstType * mut = ast::mutate( traitInst );
     1535                                                ast::chain_mutate( mut->params[i] )
     1536                                                        ( &ast::TypeExpr::type )
     1537                                                                ( &ast::TypeInstType::base )->sized = true;
     1538                                                traitInst = mut;
     1539                                        }
     1540                                }
     1541                        }
     1542
     1543                        return traitInst;
     1544                }
     1545
     1546                void previsit( const ast::QualifiedType * ) { visit_children = false; }
     1547
     1548                const ast::Type * postvisit( const ast::QualifiedType * qualType ) {
     1549                        // linking only makes sense for the "oldest ancestor" of the qualified type
     1550                        return ast::mutate_field(
     1551                                qualType, &ast::QualifiedType::parent, qualType->parent->accept( * visitor ) );
     1552                }
     1553
     1554                const ast::Decl * postvisit( const ast::EnumDecl * enumDecl ) {
     1555                        // visit enum members first so that the types of self-referencing members are updated
     1556                        // properly
     1557                        if ( ! enumDecl->body ) return enumDecl;
     1558
     1559                        // update forward declarations to point here
     1560                        auto fwds = forwardEnums.equal_range( enumDecl->name );
     1561                        if ( fwds.first != fwds.second ) {
     1562                                auto inst = fwds.first;
     1563                                do {
     1564                                        // forward decl is stored * mutably * in map, can thus be updated
     1565                                        inst->second->base = enumDecl;
     1566                                } while ( ++inst != fwds.second );
     1567                                forwardEnums.erase( fwds.first, fwds.second );
     1568                        }
     1569
     1570                        // ensure that enumerator initializers are properly set
     1571                        for ( unsigned i = 0; i < enumDecl->members.size(); ++i ) {
     1572                                auto field = enumDecl->members[i].strict_as< ast::ObjectDecl >();
     1573                                if ( field->init ) {
     1574                                        // need to resolve enumerator initializers early so that other passes that
     1575                                        // determine if an expression is constexpr have appropriate information
     1576                                        auto init = field->init.strict_as< ast::SingleInit >();
     1577
     1578                                        enumDecl = ast::mutate_field_index(
     1579                                                enumDecl, &ast::EnumDecl::members, i,
     1580                                                ast::mutate_field( field, &ast::ObjectDecl::init,
     1581                                                        ast::mutate_field( init, &ast::SingleInit::value,
     1582                                                                ResolvExpr::findSingleExpression(
     1583                                                                        init->value, new ast::BasicType{ ast::BasicType::SignedInt },
     1584                                                                        symtab ) ) ) );
     1585                                }
     1586                        }
     1587
     1588                        return enumDecl;
     1589                }
     1590
     1591                /// rename generic type parameters uniquely so that they do not conflict with user defined
     1592                /// function forall parameters, e.g. the T in Box and the T in f, below
     1593                ///   forall(otype T)
     1594                ///   struct Box {
     1595                ///     T x;
     1596                ///   };
     1597                ///   forall(otype T)
     1598                ///   void f(Box(T) b) {
     1599                ///     ...
     1600                ///   }
     1601                template< typename AggrDecl >
     1602                const AggrDecl * renameGenericParams( const AggrDecl * aggr ) {
     1603                        GuardValue( inGeneric );
     1604                        inGeneric = ! aggr->params.empty();
     1605
     1606                        for ( unsigned i = 0; i < aggr->params.size(); ++i ) {
     1607                                const ast::TypeDecl * td = aggr->params[i];
     1608
     1609                                aggr = ast::mutate_field_index(
     1610                                        aggr, &AggrDecl::params, i,
     1611                                        ast::mutate_field( td, &ast::TypeDecl::name, "__" + td->name + "_generic_" ) );
     1612                        }
     1613                        return aggr;
     1614                }
     1615
     1616                const ast::StructDecl * previsit( const ast::StructDecl * structDecl ) {
     1617                        return renameGenericParams( structDecl );
     1618                }
     1619
     1620                void postvisit( const ast::StructDecl * structDecl ) {
     1621                        // visit struct members first so that the types of self-referencing members are
     1622                        // updated properly
     1623                        if ( ! structDecl->body ) return;
     1624
     1625                        // update forward declarations to point here
     1626                        auto fwds = forwardStructs.equal_range( structDecl->name );
     1627                        if ( fwds.first != fwds.second ) {
     1628                                auto inst = fwds.first;
     1629                                do {
     1630                                        // forward decl is stored * mutably * in map, can thus be updated
     1631                                        inst->second->base = structDecl;
     1632                                } while ( ++inst != fwds.second );
     1633                                forwardStructs.erase( fwds.first, fwds.second );
     1634                        }
     1635                }
     1636
     1637                const ast::UnionDecl * previsit( const ast::UnionDecl * unionDecl ) {
     1638                        return renameGenericParams( unionDecl );
     1639                }
     1640
     1641                void postvisit( const ast::UnionDecl * unionDecl ) {
     1642                        // visit union members first so that the types of self-referencing members are updated
     1643                        // properly
     1644                        if ( ! unionDecl->body ) return;
     1645
     1646                        // update forward declarations to point here
     1647                        auto fwds = forwardUnions.equal_range( unionDecl->name );
     1648                        if ( fwds.first != fwds.second ) {
     1649                                auto inst = fwds.first;
     1650                                do {
     1651                                        // forward decl is stored * mutably * in map, can thus be updated
     1652                                        inst->second->base = unionDecl;
     1653                                } while ( ++inst != fwds.second );
     1654                                forwardUnions.erase( fwds.first, fwds.second );
     1655                        }
     1656                }
     1657
     1658                const ast::Decl * postvisit( const ast::TraitDecl * traitDecl ) {
     1659                        // set the "sized" status for the special "sized" trait
     1660                        if ( traitDecl->name == "sized" ) {
     1661                                assertf( traitDecl->params.size() == 1, "Built-in trait 'sized' has incorrect "
     1662                                        "number of parameters: %zd", traitDecl->params.size() );
     1663
     1664                                traitDecl = ast::mutate_field_index(
     1665                                        traitDecl, &ast::TraitDecl::params, 0,
     1666                                        ast::mutate_field(
     1667                                                traitDecl->params.front().get(), &ast::TypeDecl::sized, true ) );
     1668                        }
     1669
     1670                        // move assertions from type parameters into the body of the trait
     1671                        std::vector< ast::ptr< ast::DeclWithType > > added;
     1672                        for ( const ast::TypeDecl * td : traitDecl->params ) {
     1673                                for ( const ast::DeclWithType * assn : td->assertions ) {
     1674                                        auto inst = dynamic_cast< const ast::TraitInstType * >( assn->get_type() );
     1675                                        if ( inst ) {
     1676                                                expandAssertions( inst, added );
     1677                                        } else {
     1678                                                added.emplace_back( assn );
     1679                                        }
     1680                                }
     1681                        }
     1682                        if ( ! added.empty() ) {
     1683                                auto mut = mutate( traitDecl );
     1684                                for ( const ast::DeclWithType * decl : added ) {
     1685                                        mut->members.emplace_back( decl );
     1686                                }
     1687                                traitDecl = mut;
     1688                        }
     1689
     1690                        return traitDecl;
     1691                }
     1692        };
     1693
     1694        /// Replaces array and function types in forall lists by appropriate pointer type and assigns
     1695        /// each object and function declaration a unique ID
     1696        class ForallPointerDecay_new {
     1697                const CodeLocation & location;
     1698        public:
     1699                ForallPointerDecay_new( const CodeLocation & loc ) : location( loc ) {}
     1700
     1701                const ast::ObjectDecl * previsit( const ast::ObjectDecl * obj ) {
     1702                        // ensure that operator names only apply to functions or function pointers
     1703                        if (
     1704                                CodeGen::isOperator( obj->name )
     1705                                && ! dynamic_cast< const ast::FunctionType * >( obj->type->stripDeclarator() )
     1706                        ) {
     1707                                SemanticError( obj->location, toCString( "operator ", obj->name.c_str(), " is not "
     1708                                        "a function or function pointer." )  );
     1709                        }
     1710
     1711                        // ensure object has unique ID
     1712                        if ( obj->uniqueId ) return obj;
     1713                        auto mut = mutate( obj );
     1714                        mut->fixUniqueId();
     1715                        return mut;
     1716                }
     1717
     1718                const ast::FunctionDecl * previsit( const ast::FunctionDecl * func ) {
     1719                        // ensure function has unique ID
     1720                        if ( func->uniqueId ) return func;
     1721                        auto mut = mutate( func );
     1722                        mut->fixUniqueId();
     1723                        return mut;
     1724                }
     1725
     1726                /// Fix up assertions -- flattens assertion lists, removing all trait instances
     1727                template< typename node_t, typename parent_t >
     1728                static const node_t * forallFixer(
     1729                        const CodeLocation & loc, const node_t * node,
     1730                        ast::FunctionType::ForallList parent_t::* forallField
     1731                ) {
     1732                        for ( unsigned i = 0; i < (node->* forallField).size(); ++i ) {
     1733                                const ast::TypeDecl * type = (node->* forallField)[i];
     1734                                if ( type->assertions.empty() ) continue;
     1735
     1736                                std::vector< ast::ptr< ast::DeclWithType > > asserts;
     1737                                asserts.reserve( type->assertions.size() );
     1738
     1739                                // expand trait instances into their members
     1740                                for ( const ast::DeclWithType * assn : type->assertions ) {
     1741                                        auto traitInst =
     1742                                                dynamic_cast< const ast::TraitInstType * >( assn->get_type() );
     1743                                        if ( traitInst ) {
     1744                                                // expand trait instance to all its members
     1745                                                expandAssertions( traitInst, asserts );
     1746                                        } else {
     1747                                                // pass other assertions through
     1748                                                asserts.emplace_back( assn );
     1749                                        }
     1750                                }
     1751
     1752                                // apply FixFunction to every assertion to check for invalid void type
     1753                                for ( ast::ptr< ast::DeclWithType > & assn : asserts ) {
     1754                                        bool isVoid = false;
     1755                                        assn = fixFunction( assn, isVoid );
     1756                                        if ( isVoid ) {
     1757                                                SemanticError( loc, node, "invalid type void in assertion of function " );
     1758                                        }
     1759                                }
     1760
     1761                                // place mutated assertion list in node
     1762                                auto mut = mutate( type );
     1763                                mut->assertions = move( asserts );
     1764                                node = ast::mutate_field_index( node, forallField, i, mut );
     1765                        }
     1766                        return node;
     1767                }
     1768
     1769                const ast::FunctionType * previsit( const ast::FunctionType * ftype ) {
     1770                        return forallFixer( location, ftype, &ast::FunctionType::forall );
     1771                }
     1772
     1773                const ast::StructDecl * previsit( const ast::StructDecl * aggrDecl ) {
     1774                        return forallFixer( aggrDecl->location, aggrDecl, &ast::StructDecl::params );
     1775                }
     1776
     1777                const ast::UnionDecl * previsit( const ast::UnionDecl * aggrDecl ) {
     1778                        return forallFixer( aggrDecl->location, aggrDecl, &ast::UnionDecl::params );
     1779                }
     1780        };
     1781        */
     1782} // anonymous namespace
     1783
     1784/*
     1785const ast::Type * validateType(
     1786                const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab ) {
     1787        // ast::Pass< EnumAndPointerDecay_new > epc;
     1788        ast::Pass< LinkReferenceToTypes_new > lrt{ loc, symtab };
     1789        ast::Pass< ForallPointerDecay_new > fpd{ loc };
     1790
     1791        return type->accept( lrt )->accept( fpd );
     1792}
     1793*/
     1794
    13211795} // namespace SymTab
    13221796
  • src/SynTree/Declaration.h

    r63be3387 rb77f0e1  
    449449};
    450450
    451 
    452 class InlineMemberDecl : public DeclarationWithType {
    453         typedef DeclarationWithType Parent;
    454   public:
    455         Type * type;
    456 
    457         InlineMemberDecl( const std::string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage, Type * type,
    458                                 const std::list< Attribute * > attributes = std::list< Attribute * >(), Type::FuncSpecifiers fs = Type::FuncSpecifiers() );
    459         InlineMemberDecl( const InlineMemberDecl & other );
    460         virtual ~InlineMemberDecl();
    461 
    462         virtual Type * get_type() const override { return type; }
    463         virtual void set_type(Type * newType) override { type = newType; }
    464 
    465         static InlineMemberDecl * newInlineMemberDecl( const std::string & name, Type * type );
    466 
    467         virtual InlineMemberDecl * clone() const override { return new InlineMemberDecl( *this ); }
    468         virtual void accept( Visitor & v ) override { v.visit( this ); }
    469         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    470         virtual DeclarationWithType * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    471         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    472         virtual void printShort( std::ostream & os, Indenter indent = {} ) const override;
    473 
    474 };
    475 
    476451std::ostream & operator<<( std::ostream & os, const TypeDecl::Data & data );
    477452
  • src/SynTree/Mutator.h

    r63be3387 rb77f0e1  
    3636        virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) = 0;
    3737        virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) = 0;
    38         virtual DeclarationWithType * mutate( InlineMemberDecl * InlineMemberDecl ) = 0;
    3938
    4039        virtual CompoundStmt * mutate( CompoundStmt * compoundStmt ) = 0;
  • src/SynTree/SynTree.h

    r63be3387 rb77f0e1  
    3838class DirectiveDecl;
    3939class StaticAssertDecl;
    40 class InlineMemberDecl;
    4140
    4241class Statement;
  • src/SynTree/Visitor.h

    r63be3387 rb77f0e1  
    4949        virtual void visit( StaticAssertDecl * node ) { visit( const_cast<const StaticAssertDecl *>(node) ); }
    5050        virtual void visit( const StaticAssertDecl * assertDecl ) = 0;
    51         virtual void visit( InlineMemberDecl * node ) { visit( const_cast<const InlineMemberDecl *>(node) ); }
    52         virtual void visit( const InlineMemberDecl * valueDecl ) = 0;
    5351
    5452        virtual void visit( CompoundStmt * node ) { visit( const_cast<const CompoundStmt *>(node) ); }
  • src/SynTree/module.mk

    r63be3387 rb77f0e1  
    4242      SynTree/Initializer.cc \
    4343      SynTree/Initializer.h \
    44       SynTree/InlineMemberDecl.cc \
    4544      SynTree/Label.h \
    4645      SynTree/LinkageSpec.cc \
  • src/Validate/EnumAndPointerDecay.cpp

    r63be3387 rb77f0e1  
    2121#include "AST/Type.hpp"
    2222#include "SymTab/FixFunction.h"
    23 #include "Validate/NoIdSymbolTable.hpp"
    2423
    2524namespace Validate {
     
    2726namespace {
    2827
    29 struct EnumAndPointerDecayCore final : public WithNoIdSymbolTable, public ast::WithCodeLocation {
     28struct EnumAndPointerDecayCore final : public ast::WithCodeLocation {
    3029        ast::EnumDecl const * previsit( ast::EnumDecl const * decl );
    3130        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
     
    4039        // Set the type of each member of the enumeration to be EnumContant.
    4140        auto mut = ast::mutate( decl );
    42         std::vector<ast::ptr<ast::Decl>> buffer;
    43         for ( auto member : decl->members ) {
    44                 if ( ast::ObjectDecl const * object = member.as<ast::ObjectDecl>() ) {
    45                         buffer.push_back( ast::mutate_field( object,
    46                                 &ast::ObjectDecl::type,
    47                                 new ast::EnumInstType( decl, ast::CV::Const ) ) );
    48                 } else if ( auto value = member.as<ast::InlineMemberDecl>() ) {
    49                         if ( auto targetEnum = symtab.lookupEnum( value->name ) ) {
    50                                 for ( auto enumMember : targetEnum->members ) {
    51                                         auto enumObject = enumMember.strict_as<ast::ObjectDecl>();
    52                                         buffer.push_back( new ast::ObjectDecl(
    53                                                 // Get the location from the "inline" declaration.
    54                                                 value->location,
    55                                                 enumObject->name,
    56                                                 // Construct a new EnumInstType as the type.
    57                                                 new ast::EnumInstType( decl, ast::CV::Const ),
    58                                                 enumObject->init,
    59                                                 enumObject->storage,
    60                                                 enumObject->linkage,
    61                                                 enumObject->bitfieldWidth,
    62                                                 {},
    63                                                 enumObject->funcSpec
    64                                         ) );
    65                                 }
    66                         }
    67                 }
     41        for ( ast::ptr<ast::Decl> & member : mut->members ) {
     42                ast::ObjectDecl const * object = member.strict_as<ast::ObjectDecl>();
     43                member = ast::mutate_field( object, &ast::ObjectDecl::type,
     44                        new ast::EnumInstType( decl, ast::CV::Const ) );
    6845        }
    69         mut->members = buffer;
    7046        return mut;
    7147}
  • src/Validate/LinkReferenceToTypes.cpp

    r63be3387 rb77f0e1  
    185185                                decl = mut;
    186186                        }
    187                         // visit the base
    188187                } else if ( auto ptr = decl->base.as<ast::PointerType>() ) {
    189188                        if ( auto base = ptr->base.as<ast::TypeInstType>() ) {
     
    204203
    205204        // The following section
     205        auto mut = ast::mutate( decl );
     206        std::vector<ast::ptr<ast::Decl>> buffer;
     207        for ( auto it = decl->members.begin(); it != decl->members.end(); ++it) {
     208                auto member = (*it).as<ast::ObjectDecl>();
     209                if ( member->enumInLine ) {
     210                        auto targetEnum = symtab.lookupEnum( member->name );
     211                        if ( targetEnum ) {                     
     212                                for ( auto singleMamber : targetEnum->members ) {
     213                                        auto tm = singleMamber.as<ast::ObjectDecl>();
     214                                        auto t = new ast::ObjectDecl(
     215                                                member->location, // use the "inline" location
     216                                                tm->name,
     217                                                new ast::EnumInstType( decl, ast::CV::Const ),
     218                                                // Construct a new EnumInstType as the type
     219                                                tm->init,
     220                                                tm->storage,
     221                                                tm->linkage,
     222                                                tm->bitfieldWidth,
     223                                                {}, // enum member doesn't have attribute
     224                                                tm->funcSpec
     225                                        );
     226                                        t->importValue = true;
     227                                        buffer.push_back(t);
     228                                }
     229                        }
     230                } else {
     231                        auto search_it = std::find_if( buffer.begin(), buffer.end(), [member](ast::ptr<ast::Decl> cur) {
     232                                auto curAsObjDecl = cur.as<ast::ObjectDecl>();
     233                                return (curAsObjDecl->importValue) && (curAsObjDecl->name == member->name);
     234                        });
     235                        if ( search_it != buffer.end() ) {
     236                                buffer.erase( search_it ); // Found an import enum value that has the same name
     237                                // override the imported value
     238                        }
     239                        buffer.push_back( *it );
     240                }
     241        }
     242        mut->members = buffer;
     243        decl = mut;
    206244
    207245        ForwardEnumsType::iterator fwds = forwardEnums.find( decl->name );
  • src/Virtual/ExpandCasts.cc

    r63be3387 rb77f0e1  
    295295        // returns the previous declaration for error messages.
    296296        ast::ObjectDecl const * insert( ast::ObjectDecl const * typeIdDecl ) {
    297                 std::string mangledName = Mangle::mangleType( typeIdDecl->type );
     297                std::string const & mangledName =
     298                                Mangle::mangle( typeIdDecl->type, Mangle::typeMode() );
    298299                ast::ObjectDecl const *& value = instances[ mangledName ];
    299300                if ( value ) {
     
    309310
    310311        ast::ObjectDecl const * lookup( ast::Type const * typeIdType ) {
    311                 std::string mangledName = Mangle::mangleType( typeIdType );
     312                std::string const & mangledName =
     313                                Mangle::mangle( typeIdType, Mangle::typeMode() );
    312314                auto const it = instances.find( mangledName );
    313315                return ( instances.end() == it ) ? nullptr : it->second;
  • tests/array-container/array-basic.cfa

    r63be3387 rb77f0e1  
    7878}
    7979
    80 forall( [N], A & | ar(A, float, N) )
     80forall( A & | ar(A, float) )
    8181float total1d_hi( A & a ) {
    8282    float total = 0.0f;
    83     for (i; N)
     83    for (i; a`len)
    8484        total += a[i];
    8585    return total;
  • tests/collections/atomic_mpsc.cfa

    r63be3387 rb77f0e1  
    11#include <fstream.hfa>
    2 #include <containers/lockfree.hfa>
     2#include <queueLockFree.hfa>
    33#include <thread.hfa>
    44
  • tests/configs/parsebools.cfa

    r63be3387 rb77f0e1  
    1616
    1717#include <fstream.hfa>
     18#include <parseargs.hfa>
    1819
    1920#include "../meta/fork+exec.hfa"
    20 
    21 // last as a work around to a parse bug
    22 #include <parseargs.hfa>
    2321
    2422int main(int argc, char * argv[]) {
  • tests/configs/parsenums.cfa

    r63be3387 rb77f0e1  
    1616
    1717#include <fstream.hfa>
     18#include <parseargs.hfa>
    1819
    1920#include "../meta/fork+exec.hfa"
    20 
    21 // last as workaround to parser bug
    22 #include <parseargs.hfa>
    2321
    2422#if __SIZEOF_LONG__ == 4
  • tests/configs/usage.cfa

    r63be3387 rb77f0e1  
    1616
    1717#include <fstream.hfa>
    18 #include "../meta/fork+exec.hfa"
    1918#include <parseargs.hfa>
    2019
     20#include "../meta/fork+exec.hfa"
    2121
    2222int main() {
  • tests/enum_tests/.expect/enumInlineValue.txt

    r63be3387 rb77f0e1  
    11enumB.A is 5
    2 enumB.B is 6
     2enumB.B is 10
    33enumB.D is 11
    44enumB.E is 12
  • tests/enum_tests/.expect/qualifiedEnum.cfa

    r63be3387 rb77f0e1  
    1 l :1
     1l :0
  • tests/enum_tests/enumInlineValue.cfa

    r63be3387 rb77f0e1  
    66enum enumB {
    77    inline enumA,
    8     E
     8    E, B=10
    99};
    1010
  • tests/enum_tests/qualifiedEnum.cfa

    r63be3387 rb77f0e1  
    88
    99int main() {
    10     enum Level l = Level.MEDIUM;
     10    enum Level l = Level.LOW;
    1111    sout | "l :" | l;
    1212    return 0;
Note: See TracChangeset for help on using the changeset viewer.