Changeset d95969a


Ignore:
Timestamp:
Jan 25, 2021, 3:45:42 PM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
c292244
Parents:
b6a8b31 (diff), 7158202 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
14 added
173 edited
1 moved

Legend:

Unmodified
Added
Removed
  • .gitignore

    rb6a8b31 rd95969a  
    7979# generated by npm
    8080package-lock.json
     81
     82# generated by benchmark
     83benchmark/Cargo.toml
  • benchmark/io/http/filecache.cfa

    rb6a8b31 rd95969a  
    44#include <string.h>
    55
     6#include <fstream.hfa>
    67#include <stdlib.hfa>
    78
     
    182183                conflicts += put_file( raw[i], fd );
    183184        }
    184         printf("Filled cache from path \"%s\" with %zu files\n", path, fcount);
     185        sout | "Filled cache from path \"" | path | "\" with" | fcount | "files";
    185186        if( conflicts > 0 ) {
    186                 printf("Found %d conflicts (seed: %u)\n", conflicts, options.file_cache.hash_seed);
     187                sout | "Found" | conflicts | "conflicts (seed: " | options.file_cache.hash_seed | ")";
    187188                #if defined(REJECT_CONFLICTS)
    188189                        abort("Conflicts found in the cache");
     
    191192
    192193        if(options.file_cache.list) {
    193                 printf("Listing files and exiting\n");
     194                sout | "Listing files and exiting";
    194195                for(i; fcount) {
    195196                        int s; char u;
    196197                        [s, u] = human_size(raw[i].size);
    197                         printf("%4d%c - %s\n", s, u, raw[i].file);
     198                        sout | s | u | "-" | raw[i].file;
    198199                        free(raw[i].file);
    199200                }
     
    208209
    209210[int *, int] filefds(int extra) {
     211        if(!options.file_cache.path) {
     212                int * data = alloc(extra);
     213                return [data, 0];
     214        }
     215
    210216        if(!file_cache.entries) {
    211217                abort("File cache not filled!\n");
  • benchmark/io/http/main.cfa

    rb6a8b31 rd95969a  
    66#include <unistd.h>
    77extern "C" {
     8        #include <signal.h>
    89        #include <sys/socket.h>
    910        #include <netinet/in.h>
    1011}
    1112
     13#include <fstream.hfa>
    1214#include <kernel.hfa>
     15#include <iofwd.hfa>
    1316#include <stats.hfa>
    1417#include <time.hfa>
     
    5053
    5154//=============================================================================================
     55// Stats Printer
     56//============================================================================================='
     57
     58thread StatsPrinter {};
     59
     60void ?{}( StatsPrinter & this ) {
     61        ((thread&)this){ "Stats Printer Thread" };
     62}
     63
     64void main(StatsPrinter & this) {
     65        LOOP: for() {
     66                waitfor( ^?{} : this) {
     67                        break LOOP;
     68                }
     69                or else {}
     70
     71                sleep(10`s);
     72
     73                print_stats_now( *options.clopts.instance, CFA_STATS_READY_Q | CFA_STATS_IO );
     74        }
     75}
     76
     77//=============================================================================================
    5278// Main
    5379//============================================================================================='
    5480int main( int argc, char * argv[] ) {
     81        __sighandler_t s = 1p;
     82        signal(SIGPIPE, s);
     83
    5584        //===================
    5685        // Parse args
    57         const char * path = parse_options(argc, argv);
     86        parse_options(argc, argv);
    5887
    5988        //===================
    6089        // Open Files
    61         printf("Filling cache from %s\n", path);
    62         fill_cache( path );
     90        if( options.file_cache.path ) {
     91                sout | "Filling cache from" | options.file_cache.path;
     92                fill_cache( options.file_cache.path );
     93        }
    6394
    6495        //===================
    6596        // Open Socket
    66         printf("%ld : Listening on port %d\n", getpid(), options.socket.port);
     97        sout | getpid() | ": Listening on port" | options.socket.port;
    6798        int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    6899        if(server_fd < 0) {
     
    84115                        if(errno == EADDRINUSE) {
    85116                                if(waited == 0) {
    86                                         printf("Waiting for port\n");
     117                                        sout | "Waiting for port";
    87118                                } else {
    88                                         printf("\r%d", waited);
    89                                         fflush(stdout);
     119                                        sout | "\r" | waited | nonl;
     120                                        flush( sout );
    90121                                }
    91122                                waited ++;
     
    122153                }
    123154
    124                 if(options.file_cache.fixed_fds) {
     155                if(options.file_cache.path && options.file_cache.fixed_fds) {
    125156                        register_fixed_files(cl, fds, pipe_off);
    126157                }
     
    128159                {
    129160                        ServerProc procs[options.clopts.nprocs];
     161                        StatsPrinter printer;
    130162
    131163                        init_protocol();
     
    148180                                        unpark( workers[i] );
    149181                                }
    150                                 printf("%d workers started on %d processors\n", options.clopts.nworkers, options.clopts.nprocs);
     182                                sout | options.clopts.nworkers | "workers started on" | options.clopts.nprocs | "processors";
    151183                                {
    152184                                        char buffer[128];
    153                                         while(!feof(stdin)) {
    154                                                 fgets(buffer, 128, stdin);
     185                                        while(int ret = cfa_read(0, buffer, 128, 0, -1`s, 0p, 0p); ret != 0) {
     186                                                if(ret < 0) abort( "main read error: (%d) %s\n", (int)errno, strerror(errno) );
    155187                                        }
    156188
    157                                         printf("Shutting Down\n");
    158                                 }
    159 
     189                                        sout | "Shutdown received";
     190                                }
     191
     192                                sout | "Notifying connections..." | nonl; flush( sout );
    160193                                for(i; options.clopts.nworkers) {
    161                                         printf("Cancelling %p\n", (void*)workers[i].cancel.target);
    162194                                        workers[i].done = true;
    163195                                        cancel(workers[i].cancel);
    164196                                }
    165 
    166                                 printf("Shutting down socket\n");
     197                                sout | "done";
     198
     199                                sout | "Shutting down socket..." | nonl; flush( sout );
    167200                                int ret = shutdown( server_fd, SHUT_RD );
    168                                 if( ret < 0 ) { abort( "shutdown error: (%d) %s\n", (int)errno, strerror(errno) ); }
     201                                if( ret < 0 ) {
     202                                        abort( "shutdown error: (%d) %s\n", (int)errno, strerror(errno) );
     203                                }
     204                                sout | "done";
    169205
    170206                                //===================
    171207                                // Close Socket
    172                                 printf("Closing Socket\n");
     208                                sout | "Closing Socket..." | nonl; flush( sout );
    173209                                ret = close( server_fd );
    174210                                if(ret < 0) {
    175211                                        abort( "close socket error: (%d) %s\n", (int)errno, strerror(errno) );
    176212                                }
     213                                sout | "done";
     214
     215                                sout | "Stopping connection threads..." | nonl; flush( sout );
    177216                        }
    178                         printf("Workers Closed\n");
    179 
     217                        sout | "done";
     218
     219                        sout | "Stopping protocol threads..." | nonl; flush( sout );
    180220                        deinit_protocol();
    181                 }
    182 
     221                        sout | "done";
     222
     223                        sout | "Stopping processors..." | nonl; flush( sout );
     224                }
     225                sout | "done";
     226
     227                sout | "Closing splice fds..." | nonl; flush( sout );
    183228                for(i; pipe_cnt) {
    184229                        ret = close( fds[pipe_off + i] );
     
    188233                }
    189234                free(fds);
    190 
    191         }
     235                sout | "done";
     236
     237                sout | "Stopping processors..." | nonl; flush( sout );
     238        }
     239        sout | "done";
    192240
    193241        //===================
    194242        // Close Files
    195         printf("Closing Files\n");
    196         close_cache();
    197 }
     243        if( options.file_cache.path ) {
     244                sout | "Closing open files..." | nonl; flush( sout );
     245                close_cache();
     246                sout | "done";
     247        }
     248}
  • benchmark/io/http/options.cfa

    rb6a8b31 rd95969a  
    99}
    1010
     11#include <bitmanip.hfa>
     12#include <fstream.hfa>
    1113#include <kernel.hfa>
    1214#include <parseargs.hfa>
    1315
     16#include <stdlib.h>
    1417#include <string.h>
    1518
     
    1821
    1922        { // file_cache
     23                0,     // path
    2024                0,     // open_flags;
    2125                42u,   // hash_seed;
     
    3438                1,     // nprocs;
    3539                1,     // nworkers;
    36                 0,     // flags;
     40                {},     // params;
    3741                false, // procstats
    3842                false, // viewhalts
     
    4145};
    4246
    43 const char * parse_options( int argc, char * argv[] ) {
     47void parse_options( int argc, char * argv[] ) {
    4448        bool subthrd = false;
    4549        bool eagrsub = false;
     
    4852        bool iokpoll = false;
    4953        unsigned sublen = 16;
     54        unsigned nentries = 16;
     55
    5056
    5157        static cfa_option opt[] = {
    52                 {'p', "port",           "Port the server will listen on", options.socket.port},
    53                 {'c', "cpus",           "Number of processors to use", options.clopts.nprocs},
    54                 {'L', "log",            "Enable logs", options.log, parse_settrue},
    55                 {'t', "threads",        "Number of worker threads to use", options.clopts.nworkers},
    56                 {'b', "accept-backlog", "Maximum number of pending accepts", options.socket.backlog},
    57                 {'r', "request_len",    "Maximum number of bytes in the http request, requests with more data will be answered with Http Code 414", options.socket.buflen},
    58                 {'S', "seed",           "seed to use for hashing", options.file_cache.hash_seed },
    59                 {'C', "cache-size",     "Size of the cache to use, if set to small, will uses closes power of 2", options.file_cache.size },
    60                 {'l', "list-files",     "List the files in the specified path and exit", options.file_cache.list, parse_settrue },
    61                 {'s', "submitthread",   "If set, cluster uses polling thread to submit I/O", subthrd, parse_settrue },
    62                 {'e', "eagersubmit",    "If set, cluster submits I/O eagerly but still aggregates submits", eagrsub, parse_settrue},
    63                 {'f', "fixed-fds",      "If set, files are open eagerly and pre-registered with the cluster", fixedfd, parse_settrue},
    64                 {'k', "kpollsubmit",    "If set, cluster uses IORING_SETUP_SQPOLL, implies -f", sqkpoll, parse_settrue },
    65                 {'i', "kpollcomplete",  "If set, cluster uses IORING_SETUP_IOPOLL", iokpoll, parse_settrue },
    66                 {'L', "submitlength",   "Max number of submitions that can be submitted together", sublen },
     58                { 'p', "port",           "Port the server will listen on", options.socket.port},
     59                { 'c', "cpus",           "Number of processors to use", options.clopts.nprocs},
     60                { 't', "threads",        "Number of worker threads to use", options.clopts.nworkers},
     61                {'\0', "log",            "Enable logs", options.log, parse_settrue},
     62                {'\0', "accept-backlog", "Maximum number of pending accepts", options.socket.backlog},
     63                {'\0', "request_len",    "Maximum number of bytes in the http request, requests with more data will be answered with Http Code 414", options.socket.buflen},
     64                {'\0', "seed",           "seed to use for hashing", options.file_cache.hash_seed },
     65                {'\0', "cache-size",     "Size of the cache to use, if set to small, will uses closes power of 2", options.file_cache.size },
     66                {'\0', "list-files",     "List the files in the specified path and exit", options.file_cache.list, parse_settrue },
     67                { 's', "submitthread",   "If set, cluster uses polling thread to submit I/O", subthrd, parse_settrue },
     68                { 'e', "eagersubmit",    "If set, cluster submits I/O eagerly but still aggregates submits", eagrsub, parse_settrue},
     69                { 'f', "fixed-fds",      "If set, files are open eagerly and pre-registered with the cluster", fixedfd, parse_settrue},
     70                { 'k', "kpollsubmit",    "If set, cluster uses IORING_SETUP_SQPOLL, implies -f", sqkpoll, parse_settrue },
     71                { 'i', "kpollcomplete",  "If set, cluster uses IORING_SETUP_IOPOLL", iokpoll, parse_settrue },
     72                {'\0', "submitlength",   "Max number of submitions that can be submitted together", sublen },
     73                {'\0', "numentries",     "Number of I/O entries", nentries },
    6774
    6875        };
     
    7178        char **left;
    7279        parse_args( argc, argv, opt, opt_cnt, "[OPTIONS]... [PATH]\ncforall http server", left );
     80
     81        if( !is_pow2(nentries) ) {
     82                unsigned v = nentries;
     83                v--;
     84                v |= v >> 1;
     85                v |= v >> 2;
     86                v |= v >> 4;
     87                v |= v >> 8;
     88                v |= v >> 16;
     89                v++;
     90                serr | "Warning: num_entries not a power of 2" | '(' | nentries | ')' | "raising to " | v;
     91                nentries = v;
     92        }
     93        options.clopts.params.num_entries = nentries;
    7394
    7495        options.clopts.params.poller_submits = subthrd;
     
    91112        options.clopts.params.num_ready = sublen;
    92113
    93         if( left[0] == 0p ) { return "."; }
     114        if( left[0] == 0p ) { return; }
    94115
    95116        const char * path = left[0];
     
    97118
    98119        if( left[0] != 0p ) {
    99                 abort("Too many trailing arguments!\n");
     120                serr | "Too many trailing arguments!" | '\'' | path | '\'';
     121                while(left[0] != 0p) {
     122                        serr | " - " | left[0];
     123                        left++;
     124                }
     125                exit(EXIT_FAILURE);
    100126        }
    101127
    102         return path;
     128        options.file_cache.path = path;
    103129}
  • benchmark/io/http/options.hfa

    rb6a8b31 rd95969a  
    1111
    1212        struct {
     13                const char * path;
    1314                int open_flags;
    1415                uint32_t hash_seed;
     
    3637extern Options options;
    3738
    38 const char * parse_options( int argc, char * argv[] );
     39void parse_options( int argc, char * argv[] );
  • benchmark/io/http/protocol.cfa

    rb6a8b31 rd95969a  
    55        #include <fcntl.h>
    66}
     7
     8#include <fstream.hfa>
    79#include <iofwd.hfa>
    810
     
    1113extern "C" {
    1214      int snprintf ( char * s, size_t n, const char * format, ... );
    13         #include <linux/io_uring.h>
     15        // #include <linux/io_uring.h>
    1416}
    1517#include <string.h>
     
    2426        "HTTP/1.1 400 Bad Request\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    2527        "HTTP/1.1 404 Not Found\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     28        "HTTP/1.1 405 Method Not Allowed\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     29        "HTTP/1.1 408 Request Timeout\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    2630        "HTTP/1.1 413 Payload Too Large\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    2731        "HTTP/1.1 414 URI Too Long\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     
    3438        400,
    3539        404,
     40        405,
     41        408,
    3642        413,
    3743        414,
     
    4955                int ret = cfa_write(fd, it, len, 0, -1`s, 0p, 0p);
    5056                // int ret = write(fd, it, len);
    51                 if( ret < 0 ) { if( errno != EAGAIN && errno != EWOULDBLOCK) abort( "'answer error' error: (%d) %s\n", (int)errno, strerror(errno) ); }
     57                if( ret < 0 ) {
     58                        if( errno == ECONNRESET || errno == EPIPE ) return -ECONNRESET;
     59                        if( errno == EAGAIN || errno == EWOULDBLOCK) return -EAGAIN;
     60
     61                        abort( "'answer error' error: (%d) %s\n", (int)errno, strerror(errno) );
     62                }
    5263
    5364                // update it/len
     
    94105                if(ret < 0 ) {
    95106                        if( errno == EAGAIN || errno == EWOULDBLOCK) continue READ;
    96                         // if( errno == EINVAL ) return [E400, true, 0, 0];
     107                        if( errno == ECONNRESET ) return [E408, true, 0, 0];
     108                        if( errno == EPIPE ) return [E408, true, 0, 0];
    97109                        abort( "read error: (%d) %s\n", (int)errno, strerror(errno) );
    98110                }
     
    108120        }
    109121
    110         if( options.log ) printf("%.*s\n", rlen, buffer);
     122        if( options.log ) {
     123                write(sout, buffer, rlen);
     124                sout | nl;
     125        }
    111126
    112127        it = buffer;
     
    119134}
    120135
    121 void sendfile( int pipe[2], int fd, int ans_fd, size_t count ) {
     136int sendfile( int pipe[2], int fd, int ans_fd, size_t count ) {
    122137        unsigned sflags = SPLICE_F_MOVE; // | SPLICE_F_MORE;
    123138        off_t offset = 0;
     
    128143                if( ret < 0 ) {
    129144                        if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE1;
     145                        if( errno == ECONNRESET ) return -ECONNRESET;
     146                        if( errno == EPIPE ) return -EPIPE;
    130147                        abort( "splice [0] error: (%d) %s\n", (int)errno, strerror(errno) );
    131148                }
     
    139156                        if( ret < 0 ) {
    140157                                if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE2;
     158                                if( errno == ECONNRESET ) return -ECONNRESET;
     159                                if( errno == EPIPE ) return -EPIPE;
    141160                                abort( "splice [1] error: (%d) %s\n", (int)errno, strerror(errno) );
    142161                        }
     
    145164
    146165        }
     166        return count;
    147167}
    148168
  • benchmark/io/http/protocol.hfa

    rb6a8b31 rd95969a  
    77        E400,
    88        E404,
     9        E405,
     10        E408,
    911        E413,
    1012        E414,
     
    2123[HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len, io_cancellation *);
    2224
    23 void sendfile( int pipe[2], int fd, int ans_fd, size_t count );
     25int sendfile( int pipe[2], int fd, int ans_fd, size_t count );
  • benchmark/io/http/worker.cfa

    rb6a8b31 rd95969a  
    66#include <unistd.h>
    77
     8#include <fstream.hfa>
    89#include <iofwd.hfa>
    910
     
    3334        CONNECTION:
    3435        for() {
    35                 if( options.log ) printf("=== Accepting connection ===\n");
     36                if( options.log ) sout | "=== Accepting connection ===";
    3637                int fd = cfa_accept4( this.[sockfd, addr, addrlen, flags], 0, -1`s, &this.cancel, 0p );
    3738                // int fd = accept4( this.[sockfd, addr, addrlen, flags] );
    3839                if(fd < 0) {
    3940                        if( errno == ECONNABORTED ) break;
    40                         if( errno == EINVAL && this.done ) break;
     41                        if( this.done && (errno == EINVAL || errno == EBADF) ) break;
    4142                        abort( "accept error: (%d) %s\n", (int)errno, strerror(errno) );
    4243                }
    4344
    44                 if( options.log ) printf("=== New connection %d, waiting for requests ===\n", fd);
     45                if( options.log ) sout | "=== New connection" | fd | "" | ", waiting for requests ===";
    4546                REQUEST:
    4647                for() {
     
    5354                        size_t len = options.socket.buflen;
    5455                        char buffer[len];
    55                         if( options.log ) printf("=== Reading request ===\n");
     56                        if( options.log ) sout | "=== Reading request ===";
    5657                        [code, closed, file, name_size] = http_read(fd, buffer, len, &this.cancel);
    5758
    5859                        // if we are done, break out of the loop
    59                         if( closed ) {
    60                                 if( options.log ) printf("=== Connection closed ===\n");
    61                                 close(fd);
    62                                 continue CONNECTION;
    63                         }
     60                        if( closed ) break REQUEST;
    6461
    6562                        // If this wasn't a request retrun 400
    6663                        if( code != OK200 ) {
    67                                 printf("=== Invalid Request : %d ===\n", code_val(code));
     64                                sout | "=== Invalid Request :" | code_val(code) | "===";
    6865                                answer_error(fd, code);
    6966                                continue REQUEST;
     
    7168
    7269                        if(0 == strncmp(file, "plaintext", min(name_size, sizeof("plaintext") ))) {
    73                                 if( options.log ) printf("=== Request for /plaintext ===\n");
     70                                if( options.log ) sout | "=== Request for /plaintext ===";
    7471
    7572                                char text[] = "Hello, World!\n";
    7673
    7774                                // Send the header
    78                                 answer_plain(fd, text, sizeof(text));
     75                                int ret = answer_plain(fd, text, sizeof(text));
     76                                if( ret == -ECONNRESET ) break REQUEST;
    7977
    80                                 if( options.log ) printf("=== Answer sent ===\n");
     78                                if( options.log ) sout | "=== Answer sent ===";
    8179                                continue REQUEST;
    8280                        }
    8381
    8482                        if(0 == strncmp(file, "ping", min(name_size, sizeof("ping") ))) {
    85                                 if( options.log ) printf("=== Request for /ping ===\n");
     83                                if( options.log ) sout | "=== Request for /ping ===";
    8684
    8785                                // Send the header
    88                                 answer_empty(fd);
     86                                int ret = answer_empty(fd);
     87                                if( ret == -ECONNRESET ) break REQUEST;
    8988
    90                                 if( options.log ) printf("=== Answer sent ===\n");
     89                                if( options.log ) sout | "=== Answer sent ===";
    9190                                continue REQUEST;
    9291                        }
    9392
    94                         if( options.log ) printf("=== Request for file %.*s ===\n", (int)name_size, file);
     93                        if( options.log ) {
     94                                sout | "=== Request for file " | nonl;
     95                                write(sout, file, name_size);
     96                                sout | " ===";
     97                        }
     98
     99                        if( !options.file_cache.path ) {
     100                                if( options.log ) {
     101                                        sout | "=== File Not Found (" | nonl;
     102                                        write(sout, file, name_size);
     103                                        sout | ") ===";
     104                                }
     105                                answer_error(fd, E405);
     106                                continue REQUEST;
     107                        }
    95108
    96109                        // Get the fd from the file cache
     
    101114                        // If we can't find the file, return 404
    102115                        if( ans_fd < 0 ) {
    103                                 printf("=== File Not Found ===\n");
     116                                if( options.log ) {
     117                                        sout | "=== File Not Found (" | nonl;
     118                                        write(sout, file, name_size);
     119                                        sout | ") ===";
     120                                }
    104121                                answer_error(fd, E404);
    105122                                continue REQUEST;
     
    107124
    108125                        // Send the header
    109                         answer_header(fd, count);
     126                        int ret = answer_header(fd, count);
     127                        if( ret == -ECONNRESET ) break REQUEST;
    110128
    111129                        // Send the desired file
    112                         sendfile( this.pipe, fd, ans_fd, count);
     130                        ret = sendfile( this.pipe, fd, ans_fd, count);
     131                        if( ret == -ECONNRESET ) break REQUEST;
    113132
    114                         if( options.log ) printf("=== Answer sent ===\n");
     133                        if( options.log ) sout | "=== Answer sent ===";
    115134                }
     135
     136                if( options.log ) sout | "=== Connection closed ===";
     137                close(fd);
     138                continue CONNECTION;
    116139        }
    117140}
  • doc/LaTeXmacros/common.tex

    rb6a8b31 rd95969a  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon Oct  5 09:34:46 2020
    14 %% Update Count     : 464
     13%% Last Modified On : Sat Jan 23 09:06:39 2021
     14%% Update Count     : 491
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    229229\usepackage{listings}                                                                   % format program code
    230230\usepackage{lstlang}
     231\usepackage{calc}                                                                               % latex arithmetic
     232
    231233\makeatletter
    232 
    233234\newcommand{\LstBasicStyle}[1]{{\lst@basicstyle{#1}}}
    234235\newcommand{\LstKeywordStyle}[1]{{\lst@basicstyle{\lst@keywordstyle{#1}}}}
     
    265266showlines=true,                                                 % show blank lines at end of code
    266267aboveskip=4pt,                                                  % spacing above/below code block
    267 belowskip=3pt,
     268belowskip=-2pt,
     269numberstyle=\footnotesize\sf,                   % numbering style
    268270% replace/adjust listing characters that look bad in sanserif
    269271literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1
     
    293295language=CFA,
    294296escapechar=\$,                                                  % LaTeX escape in CFA code
     297mathescape=false,                                               % LaTeX math escape in CFA code $...$
    295298moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
    296299}% lstset
  • doc/bibliography/pl.bib

    rb6a8b31 rd95969a  
    688688    title       = {Asynchronous Exception Propagation in Blocked Tasks},
    689689    booktitle   = {4th International Workshop on Exception Handling (WEH.08)},
    690     organization= {16th International Symposium on the Foundations of Software Engineering (FSE 16)},
     690    optorganization= {16th International Symposium on the Foundations of Software Engineering (FSE 16)},
    691691    address     = {Atlanta, U.S.A},
    692692    month       = nov,
     
    72467246
    72477247@inproceedings{Edelson92,
    7248     keywords    = {persistence, pointers},
     7248    keywords    = {persistence, smart pointers},
    72497249    contributer = {pabuhr@plg},
    72507250    author      = {Daniel R. Edelson},
     
    72567256    year        = 1992,
    72577257    pages       = {1-19},
     7258}
     7259
     7260@incollection{smartpointers,
     7261    keywords    = {smart pointers},
     7262    contributer = {pabuhr@plg},
     7263    author      = {Andrei Alexandrescu},
     7264    title       = {Smart Pointers},
     7265    booktitle   = {Modern C++ Design: Generic Programming and Design Patterns Applied},
     7266    publisher   = {Addison-Wesley},
     7267    year        = 2001,
     7268    chapter     = 7,
     7269    optpages    = {?-?},
    72587270}
    72597271
     
    82458257}
    82468258
     8259@misc{vistorpattern,
     8260    keywords    = {visitor pattern},
     8261    contributer = {pabuhr@plg},
     8262    key         = {vistor pattern},
     8263    title       = {vistor pattern},
     8264    year        = 2020,
     8265    note        = {WikipediA},
     8266    howpublished= {\href{https://en.wikipedia.org/wiki/Visitor\_pattern}
     8267                  {https://\-en.wikipedia.org/\-wiki/\-Visitor\_pattern}},
     8268}
     8269
    82478270% W
    82488271
  • doc/theses/andrew_beach_MMath/.gitignore

    rb6a8b31 rd95969a  
    33
    44# Final Files:
    5 thesis.pdf
     5*.pdf
    66
    77# The Makefile here is not generated.
  • doc/theses/andrew_beach_MMath/Makefile

    rb6a8b31 rd95969a  
    11### Makefile for Andrew Beach's Masters Thesis
    22
    3 DOC=thesis.pdf
     3DOC=uw-ethesis.pdf
    44BUILD=out
    55TEXSRC=$(wildcard *.tex)
     
    77STYSRC=$(wildcard *.sty)
    88CLSSRC=$(wildcard *.cls)
    9 TEXLIB= .:${BUILD}:
     9TEXLIB= .:../../LaTeXmacros:${BUILD}:
    1010BIBLIB= .:../../bibliography
    1111
     
    2929        ${LATEX} ${BASE}
    3030        ${BIBTEX} ${BUILD}/${BASE}
     31        ${LATEX} ${BASE}
    3132        ${GLOSSARY} ${BUILD}/${BASE}
    3233        ${LATEX} ${BASE}
  • doc/theses/andrew_beach_MMath/existing.tex

    rb6a8b31 rd95969a  
    1 \chapter{\CFA{} Existing Features}
    2 
    3 \section{Overloading and extern}
    4 Cforall has overloading, allowing multiple definitions of the same name to
    5 be defined.
    6 
    7 This also adds name mangling so that the assembly symbols are unique for
    8 different overloads. For compatability with names in C there is also a
    9 syntax to diable the name mangling. These unmangled names cannot be overloaded
    10 but act as the interface between C and \CFA code.
    11 
    12 The syntax for disabling mangling is:
    13 \begin{lstlisting}
    14 extern "C" {
    15     ...
    16 }
    17 \end{lstlisting}
    18 
    19 To re-enable mangling once it is disabled the syntax is:
    20 \begin{lstlisting}
    21 extern "Cforall" {
    22     ...
    23 }
    24 \end{lstlisting}
    25 
    26 Both should occur at the declaration level and effect all the declarations
    27 in \texttt{...}. Neither care about the state of mangling when they begin
    28 and will return to that state after the group is finished. So re-enabling
    29 is only used to nest areas of mangled and unmangled declarations.
    30 
    31 \section{References}
    32 \CFA adds references to C. These are auto-dereferencing pointers and use the
    33 same syntax as pointers except they use ampersand (\codeCFA{\&}) instead of
    34 the asterisk (\codeCFA{*}). They can also be constaint or mutable, if they
    35 are mutable they may be assigned to by using the address-of operator
    36 (\codeCFA\&) which converts them into a pointer.
     1\chapter{\texorpdfstring{\CFA Existing Features}{Cforall Existing Features}}
     2
     3\CFA (C-for-all)~\cite{Cforall} is an open-source project extending ISO C with
     4modern safety and productivity features, while still ensuring backwards
     5compatibility with C and its programmers.  \CFA is designed to have an
     6orthogonal feature-set based closely on the C programming paradigm
     7(non-object-oriented) and these features can be added incrementally to an
     8existing C code-base allowing programmers to learn \CFA on an as-needed basis.
     9
     10Only those \CFA features pertinent to this thesis are discussed.  Many of the
     11\CFA syntactic and semantic features used in the thesis should be fairly
     12obvious to the reader.
     13
     14\section{\texorpdfstring{Overloading and \lstinline|extern|}{Overloading and extern}}
     15\CFA has extensive overloading, allowing multiple definitions of the same name
     16to be defined.~\cite{Moss18}
     17\begin{cfa}
     18char i; int i; double i;                        $\C[3.75in]{// variable overload}$
     19int f(); double f();                            $\C{// return overload}$
     20void g( int ); void g( double );        $\C{// parameter overload}\CRT$
     21\end{cfa}
     22This feature requires name mangling so the assembly symbols are unique for
     23different overloads. For compatibility with names in C, there is also a syntax
     24to disable name mangling. These unmangled names cannot be overloaded but act as
     25the interface between C and \CFA code.  The syntax for disabling/enabling
     26mangling is:
     27\begin{cfa}
     28// name mangling
     29int i; // _X1ii_1
     30@extern "C"@ {  // no name mangling
     31        int j; // j
     32        @extern "Cforall"@ {  // name mangling
     33                int k; // _X1ki_1
     34        }
     35        // no name mangling
     36}
     37// name mangling
     38\end{cfa}
     39Both forms of @extern@ affect all the declarations within their nested lexical
     40scope and transition back to the previous mangling state when the lexical scope
     41ends.
     42
     43\section{Reference Type}
     44\CFA adds a rebindable reference type to C, but more expressive than the \CC
     45reference.  Multi-level references are allowed and act like auto-dereferenced
     46pointers using the ampersand (@&@) instead of the pointer asterisk (@*@). \CFA
     47references may also be mutable or non-mutable. If mutable, a reference variable
     48may be assigned to using the address-of operator (@&@), which converts the
     49reference to a pointer.
     50\begin{cfa}
     51int i, j;
     52int @&@ ri = i, @&&@ rri = ri;
     53rri = 3;  // auto-dereference assign to i
     54@&@ri = @&@j; // rebindable
     55ri = 5;   // assign to j
     56\end{cfa}
    3757
    3858\section{Constructors and Destructors}
    3959
    4060Both constructors and destructors are operators, which means they are just
    41 functions with special names. The special names are used to define them and
    42 may be used to call the functions expicately. The \CFA special names are
    43 constructed by taking the tokens in the operators and putting \texttt{?} where
    44 the arguments would go. So multiplication is \texttt{?*?} while dereference
    45 is \texttt{*?}. This also make it easy to tell the difference between
    46 pre-fix operations (such as \texttt{++?}) and post-fix operations
    47 (\texttt{?++}).
    48 
    49 The special name for contructors is \texttt{?\{\}}, which comes from the
    50 initialization syntax in C. The special name for destructors is
    51 \texttt{\^{}?\{\}}. % I don't like the \^{} symbol but $^\wedge$ isn't better.
    52 
    53 Any time a type T goes out of scope the destructor matching
    54 \codeCFA{void ^?\{\}(T \&);} is called. In theory this is also true of
    55 primitive types such as \codeCFA{int}, but in practice those are no-ops and
    56 are usually omitted for optimization.
     61functions with special operator names rather than type names in \CC. The
     62special operator names may be used to call the functions explicitly (not
     63allowed in \CC for constructors).
     64
     65In general, operator names in \CFA are constructed by bracketing an operator
     66token with @?@, which indicates where the arguments. For example, infixed
     67multiplication is @?*?@ while prefix dereference is @*?@. This syntax make it
     68easy to tell the difference between prefix operations (such as @++?@) and
     69post-fix operations (@?++@).
     70
     71The special name for a constructor is @?{}@, which comes from the
     72initialization syntax in C. The special name for a destructor is @^{}@, where
     73the @^@ has no special meaning.
     74% I don't like the \^{} symbol but $^\wedge$ isn't better.
     75\begin{cfa}
     76struct T { ... };
     77void ?@{}@(@T &@ this, ...) { ... }  // constructor
     78void ?@^{}@(@T &@ this, ...) { ... } // destructor
     79{
     80        T s = @{@ ... @}@;  // same constructor/initialization braces
     81} // destructor call automatically generated
     82\end{cfa}
     83The first parameter is a reference parameter to the type for the
     84constructor/destructor. Destructors may have multiple parameters.  The compiler
     85implicitly matches an overloaded constructor @void ^?{}(T &, ...);@ to an
     86object declaration with associated initialization, and generates a construction
     87call after the object is allocated. When an object goes out of scope, the
     88matching overloaded destructor @void ^?{}(T &);@ is called.  Without explicit
     89definition, \CFA creates a default and copy constructor, destructor and
     90assignment (like \CC). It is possible to define constructors/destructors for
     91basic and existing types.
    5792
    5893\section{Polymorphism}
    59 \CFA uses polymorphism to create functions and types that are defined over
    60 different types. \CFA polymorphic declarations serve the same role as \CPP
    61 templates or Java generics.
    62 
    63 Polymorphic declaractions start with a forall clause that goes before the
    64 standard (monomorphic) declaration. These declarations have the same syntax
    65 except that you may use the names introduced by the forall clause in them.
    66 
    67 Forall clauses are written \codeCFA{forall( ... )} where \codeCFA{...} becomes
    68 the list of polymorphic variables (local type names) and assertions, which
    69 repersent required operations on those types.
    70 
    71 \begin{lstlisting}
    72 forall(dtype T | { void do_once(T &); })
    73 void do_twice(T & value) {
    74     do_once(value);
    75     do_once(value);
    76 }
    77 \end{lstlisting}
    78 
    79 A polymorphic function can be used in the same way normal functions are.
    80 The polymorphics variables are filled in with concrete types and the
    81 assertions are checked. An assertion checked by seeing if that name of that
    82 type (with all the variables replaced with the concrete types) is defined at
    83 the the call site.
    84 
    85 As an example, even if no function named \codeCFA{do_once} is not defined
    86 near the definition of \codeCFA{do_twice} the following code will work.
    87 \begin{lstlisting}
     94\CFA uses parametric polymorphism to create functions and types that are
     95defined over multiple types. \CFA polymorphic declarations serve the same role
     96as \CC templates or Java generics. The ``parametric'' means the polymorphism is
     97accomplished by passing argument operations to associate \emph{parameters} at
     98the call site, and these parameters are used in the function to differentiate
     99among the types the function operates on.
     100
     101Polymorphic declarations start with a universal @forall@ clause that goes
     102before the standard (monomorphic) declaration. These declarations have the same
     103syntax except they may use the universal type names introduced by the @forall@
     104clause.  For example, the following is a polymorphic identity function that
     105works on any type @T@:
     106\begin{cfa}
     107@forall( T )@ @T@ identity( @T@ val ) { return val; }
     108int forty_two = identity( 42 ); // T bound to int, forty_two == 42
     109\end{cfa}
     110
     111To allow a polymorphic function to be separately compiled, the type @T@ must be
     112constrained by the operations used on @T@ in the function body. The @forall@
     113clauses is augmented with a list of polymorphic variables (local type names)
     114and assertions (constraints), which represent the required operations on those
     115types used in a function, \eg:
     116\begin{cfa}
     117forall( T @| { void do_once(T); }@) // assertion
     118void do_twice(T value) {
     119        do_once(value);
     120        do_once(value);
     121}
     122void do_once(int i) { ... }  // provide assertion
     123int i;
     124do_twice(i); // implicitly pass assertion do_once to do_twice
     125\end{cfa}
     126Any object with a type fulfilling the assertion may be passed as an argument to
     127a @do_twice@ call.
     128
     129A polymorphic function can be used in the same way as a normal function.  The
     130polymorphic variables are filled in with concrete types and the assertions are
     131checked. An assertion is checked by verifying each assertion operation (with
     132all the variables replaced with the concrete types from the arguments) is
     133defined at a call site.
     134
     135Note, a function named @do_once@ is not required in the scope of @do_twice@ to
     136compile it, unlike \CC template expansion. Furthermore, call-site inferencing
     137allows local replacement of the most specific parametric functions needs for a
     138call.
     139\begin{cfa}
     140void do_once(double y) { ... } // global
    88141int quadruple(int x) {
    89     void do_once(int & y) {
    90         y = y * 2;
    91     }
    92     do_twice(x);
    93     return x;
    94 }
    95 \end{lstlisting}
    96 This is not the recommended way to implement a quadruple function but it
    97 does work. The complier will deduce that \codeCFA{do_twice}'s T is an
    98 integer from the argument. It will then look for a definition matching the
    99 assertion which is the \codeCFA{do_once} defined within the function. That
    100 function will be passed in as a function pointer to \codeCFA{do_twice} and
    101 called within it.
    102 
    103 To avoid typing out long lists of assertions again and again there are also
    104 traits which collect assertions into convenent packages that can then be used
    105 in assertion lists instead of all of their components.
    106 \begin{lstlisting}
    107 trait done_once(dtype T) {
    108     void do_once(T &);
    109 }
    110 \end{lstlisting}
    111 
    112 After this the forall list in the previous example could instead be written
    113 with the trait instead of the assertion itself.
    114 \begin{lstlisting}
    115 forall(dtype T | done_once(T))
    116 \end{lstlisting}
    117 
    118 Traits can have arbitrary number of assertions in them and are usually used to
    119 create short hands for, and give descriptive names to, commond groupings of
    120 assertions.
    121 
    122 Polymorphic structures and unions may also be defined by putting a forall
    123 clause before the declaration. The type variables work the same way except
    124 are now used in field declaractions instead of parameters and local variables.
    125 
    126 \begin{lstlisting}
     142        void do_once(int y) { y = y * 2; } // local
     143        do_twice(x); // using local "do_once"
     144        return x;
     145}
     146\end{cfa}
     147Specifically, the complier deduces that @do_twice@'s T is an integer from the
     148argument @x@. It then looks for the most specific definition matching the
     149assertion, which is the nested integral @do_once@ defined within the
     150function. The matched assertion function is then passed as a function pointer
     151to @do_twice@ and called within it.
     152
     153To avoid typing long lists of assertions, constraints can be collect into
     154convenient packages called a @trait@, which can then be used in an assertion
     155instead of the individual constraints.
     156\begin{cfa}
     157trait done_once(T) {
     158        void do_once(T);
     159}
     160\end{cfa}
     161and the @forall@ list in the previous example is replaced with the trait.
     162\begin{cfa}
     163forall(dtype T | @done_once(T)@)
     164\end{cfa}
     165In general, a trait can contain an arbitrary number of assertions, both
     166functions and variables, and are usually used to create a shorthand for, and
     167give descriptive names to, common groupings of assertions describing a certain
     168functionality, like @sumable@, @listable@, \etc.
     169
     170Polymorphic structures and unions are defined by qualifying the aggregate type
     171with @forall@. The type variables work the same except they are used in field
     172declarations instead of parameters, returns, and local variable declarations.
     173\begin{cfa}
    127174forall(dtype T)
    128175struct node {
    129     node(T) * next;
    130     T * data;
    131 }
    132 \end{lstlisting}
    133 
    134 The \codeCFA{node(T)} is a use of a polymorphic structure. Polymorphic types
    135 must be provided their polymorphic parameters.
    136 
    137 There are many other features of polymorphism that have not given here but
    138 these are the ones used by the exception system.
     176        node(T) * next;  // generic linked node
     177        T * data;
     178}
     179\end{cfa}
     180The generic type @node(T)@ is an example of a polymorphic-type usage.  Like \CC
     181templates usage, a polymorphic-type usage must specify a type parameter.
     182
     183There are many other polymorphism features in \CFA but these are the ones used
     184by the exception system.
    139185
    140186\section{Concurrency}
    141 
    142 \CFA has a number of concurrency features, \codeCFA{thread}s,
    143 \codeCFA{monitor}s and \codeCFA{mutex} parameters, \codeCFA{coroutine}s and
    144 \codeCFA{generator}s. The two features that interact with the exception system
    145 are \codeCFA{thread}s and \codeCFA{coroutine}s; they and their supporting
    146 constructs will be described here.
    147 
    148 \subsection{Coroutines}
    149 Coroutines are routines that do not have to finish execution to hand control
    150 back to their caller, instead they may suspend their execution at any time
    151 and resume it later.
    152 Coroutines are not true concurrency but share some similarities and many of
    153 the same underpinnings and so are included as part of the \CFA threading
    154 library.
    155 
    156 In \CFA coroutines are created using the \codeCFA{coroutine} keyword which
    157 works just like \codeCFA{struct} except that the created structure will be
    158 modified by the compiler to satify the \codeCFA{is_coroutine} trait.
    159 
    160 These structures act as the interface between callers and the coroutine,
    161 the fields are used to pass information in and out. Here is a simple example
    162 where the single field is used to pass the next number in a sequence out.
    163 \begin{lstlisting}
     187\CFA has a number of concurrency features: @thread@, @monitor@, @mutex@
     188parameters, @coroutine@ and @generator@. The two features that interact with
     189the exception system are @thread@ and @coroutine@; they and their supporting
     190constructs are described here.
     191
     192\subsection{Coroutine}
     193A coroutine is a type with associated functions, where the functions are not
     194required to finish execution when control is handed back to the caller. Instead
     195they may suspend execution at any time and be resumed later at the point of
     196last suspension. (Generators are stackless and coroutines are stackful.) These
     197types are not concurrent but share some similarities along with common
     198underpinnings, so they are combined with the \CFA threading library. Further
     199discussion in this section only refers to the coroutine because generators are
     200similar.
     201
     202In \CFA, a coroutine is created using the @coroutine@ keyword, which is an
     203aggregate type like @struct,@ except the structure is implicitly modified by
     204the compiler to satisfy the @is_coroutine@ trait; hence, a coroutine is
     205restricted by the type system to types that provide this special trait.  The
     206coroutine structure acts as the interface between callers and the coroutine,
     207and its fields are used to pass information in and out of coroutine interface
     208functions.
     209
     210Here is a simple example where a single field is used to pass (communicate) the
     211next number in a sequence.
     212\begin{cfa}
    164213coroutine CountUp {
    165     unsigned int next;
    166 }
    167 \end{lstlisting}
    168 
    169 The routine part of the coroutine is a main function for the coroutine. It
    170 takes a reference to a coroutine object and returns nothing. In this function,
    171 and any functions called by this function, the suspend statement may be used
    172 to return execution to the coroutine's caller. When control returns to the
    173 function it continue from that same suspend statement instead of at the top
    174 of the function.
    175 \begin{lstlisting}
    176 void main(CountUp & this) {
    177     unsigned int next = 0;
    178     while (true) {
    179         this.next = next;
    180         suspend;
    181         next = next + 1;
    182     }
    183 }
    184 \end{lstlisting}
    185 
    186 Control is passed to the coroutine with the resume function. This includes the
    187 first time when the coroutine is starting up. The resume function takes a
    188 reference to the coroutine structure and returns the same reference. The
    189 return value is for easy access to communication variables. For example the
    190 next value from a count-up can be generated and collected in a single
    191 expression: \codeCFA{resume(count).next}.
     214        unsigned int next; // communication variable
     215}
     216CountUp countup;
     217\end{cfa}
     218Each coroutine has @main@ function, which takes a reference to a coroutine
     219object and returns @void@.
     220\begin{cfa}[numbers=left]
     221void main(@CountUp & this@) { // argument matches trait is_coroutine
     222        unsigned int up = 0;  // retained between calls
     223        while (true) {
     224                next = up; // make "up" available outside function
     225                @suspend;@$\label{suspend}$
     226                up += 1;
     227        }
     228}
     229\end{cfa}
     230In this function, or functions called by this function (helper functions), the
     231@suspend@ statement is used to return execution to the coroutine's caller
     232without terminating the coroutine.
     233
     234A coroutine is resumed by calling the @resume@ function, \eg @resume(countup)@.
     235The first resume calls the @main@ function at the top. Thereafter, resume calls
     236continue a coroutine in the last suspended function after the @suspend@
     237statement, in this case @main@ line~\ref{suspend}.  The @resume@ function takes
     238a reference to the coroutine structure and returns the same reference. The
     239return value allows easy access to communication variables defined in the
     240coroutine object. For example, the @next@ value for coroutine object @countup@
     241is both generated and collected in the single expression:
     242@resume(countup).next@.
    192243
    193244\subsection{Monitors and Mutex}
    194 
    195 True concurrency does not garrenty ordering. To get some of that ordering back
    196 \CFA uses monitors and mutex (mutual exclution) parameters. A monitor is
    197 another special declaration that contains a lock and is compatable with mutex
    198 parameters.
    199 
    200 Function parameters can have the \codeCFA{mutex} qualifiers on reference
    201 arguments, for example \codeCFA{void example(a_monitor & mutex arg);}. When the
    202 function is called it will acquire the lock on all of the mutex parameters.
    203 
    204 This means that all functions that mutex on a type are part of a critical
    205 section and only one will ever run at a time.
     245Concurrency does not guarantee ordering; without ordering results are
     246non-deterministic. To claw back ordering, \CFA uses monitors and @mutex@
     247(mutual exclusion) parameters. A monitor is another kind of aggregate, where
     248the compiler implicitly inserts a lock and instances are compatible with
     249@mutex@ parameters.
     250
     251A function that requires deterministic (ordered) execution, acquires mutual
     252exclusion on a monitor object by qualifying an object reference parameter with
     253@mutex@.
     254\begin{cfa}
     255void example(MonitorA & @mutex@ argA, MonitorB & @mutex@ argB);
     256\end{cfa}
     257When the function is called, it implicitly acquires the monitor lock for all of
     258the mutex parameters without deadlock.  This semantics means all functions with
     259the same mutex type(s) are part of a critical section for objects of that type
     260and only one runs at a time.
    206261
    207262\subsection{Threads}
    208 While coroutines allow new things to be done with a single execution path
    209 threads actually introduce new paths of execution that continue independently.
    210 Now for threads to work together their must be some communication between them
    211 and that means the timing of certain operations does have to be known. There
    212 or various means of syncronization and mutual exclution provided by \CFA but
    213 for exceptions only the basic two -- fork and join -- are needed.
    214 
    215 Threads are created like coroutines except the keyword is changed:
    216 \begin{lstlisting}
     263Functions, generators, and coroutines are sequential so there is only a single
     264(but potentially sophisticated) execution path in a program. Threads introduce
     265multiple execution paths that continue independently.
     266
     267For threads to work safely with objects requires mutual exclusion using
     268monitors and mutex parameters. For threads to work safely with other threads,
     269also requires mutual exclusion in the form of a communication rendezvous, which
     270also supports internal synchronization as for mutex objects. For exceptions
     271only the basic two basic operations are important: thread fork and join.
     272
     273Threads are created like coroutines with an associated @main@ function:
     274\begin{cfa}
    217275thread StringWorker {
    218     const char * input;
    219     int result;
     276        const char * input;
     277        int result;
    220278};
    221 
    222279void main(StringWorker & this) {
    223     const char * localCopy = this.input;
    224     // ... do some work, perhaps hashing the string ...
    225     this.result = result;
    226 }
    227 \end{lstlisting}
    228 The main function will start executing after the fork operation and continue
    229 executing until it is finished. If another thread joins with this one it will
    230 wait until main has completed execution. In other words everything the thread
    231 does is between fork and join.
    232 
    233 From the outside this is the creation and destruction of the thread object.
    234 Fork happens after the constructor is run and join happens before the
    235 destructor runs. Join also happens during the \codeCFA{join} function which
    236 can be used to join a thread earlier. If it is used the destructor does not
    237 join as that has already been completed.
     280        const char * localCopy = this.input;
     281        // ... do some work, perhaps hashing the string ...
     282        this.result = result;
     283}
     284{
     285        StringWorker stringworker; // fork thread running in "main"
     286} // implicitly join with thread $\(\Rightarrow\)$ wait for completion
     287\end{cfa}
     288The thread main is where a new thread starts execution after a fork operation
     289and then the thread continues executing until it is finished. If another thread
     290joins with an executing thread, it waits until the executing main completes
     291execution. In other words, everything a thread does is between a fork and join.
     292
     293From the outside, this behaviour is accomplished through creation and
     294destruction of a thread object.  Implicitly, fork happens after a thread
     295object's constructor is run and join happens before the destructor runs. Join
     296can also be specified explicitly using the @join@ function to wait for a
     297thread's completion independently from its deallocation (\ie destructor
     298call). If @join@ is called explicitly, the destructor does not implicitly join.
  • doc/theses/andrew_beach_MMath/features.tex

    rb6a8b31 rd95969a  
    1 \chapter{Features}
    2 
    3 This chapter covers the design and user interface of the \CFA exception
    4 handling mechanism.
    5 
    6 \section{Virtual Casts}
    7 
    8 Virtual casts and virtual types are not truly part of the exception system but
    9 they did not exist in \CFA and are useful in exceptions. So a minimal version
    10 of they virtual system was designed and implemented.
    11 
    12 Virtual types are organizied in simple hierarchies. Each virtual type may have
    13 a parent and can have any number of children. A type's descendants are its
    14 children and its children's descendants. A type may not be its own descendant.
    15 
    16 Each virtual type has an associated virtual table type. A virtual table is a
    17 structure that has fields for all the virtual members of a type. A virtual
    18 type has all the virtual members of its parent and can add more. It may also
    19 update the values of the virtual members.
    20 
    21 Except for virtual casts, this is only used internally in the exception
    22 system. There is no general purpose interface for the other features. A
    23 a virtual cast has the following syntax:
    24 
    25 \begin{lstlisting}
     1\chapter{Exception Features}
     2
     3This chapter covers the design and user interface of the \CFA
     4exception-handling mechanism.
     5
     6\section{Virtuals}
     7Virtual types and casts are not required for a basic exception-system but are
     8useful for advanced exception features. However, \CFA is not object-oriented so
     9there is no obvious concept of virtuals.  Hence, to create advanced exception
     10features for this work, I needed to designed and implemented a virtual-like
     11system for \CFA.
     12
     13Object-oriented languages often organized exceptions into a simple hierarchy,
     14\eg Java.
     15\begin{center}
     16\setlength{\unitlength}{4000sp}%
     17\begin{picture}(1605,612)(2011,-1951)
     18\put(2100,-1411){\vector(1, 0){225}}
     19\put(3450,-1411){\vector(1, 0){225}}
     20\put(3550,-1411){\line(0,-1){225}}
     21\put(3550,-1636){\vector(1, 0){150}}
     22\put(3550,-1636){\line(0,-1){225}}
     23\put(3550,-1861){\vector(1, 0){150}}
     24\put(2025,-1490){\makebox(0,0)[rb]{\LstBasicStyle{exception}}}
     25\put(2400,-1460){\makebox(0,0)[lb]{\LstBasicStyle{arithmetic}}}
     26\put(3750,-1460){\makebox(0,0)[lb]{\LstBasicStyle{underflow}}}
     27\put(3750,-1690){\makebox(0,0)[lb]{\LstBasicStyle{overflow}}}
     28\put(3750,-1920){\makebox(0,0)[lb]{\LstBasicStyle{zerodivide}}}
     29\end{picture}%
     30\end{center}
     31The hierarchy provides the ability to handle an exception at different degrees
     32of specificity (left to right).  Hence, it is possible to catch a more general
     33exception-type in higher-level code where the implementation details are
     34unknown, which reduces tight coupling to the lower-level implementation.
     35Otherwise, low-level code changes require higher-level code changes, \eg,
     36changing from raising @underflow@ to @overflow@ at the low level means changing
     37the matching catch at the high level versus catching the general @arithmetic@
     38exception. In detail, each virtual type may have a parent and can have any
     39number of children. A type's descendants are its children and its children's
     40descendants. A type may not be its own descendant.
     41
     42The exception hierarchy allows a handler (@catch@ clause) to match multiple
     43exceptions, \eg a base-type handler catches both base and derived
     44exception-types.
     45\begin{cfa}
     46try {
     47        ...
     48} catch(arithmetic &) {
     49        ... // handle arithmetic, underflow, overflow, zerodivide
     50}
     51\end{cfa}
     52Most exception mechanisms perform a linear search of the handlers and select
     53the first matching handler, so the order of handers is now important because
     54matching is many to one.
     55
     56Each virtual type needs an associated virtual table. A virtual table is a
     57structure with fields for all the virtual members of a type. A virtual type has
     58all the virtual members of its parent and can add more. It may also update the
     59values of the virtual members and often does.
     60
     61While much of the virtual infrastructure is created, it is currently only used
     62internally for exception handling. The only user-level feature is the virtual
     63cast, which is the same as the \CC \lstinline[language=C++]|dynamic_cast|.
     64\begin{cfa}
    2665(virtual TYPE)EXPRESSION
    27 \end{lstlisting}
    28 
    29 This has the same precidence as a traditional C-cast and can be used in the
    30 same places. This will convert the result of EXPRESSION to the type TYPE. Both
    31 the type of EXPRESSION and TYPE must be pointers to virtual types.
    32 
    33 The cast is checked and will either return the original value or null, based
    34 on the result of the check. The check is does the object pointed at have a
    35 type that is a descendant of the target type. If it is the result is the
    36 pointer, otherwise the result is null.
    37 
    38 \section{Exceptions}
     66\end{cfa}
     67Note, the syntax and semantics matches a C-cast, rather than the unusual \CC
     68syntax for special casts. Both the type of @EXPRESSION@ and @TYPE@ must be a
     69pointer to a virtual type. The cast dynamically checks if the @EXPRESSION@ type
     70is the same or a subtype of @TYPE@, and if true, returns a pointer to the
     71@EXPRESSION@ object, otherwise it returns @0p@ (null pointer).
     72
     73\section{Exception}
    3974% Leaving until later, hopefully it can talk about actual syntax instead
    4075% of my many strange macros. Syntax aside I will also have to talk about the
    4176% features all exceptions support.
    4277
    43 \section{Termination}
    44 
    45 Termination exception throws are likely the most framilar kind, as they are
    46 used in several popular programming languages. A termination will throw an
    47 exception, search the stack for a handler, unwind the stack to where the
    48 handler is defined, execute the handler and then continue execution after
    49 the handler. They are used when execution cannot continue here.
    50 
    51 Termination has two pieces of syntax it uses. The first is the throw:
    52 \begin{lstlisting}
     78Exceptions are defined by the trait system; there are a series of traits, and
     79if a type satisfies them, then it can be used as an exception.  The following
     80is the base trait all exceptions need to match.
     81\begin{cfa}
     82trait is_exception(exceptT &, virtualT &) {
     83        virtualT const & @get_exception_vtable@(exceptT *);
     84};
     85\end{cfa}
     86The function takes any pointer, including the null pointer, and returns a
     87reference to the virtual-table object. Defining this function also establishes
     88the virtual type and a virtual-table pair to the \CFA type-resolver and
     89promises @exceptT@ is a virtual type and a child of the base exception-type.
     90
     91{\color{blue} PAB: I do not understand this paragraph.}
     92One odd thing about @get_exception_vtable@ is that it should always be a
     93constant function, returning the same value regardless of its argument.  A
     94pointer or reference to the virtual table instance could be used instead,
     95however using a function has some ease of implementation advantages and allows
     96for easier disambiguation because the virtual type name (or the address of an
     97instance that is in scope) can be used instead of the mangled virtual table
     98name.  Also note the use of the word ``promise'' in the trait
     99description. Currently, \CFA cannot check to see if either @exceptT@ or
     100@virtualT@ match the layout requirements. This is considered part of
     101@get_exception_vtable@'s correct implementation.
     102
     103\section{Raise}
     104\CFA provides two kinds of exception raise: termination (see
     105\VRef{s:Termination}) and resumption (see \VRef{s:Resumption}), which are
     106specified with the following traits.
     107\begin{cfa}
     108trait is_termination_exception(
     109                exceptT &, virtualT & | is_exception(exceptT, virtualT)) {
     110        void @defaultTerminationHandler@(exceptT &);
     111};
     112\end{cfa}
     113The function is required to allow a termination raise, but is only called if a
     114termination raise does not find an appropriate handler.
     115
     116Allowing a resumption raise is similar.
     117\begin{cfa}
     118trait is_resumption_exception(
     119                exceptT &, virtualT & | is_exception(exceptT, virtualT)) {
     120        void @defaultResumptionHandler@(exceptT &);
     121};
     122\end{cfa}
     123The function is required to allow a resumption raise, but is only called if a
     124resumption raise does not find an appropriate handler.
     125
     126Finally there are three convenience macros for referring to the these traits:
     127@IS_EXCEPTION@, @IS_TERMINATION_EXCEPTION@ and @IS_RESUMPTION_EXCEPTION@.  Each
     128takes the virtual type's name, and for polymorphic types only, the
     129parenthesized list of polymorphic arguments. These macros do the name mangling
     130to get the virtual-table name and provide the arguments to both sides
     131{\color{blue}(PAB: What's a ``side''?)}
     132
     133\subsection{Termination}
     134\label{s:Termination}
     135
     136Termination raise, called ``throw'', is familiar and used in most programming
     137languages with exception handling. The semantics of termination is: search the
     138stack for a matching handler, unwind the stack frames to the matching handler,
     139execute the handler, and continue execution after the handler. Termination is
     140used when execution \emph{cannot} return to the throw. To continue execution,
     141the program must \emph{recover} in the handler from the failed (unwound)
     142execution at the raise to safely proceed after the handler.
     143
     144A termination raise is started with the @throw@ statement:
     145\begin{cfa}
    53146throw EXPRESSION;
    54 \end{lstlisting}
    55 
    56 The expression must evaluate to a reference to a termination exception. A
    57 termination exception is any exception with a
    58 \codeCFA{void defaultTerminationHandler(T &);} (the default handler) defined
    59 on it. The handler is taken from the call sight with \CFA's trait system and
    60 passed into the exception system along with the exception itself.
    61 
    62 The exception passed into the system is then copied into managed memory.
    63 This is to ensure it remains in scope during unwinding. It is the user's
    64 responsibility to make sure the original exception is freed when it goes out
    65 of scope. Being allocated on the stack is sufficient for this.
    66 
    67 Then the exception system will search the stack starting from the throw and
    68 proceding towards the base of the stack, from callee to caller. As it goes
    69 it will check any termination handlers it finds:
    70 
    71 \begin{lstlisting}
    72 try {
    73     TRY_BLOCK
    74 } catch (EXCEPTION_TYPE * NAME) {
    75     HANDLER
    76 }
    77 \end{lstlisting}
    78 
    79 This shows a try statement with a single termination handler. The statements
    80 in TRY\_BLOCK will be executed when control reaches this statement. While
    81 those statements are being executed if a termination exception is thrown and
    82 it is not handled by a try statement further up the stack the EHM will check
    83 all of the terminations handlers attached to the try block, top to bottom.
    84 
    85 At each handler the EHM will check to see if the thrown exception is a
    86 descendant of EXCEPTION\_TYPE. If it is the pointer to the exception is
    87 bound to NAME and the statements in HANDLER are executed. If control reaches
    88 the end of the handler then it exits the block, the exception is freed and
    89 control continues after the try statement.
    90 
    91 The default handler is only used if no handler for the exception is found
    92 after the entire stack is searched. When that happens the default handler
    93 is called with a reference to the exception as its only argument. If the
    94 handler returns control continues from after the throw statement.
    95 
    96 \paragraph{Conditional Catches}
    97 
    98 Catch clauses may also be written as:
    99 \begin{lstlisting}
    100 catch (EXCEPTION_TYPE * NAME ; CONDITION)
    101 \end{lstlisting}
    102 This has the same behaviour as a regular catch clause except that if the
    103 exception matches the given type the condition is also run. If the result is
    104 true only then is this considered a matching handler. If the result is false
    105 then the handler does not match and the search continues with the next clause
    106 in the try block.
    107 
    108 The condition considers all names in scope at the beginning of the try block
    109 to be in scope along with the name introduce in the catch clause itself.
    110 
    111 \paragraph{Re-Throwing}
    112 
    113 You can also rethrow the most recent termination exception with
    114 \codeCFA{throw;}. % This is terrible and you should never do it.
    115 This can be done in a handler or any function that could be called from a
    116 handler.
    117 
    118 This will start another termination throw reusing the exception, meaning it
    119 does not copy the exception or allocated any more memory for it. However the
    120 default handler is still at the original through and could refer to data that
    121 was on the unwound section of the stack. So instead a new default handler that
    122 does a program level abort is used.
    123 
    124 \section{Resumption}
    125 
    126 Resumption exceptions are less popular then termination but in many
    127 regards are simpler and easier to understand. A resumption throws an exception,
    128 searches for a handler on the stack, executes that handler on top of the stack
    129 and then continues execution from the throw. These are used when a problem
    130 needs to be fixed before execution continues.
    131 
    132 A resumption is thrown with a throw resume statement:
    133 \begin{lstlisting}
     147\end{cfa}
     148The expression must return a termination-exception reference, where the
     149termination exception has a type with a @void defaultTerminationHandler(T &)@
     150(default handler) defined. The handler is found at the call site using \CFA's
     151trait system and passed into the exception system along with the exception
     152itself.
     153
     154At runtime, a representation of the exception type and an instance of the
     155exception type is copied into managed memory (heap) to ensure it remains in
     156scope during unwinding. It is the user's responsibility to ensure the original
     157exception object at the throw is freed when it goes out of scope. Being
     158allocated on the stack is sufficient for this.
     159
     160Then the exception system searches the stack starting from the throw and
     161proceeding towards the base of the stack, from callee to caller. At each stack
     162frame, a check is made for termination handlers defined by the @catch@ clauses
     163of a @try@ statement.
     164\begin{cfa}
     165try {
     166        GUARDED_BLOCK
     167} @catch (EXCEPTION_TYPE$\(_1\)$ * NAME)@ { // termination handler 1
     168        HANDLER_BLOCK$\(_1\)$
     169} @catch (EXCEPTION_TYPE$\(_2\)$ * NAME)@ { // termination handler 2
     170        HANDLER_BLOCK$\(_2\)$
     171}
     172\end{cfa}
     173The statements in the @GUARDED_BLOCK@ are executed. If those statements, or any
     174functions invoked from those statements, throws an exception, and the exception
     175is not handled by a try statement further up the stack, the termination
     176handlers are searched for a matching exception type from top to bottom.
     177
     178Exception matching checks the representation of the thrown exception-type is
     179the same or a descendant type of the exception types in the handler clauses. If
     180there is a match, a pointer to the exception object created at the throw is
     181bound to @NAME@ and the statements in the associated @HANDLER_BLOCK@ are
     182executed. If control reaches the end of the handler, the exception is freed,
     183and control continues after the try statement.
     184
     185The default handler visible at the throw statement is used if no matching
     186termination handler is found after the entire stack is searched. At that point,
     187the default handler is called with a reference to the exception object
     188generated at the throw. If the default handler returns, the system default
     189action is executed, which often terminates the program. This feature allows
     190each exception type to define its own action, such as printing an informative
     191error message, when an exception is not handled in the program.
     192
     193\subsection{Resumption}
     194\label{s:Resumption}
     195
     196Resumption raise, called ``resume'', is as old as termination
     197raise~\cite{Goodenough75} but is less popular. In many ways, resumption is
     198simpler and easier to understand, as it is simply a dynamic call (as in
     199Lisp). The semantics of resumption is: search the stack for a matching handler,
     200execute the handler, and continue execution after the resume. Notice, the stack
     201cannot be unwound because execution returns to the raise point. Resumption is
     202used used when execution \emph{can} return to the resume. To continue
     203execution, the program must \emph{correct} in the handler for the failed
     204execution at the raise so execution can safely continue after the resume.
     205
     206A resumption raise is started with the @throwResume@ statement:
     207\begin{cfa}
    134208throwResume EXPRESSION;
    135 \end{lstlisting}
    136 The result of EXPRESSION must be a resumption exception type. A resumption
    137 exception type is any type that satifies the assertion
    138 \codeCFA{void defaultResumptionHandler(T &);} (the default handler). When the
    139 statement is executed the expression is evaluated and the result is thrown.
    140 
    141 Handlers are declared using clauses in try statements:
    142 \begin{lstlisting}
    143 try {
    144     TRY_BLOCK
    145 } catchResume (EXCEPTION_TYPE * NAME) {
    146     HANDLER
    147 }
    148 \end{lstlisting}
    149 This is a simple example with the try block and a single resumption handler.
    150 Multiple resumption handlers can be put in a try statement and they can be
    151 mixed with termination handlers.
    152 
    153 When a resumption begins it will start searching the stack starting from
    154 the throw statement and working its way to the callers. In each try statement
    155 handlers will be tried top to bottom. Each handler is checked by seeing if
    156 the thrown exception is a descendant of EXCEPTION\_TYPE. If not the search
    157 continues. Otherwise NAME is bound to a pointer to the exception and the
    158 HANDLER statements are executed. After they are finished executing control
    159 continues from the throw statement.
    160 
    161 If no approprate handler is found then the default handler is called. The
    162 throw statement acts as a regular function call passing the exception to
    163 the default handler and after the handler finishes executing control continues
    164 from the throw statement.
    165 
    166 The exception system also tracks the position of a search on the stack. If
    167 another resumption exception is thrown while a resumption handler is running
    168 it will first check handlers pushed to the stack by the handler and any
    169 functions it called, then it will continue from the try statement that the
    170 handler is a part of; except for the default handler where it continues from
    171 the throw the default handler was passed to.
    172 
    173 This makes the search pattern for resumption reflect the one for termination,
    174 which is what most users expect.
    175 
    176 % This might need a diagram. But it is an important part of the justifaction
     209\end{cfa}
     210The semantics of the @throwResume@ statement are like the @throw@, but the
     211expression has a type with a @void defaultResumptionHandler(T &)@ (default
     212handler) defined, where the handler is found at the call site by the type
     213system.  At runtime, a representation of the exception type and an instance of
     214the exception type is \emph{not} copied because the stack is maintained during
     215the handler search.
     216
     217Then the exception system searches the stack starting from the resume and
     218proceeding towards the base of the stack, from callee to caller. At each stack
     219frame, a check is made for resumption handlers defined by the @catchResume@
     220clauses of a @try@ statement.
     221\begin{cfa}
     222try {
     223        GUARDED_BLOCK
     224} @catchResume (EXCEPTION_TYPE$\(_1\)$ * NAME)@ { // resumption handler 1
     225        HANDLER_BLOCK$\(_1\)$
     226} @catchResume (EXCEPTION_TYPE$\(_2\)$ * NAME)@ { // resumption handler 2
     227        HANDLER_BLOCK$\(_2\)$
     228}
     229\end{cfa}
     230The statements in the @GUARDED_BLOCK@ are executed. If those statements, or any
     231functions invoked from those statements, resumes an exception, and the
     232exception is not handled by a try statement further up the stack, the
     233resumption handlers are searched for a matching exception type from top to
     234bottom. (Note, termination and resumption handlers may be intermixed in a @try@
     235statement but the kind of raise (throw/resume) only matches with the
     236corresponding kind of handler clause.)
     237
     238The exception search and matching for resumption is the same as for
     239termination, including exception inheritance. The difference is when control
     240reaches the end of the handler: the resumption handler returns after the resume
     241rather than after the try statement. The resume point assumes the handler has
     242corrected the problem so execution can safely continue.
     243
     244Like termination, if no resumption handler is found, the default handler
     245visible at the resume statement is called, and the system default action is
     246executed.
     247
     248For resumption, the exception system uses stack marking to partition the
     249resumption search. If another resumption exception is raised in a resumption
     250handler, the second exception search does not start at the point of the
     251original raise. (Remember the stack is not unwound and the current handler is
     252at the top of the stack.) The search for the second resumption starts at the
     253current point on the stack because new try statements may have been pushed by
     254the handler or functions called from the handler. If there is no match back to
     255the point of the current handler, the search skips the stack frames already
     256searched by the first resume and continues after the try statement. The default
     257handler always continues from default handler associated with the point where
     258the exception is created.
     259
     260% This might need a diagram. But it is an important part of the justification
    177261% of the design of the traversal order.
    178 It also avoids the recursive resumption problem. If the entire stack is
    179 searched loops of resumption can form. Consider a handler that handles an
    180 exception of type A by resuming an exception of type B and on the same stack,
    181 later in the search path, is a second handler that handles B by resuming A.
    182 
    183 Assuming no other handlers on the stack handle A or B then in either traversal
    184 system an A resumed from the top of the stack will be handled by the first
    185 handler. A B resumed from the top or from the first handler it will be handled
    186 by the second hander. The only difference is when A is thrown from the second
    187 handler. The entire stack search will call the first handler again, creating a
    188 loop. Starting from the position in the stack though will break this loop.
    189 
    190 \paragraph{Conditional Catches}
    191 
    192 Resumption supports conditional catch clauses like termination does. They
    193 use the same syntax except the keyword is changed:
    194 \begin{lstlisting}
    195 catchResume (EXCEPTION_TYPE * NAME ; CONDITION) 
    196 \end{lstlisting}
    197 
    198 It also has the same behaviour, after the exception type has been matched
    199 with the EXCEPTION\_TYPE the CONDITION is evaluated with NAME in scope. If
    200 the result is true then the hander is run, otherwise the search continues
    201 just as if there had been a type mismatch.
    202 
    203 \paragraph{Re-Throwing}
    204 
    205 You may also re-throw resumptions with a \codeCFA{throwResume;} statement.
    206 This can only be done from inside of a \codeCFA{catchResume} block.
    207 
    208 Outside of any side effects of any code already run in the handler this will
    209 have the same effect as if the exception had not been caught in the first
    210 place.
     262\begin{verbatim}
     263       throwResume2 ----------.
     264            |                 |
     265 generated from handler       |
     266            |                 |
     267         handler              |
     268            |                 |
     269        throwResume1 -----.   :
     270            |             |   :
     271           try            |   : search skip
     272            |             |   :
     273        catchResume  <----'   :
     274            |                 |
     275\end{verbatim}
     276
     277This resumption search-pattern reflect the one for termination, which matches
     278with programmer expectations. However, it avoids the \emph{recursive
     279resumption} problem. If parts of the stack are searched multiple times, loops
     280can easily form resulting in infinite recursion.
     281
     282Consider the trivial case:
     283\begin{cfa}
     284try {
     285        throwResume$\(_1\)$ (E &){};
     286} catch( E * ) {
     287        throwResume;
     288}
     289\end{cfa}
     290Based on termination semantics, programmer expectation is for the re-resume to
     291continue searching the stack frames after the try statement. However, the
     292current try statement is still on the stack below the handler issuing the
     293reresume (see \VRef{s:Reraise}). Hence, the try statement catches the re-raise
     294again and does another re-raise \emph{ad infinitum}, which is confusing and
     295difficult to debug. The \CFA resumption search-pattern skips the try statement
     296so the reresume search continues after the try, mathcing programmer
     297expectation.
     298
     299\section{Conditional Catch}
     300Both termination and resumption handler-clauses may perform conditional matching:
     301\begin{cfa}
     302catch (EXCEPTION_TYPE * NAME ; @CONDITION@)
     303\end{cfa}
     304First, the same semantics is used to match the exception type. Second, if the
     305exception matches, @CONDITION@ is executed. The condition expression may
     306reference all names in scope at the beginning of the try block and @NAME@
     307introduced in the handler clause.  If the condition is true, then the handler
     308matches. Otherwise, the exception search continues at the next appropriate kind
     309of handler clause in the try block.
     310\begin{cfa}
     311try {
     312        f1 = open( ... );
     313        f2 = open( ... );
     314        ...
     315} catch( IOFailure * f ; fd( f ) == f1 ) {
     316        // only handle IO failure for f1
     317}
     318\end{cfa}
     319Note, catching @IOFailure@, checking for @f1@ in the handler, and reraising the
     320exception if not @f1@ is different because the reraise does not examine any of
     321remaining handlers in the current try statement.
     322
     323\section{Reraise}
     324\label{s:Reraise}
     325Within the handler block or functions called from the handler block, it is
     326possible to reraise the most recently caught exception with @throw@ or
     327@throwResume@, respective.
     328\begin{cfa}
     329catch( ... ) {
     330        ... throw; // rethrow
     331} catchResume( ... ) {
     332        ... throwResume; // reresume
     333}
     334\end{cfa}
     335The only difference between a raise and a reraise is that reraise does not
     336create a new exception; instead it continues using the current exception, \ie
     337no allocation and copy. However the default handler is still set to the one
     338visible at the raise point, and hence, for termination could refer to data that
     339is part of an unwound stack frame. To prevent this problem, a new default
     340handler is generated that does a program-level abort.
     341
    211342
    212343\section{Finally Clauses}
    213 
    214 A \codeCFA{finally} clause may be placed at the end of a try statement after
    215 all the handler clauses. In the simply case, with no handlers, it looks like
    216 this:
    217 
    218 \begin{lstlisting}
    219 try {
    220     TRY_BLOCK
     344A @finally@ clause may be placed at the end of a @try@ statement.
     345\begin{cfa}
     346try {
     347        GUARDED_BLOCK
     348} ...   // any number or kind of handler clauses
    221349} finally {
    222     FINAL_STATEMENTS
    223 }
    224 \end{lstlisting}
    225 
    226 Any number of termination handlers and resumption handlers may proceed the
    227 finally clause.
    228 
    229 The FINAL\_STATEMENTS, the finally block, are executed whenever the try
    230 statement is removed from the stack. This includes: the TRY\_BLOCK finishes
    231 executing, a termination exception finishes executing and the stack unwinds.
    232 
    233 Execution of the finally block should finish by letting control run off
    234 the end of the block. This is because after the finally block is complete
    235 control will continue to where ever it would if the finally clause was not
    236 present.
    237 
    238 Because of this local control flow out of the finally block is forbidden.
    239 The compiler rejects uses of \codeCFA{break}, \codeCFA{continue},
    240 \codeCFA{fallthru} and \codeCFA{return} that would cause control to leave
    241 the finally block. Other ways to leave the finally block - such as a long
    242 jump or termination - are much harder to check, at best requiring additional
    243 runtime overhead, and so are merely discouraged.
     350        FINALLY_BLOCK
     351}
     352\end{cfa}
     353The @FINALLY_BLOCK@ is executed when the try statement is unwound from the
     354stack, \ie when the @GUARDED_BLOCK@ or any handler clause finishes. Hence, the
     355finally block is always executed.
     356
     357Execution of the finally block should always finish, meaning control runs off
     358the end of the block. This requirement ensures always continues as if the
     359finally clause is not present, \ie finally is for cleanup not changing control
     360flow.  Because of this requirement, local control flow out of the finally block
     361is forbidden.  The compiler precludes any @break@, @continue@, @fallthru@ or
     362@return@ that causes control to leave the finally block. Other ways to leave
     363the finally block, such as a long jump or termination are much harder to check,
     364and at best requiring additional run-time overhead, and so are discouraged.
    244365
    245366\section{Cancellation}
    246 
    247 Cancellation can be thought of as a stack-level abort or as an uncatchable
    248 termination. It unwinds the entirety of the current exception and if possible
    249 passes an exception to a different stack as a message.
    250 
    251 There is no special statement for starting a cancellation, instead you call
    252 the standard libary function \codeCFA{cancel\_stack} which takes an exception.
    253 Unlike in a throw this exception is not used in control flow but is just there
    254 to pass information about why the cancellation happened.
    255 
    256 The handler is decided entirely by which stack is being cancelled. There are
    257 three handlers that apply to three different groups of stacks:
    258 \begin{itemize}
    259 \item Main Stack:
    260 The main stack is the one on which the program main is called at the beginning
    261 of your program. It is also the only stack you have without the libcfathreads.
    262 
    263 Because of this there is no other stack ``above" (or possibly at all) for main
    264 to notify when a cancellation occurs. So after the stack is unwound we do a
    265 program level abort.
    266 
    267 \item Thread Stack:
    268 Thread stacks are those created \codeCFA{thread} or otherwise satify the
    269 \codeCFA{is\_thread} trait.
    270 
    271 Threads only have two structural points of communication that must happen,
    272 start and join. As the thread must be running to preform a cancellation it
    273 will be after start and before join, so join is one cancellation uses.
    274 
    275 After the stack is unwound the thread will halt as if had completed normally
    276 and wait for another thread to join with it. The other thread, when it joins,
    277 checks for a cancellation. If so it will throw the resumption exception
    278 \codeCFA{ThreadCancelled}.
    279 
    280 There is a difference here in how explicate joins (with the \codeCFA{join}
    281 function) and implicate joins (from a destructor call). Explicate joins will
    282 take the default handler (\codeCFA{defaultResumptionHandler}) from the context
    283 and use like a regular through does if the exception is not caught. The
    284 implicate join does a program abort instead.
    285 
    286 This is for safety. One of the big problems in exceptions is you cannot handle
    287 two terminations or cancellations on the same stack as either can destroy the
    288 context required for the other. This can happen with join but as the
    289 destructors will always be run when the stack is being unwound and one
    290 termination/cancellation is already active. Also since they are implicite they
    291 are easier to forget about.
    292 
    293 \item Coroutine Stack:
    294 Coroutine stacks are those created with \codeCFA{coroutine} or otherwise
    295 satify the \codeCFA{is\_coroutine} trait.
    296 
    297 A coroutine knows of two other coroutines, its starter and its last resumer.
    298 The last resumer is ``closer" so that is the one notified.
    299 
    300 After the stack is unwound control goes to the last resumer.
    301 Resume will resume throw a \codeCFA{CoroutineCancelled} exception, which is
    302 polymorphic over the coroutine type and has a pointer to the coroutine being
    303 cancelled and the cancelling exception. The resume function also has an
    304 assertion that the \codeCFA{defaultResumptionHandler} for the exception. So it
    305 will use the default handler like a regular throw.
    306 
    307 \end{itemize}
     367Cancellation is a stack-level abort, which can be thought of as as an
     368uncatchable termination. It unwinds the entirety of the current stack, and if
     369possible forwards the cancellation exception to a different stack.
     370
     371There is no special statement for starting a cancellation; instead the standard
     372library function @cancel_stack@ is called passing an exception.  Unlike a
     373raise, this exception is not used in matching only to pass information about
     374the cause of the cancellation.
     375
     376Handling of a cancellation depends on which stack is being cancelled.
     377\begin{description}
     378\item[Main Stack:]
     379
     380The main stack is the one used by the program main at the start of execution,
     381and is the only stack in a sequential program.  Hence, when cancellation is
     382forwarded to the main stack, there is no other forwarding stack, so after the
     383stack is unwound, there is a program-level abort.
     384
     385\item[Thread Stack:]
     386A thread stack is created for a @thread@ object or object that satisfies the
     387@is_thread@ trait.  A thread only has two points of communication that must
     388happen: start and join. As the thread must be running to perform a
     389cancellation, it must occur after start and before join, so join is a
     390cancellation point.  After the stack is unwound, the thread halts and waits for
     391another thread to join with it. The joining thread, checks for a cancellation,
     392and if present, resumes exception @ThreadCancelled@.
     393
     394There is a subtle difference between the explicit join (@join@ function) and
     395implicit join (from a destructor call). The explicit join takes the default
     396handler (@defaultResumptionHandler@) from its calling context, which is used if
     397the exception is not caught. The implicit join does a program abort instead.
     398
     399This semantics is for safety. One difficult problem for any exception system is
     400defining semantics when an exception is raised during an exception search:
     401which exception has priority, the original or new exception? No matter which
     402exception is selected, it is possible for the selected one to disrupt or
     403destroy the context required for the other. {\color{blue} PAB: I do not
     404understand the following sentences.} This loss of information can happen with
     405join but as the thread destructor is always run when the stack is being unwound
     406and one termination/cancellation is already active. Also since they are
     407implicit they are easier to forget about.
     408
     409\item[Coroutine Stack:] A coroutine stack is created for a @coroutine@ object
     410or object that satisfies the @is_coroutine@ trait.  A coroutine only knows of
     411two other coroutines, its starter and its last resumer.  The last resumer has
     412the tightest coupling to the coroutine it activated.  Hence, cancellation of
     413the active coroutine is forwarded to the last resumer after the stack is
     414unwound, as the last resumer has the most precise knowledge about the current
     415execution. When the resumer restarts, it resumes exception
     416@CoroutineCancelled@, which is polymorphic over the coroutine type and has a
     417pointer to the cancelled coroutine.
     418
     419The resume function also has an assertion that the @defaultResumptionHandler@
     420for the exception. So it will use the default handler like a regular throw.
     421\end{description}
  • doc/theses/andrew_beach_MMath/future.tex

    rb6a8b31 rd95969a  
    88parts of the exception system that use the current version.
    99
    10 For instance a full virtual system would probably allow for several
    11 improvements to the exception traits. Although they do currently work they
    12 could be made easier to use by making the virtual table type implitate in the
    13 trait (which would remove the need for those wrapper marcos) or allowing
    14 for assertions that give the layout of a virtual table for safety.
     10There are several improvements to the virtual system that would improve
     11the exception traits. The biggest one is an assertion that checks that one
     12virtual type is a child of another virtual type. This would capture many of
     13the requirements much more precisely.
     14
     15The full virtual system might also include other improvement like associated
     16types. This is a proposed feature that would allow traits to refer to types
     17not listed in their header. This would allow the exception traits to not
     18refer to the virtual table type explicatly which would remove the need for
     19the interface macros.
    1520
    1621\section{Additional Throws}
    17 Several other kinds of throws, beyond the termination throw (\codeCFA{throw}),
    18 the resumption throw (\codeCFA{throwResume}) and the re-throws, were considered.
     22Several other kinds of throws, beyond the termination throw (@throw@),
     23the resumption throw (@throwResume@) and the re-throws, were considered.
    1924None were as useful as the core throws but they would likely be worth
    2025revising.
     
    6570
    6671Also new techniques to skip previously searched parts of the stack will have
    67 to be developed.
     72to be developed. The recursive resume problem still remains and ideally the
     73same pattern of ignoring sections of the stack.
    6874
    69 \section{Support for More Platforms}
    70 Termination is not portable because it is implemented with inline assembly.
    71 Those sections will have to be rewritten to support different architectures
     75\section{Signal Exceptions}
     76Exception Handling: Issues and a Proposed Notation suggests there are three
     77types of exceptions: escape, notify and signal.
     78Escape exceptions are our termination exceptions, notify exceptions are
     79resumption exceptions and that leaves signal exception unimplemented.
    7280
    73 \section{Quality-of-Life Improvements}
    74 Finally come various improvements to the usability of \CFA. Most of these
    75 would just require time. Time that would not lead to interesting research so
    76 it has been left aside for now. A few examples are included here but there
    77 are more:
     81Signal exceptions allow either behaviour, that is after the exception is
     82handled control can either return to the throw or from where the handler is
     83defined.
     84
     85The design should be rexamined and be updated for \CFA. A very direct
     86translation would perhaps have a new throw and catch pair and a statement
     87(or statements) could be used to decide if the handler returns to the throw
     88or continues where it is, but there are other options.
     89
     90For instance resumption could be extended to cover this use by allowing
     91local control flow out of it. This would require an unwind as part of the
     92transition as there are stack frames that have to be removed.
     93This would mean there is no notify like throw but because \CFA does not have
     94exception signatures a termination can be thrown from any resumption handler
     95already so there are already ways one could try to do this in existing \CFA.
     96
     97% Maybe talk about the escape; and escape CONTROL_STMT; statements or how
     98% if we could choose if _Unwind_Resume proceeded to the clean-up stage this
     99% would be much easier to implement.
     100
     101\section{Language Improvements}
     102There is also a lot of work that are not follow ups to this work in terms of
     103research, some have no interesting research to be done at all, but would
     104improve \CFA as a programming language. The full list of these would
     105naturally be quite extensive but here are a few examples that involve
     106exceptions:
    78107
    79108\begin{itemize}
     109\item The implementation of termination is not portable because it includes
     110some assembly statements. These sections will have to be re-written to so
     111\CFA has full support on more machines.
    80112\item Allowing exception handler to bind the exception to a reference instead
    81113of a pointer. This should actually result in no change in behaviour so there
    82114is no reason not to allow it. It is however a small improvement; giving a bit
    83115of flexibility to the user in what style they want to use.
    84 \item Enabling local control flow (by \codeCFA{break}, \codeCFA{return} and
     116\item Enabling local control flow (by @break@, @return@ and
    85117similar statements) out of a termination handler. The current set-up makes
    86118this very difficult but the catch function that runs the handler after it has
     
    88120much easier. (To do the same for try blocks would probably wait for zero-cost
    89121exceptions, which would allow the try block to be inlined as well.)
    90 \item Enabling local control flow out of a resumption handler. This would be
    91 a weighty operation, causing a stack unwind like a termination, so there might
    92 be a different statement or a statement modifier to make sure the user does
    93 this purposefully.
    94 
    95 However this would require the more complex system as they cannot be inlined
    96 into the original function as they can be run at a different place on the
    97 stack. So instead the unwinding will have to carry with it information on
    98 which one of these points to continue at and possibly also the return value
    99 for the function if a \codeCFA{return} statement was used.
    100122\end{itemize}
  • doc/theses/andrew_beach_MMath/implement.tex

    rb6a8b31 rd95969a  
    99
    1010All of this is accessed through a field inserted at the beginning of every
    11 virtual type. Currently it is called \codeC{virtual_table} but it is not
     11virtual type. Currently it is called @virtual_table@ but it is not
    1212ment to be accessed by the user. This field is a pointer to the type's
    1313virtual table instance. It is assigned once during the object's construction
     
    4040using that to calculate the mangled name of the parent's virtual table type.
    4141There are two special fields that are included like normal fields but have
    42 special initialization rules: the \codeC{size} field is the type's size and is
    43 initialized with a sizeof expression, the \codeC{align} field is the type's
     42special initialization rules: the @size@ field is the type's size and is
     43initialized with a sizeof expression, the @align@ field is the type's
    4444alignment and uses an alignof expression. The remaining fields are resolved
    4545to a name matching the field's name and type using the normal visibility
     
    5656The declarations include the virtual type definition and forward declarations
    5757of the virtual table instance, constructor, message function and
    58 \codeCFA{get_exception_vtable}. The definition includes the storage and
     58@get_exception_vtable@. The definition includes the storage and
    5959initialization of the virtual table instance and the bodies of the three
    6060functions.
     
    6565from the per-instance information. The virtual table type and most of the
    6666functions are polymorphic so they are all part of the core. The virtual table
    67 instance and the \codeCFA{get_exception_vtable} function.
    68 
    69 Coroutines and threads need instances of \codeCFA{CoroutineCancelled} and
    70 \codeCFA{ThreadCancelled} respectively to use all of their functionality.
    71 When a new data type is declared with \codeCFA{coroutine} or \codeCFA{thread}
     67instance and the @get_exception_vtable@ function.
     68
     69Coroutines and threads need instances of @CoroutineCancelled@ and
     70@ThreadCancelled@ respectively to use all of their functionality.
     71When a new data type is declared with @coroutine@ or @thread@
    7272the forward declaration for the instance is created as well. The definition
    7373of the virtual table is created at the definition of the main function.
     
    7979function.
    8080
    81 The function is \codeC{__cfa__virtual_cast} and it is implemented in the
     81The function is @__cfa__virtual_cast@ and it is implemented in the
    8282standard library. It takes a pointer to the target type's virtual table and
    8383the object pointer being cast. The function is very simple, getting the
     
    8787
    8888For the generated code a forward decaration of the virtual works as follows.
    89 There is a forward declaration of \codeC{__cfa__virtual_cast} in every cfa
     89There is a forward declaration of @__cfa__virtual_cast@ in every cfa
    9090file so it can just be used. The object argument is the expression being cast
    9191so that is just placed in the argument list.
     
    110110often across functions.
    111111
    112 At a very basic level this can be done with \codeC{setjmp} \& \codeC{longjmp}
     112At a very basic level this can be done with @setjmp@ \& @longjmp@
    113113which simply move the top of the stack, discarding everything on the stack
    114114above a certain point. However this ignores all the clean-up code that should
     
    118118both of these problems.
    119119
    120 Libunwind, provided in \texttt{unwind.h} on most platorms, is a C library
     120Libunwind, provided in @unwind.h@ on most platorms, is a C library
    121121that provides \CPP style stack unwinding. Its operation is divided into two
    122122phases. The search phase -- phase 1 -- is used to scan the stack and decide
     
    142142
    143143GCC will generate an LSDA and attach its personality function with the
    144 \texttt{-fexceptions} flag. However this only handles the cleanup attribute.
     144@-fexceptions@ flag. However this only handles the cleanup attribute.
    145145This attribute is used on a variable and specifies a function that should be
    146146run when the variable goes out of scope. The function is passed a pointer to
     
    165165messages for special cases (some of which should never be used by the
    166166personality function) and error codes but unless otherwise noted the
    167 personality function should always return \codeC{_URC_CONTINUE_UNWIND}.
    168 
    169 The \codeC{version} argument is the verson of the implementation that is
     167personality function should always return @_URC_CONTINUE_UNWIND@.
     168
     169The @version@ argument is the verson of the implementation that is
    170170calling the personality function. At this point it appears to always be 1 and
    171171it will likely stay that way until a new version of the API is updated.
    172172
    173 The \codeC{action} argument is set of flags that tell the personality
     173The @action@ argument is set of flags that tell the personality
    174174function when it is being called and what it must do on this invocation.
    175175The flags are as follows:
    176176\begin{itemize}
    177 \item\codeC{_UA_SEARCH_PHASE}: This flag is set whenever the personality
     177\item@_UA_SEARCH_PHASE@: This flag is set whenever the personality
    178178function is called during the search phase. The personality function should
    179179decide if unwinding will stop in this function or not. If it does then the
    180 personality function should return \codeC{_URC_HANDLER_FOUND}.
    181 \item\codeC{_UA_CLEANUP_PHASE}: This flag is set whenever the personality
     180personality function should return @_URC_HANDLER_FOUND@.
     181\item@_UA_CLEANUP_PHASE@: This flag is set whenever the personality
    182182function is called during the cleanup phase. If no other flags are set this
    183183means the entire frame will be unwound and all cleanup code should be run.
    184 \item\codeC{_UA_HANDLER_FRAME}: This flag is set during the cleanup phase
     184\item@_UA_HANDLER_FRAME@: This flag is set during the cleanup phase
    185185on the function frame that found the handler. The personality function must
    186186prepare to return to normal code execution and return
    187 \codeC{_URC_INSTALL_CONTEXT}.
    188 \item\codeC{_UA_FORCE_UNWIND}: This flag is set if the personality function
     187@_URC_INSTALL_CONTEXT@.
     188\item@_UA_FORCE_UNWIND@: This flag is set if the personality function
    189189is called through a forced unwind call. Forced unwind only performs the
    190190cleanup phase and uses a different means to decide when to stop. See its
     
    192192\end{itemize}
    193193
    194 The \codeC{exception_class} argument is a copy of the \codeC{exception}'s
    195 \codeC{exception_class} field.
    196 
    197 The \codeC{exception} argument is a pointer to the user provided storage
     194The @exception_class@ argument is a copy of the @exception@'s
     195@exception_class@ field.
     196
     197The @exception@ argument is a pointer to the user provided storage
    198198object. It has two public fields, the exception class which is actually just
    199199a number that identifies the exception handling mechanism that created it and
     
    201201exception needs to
    202202
    203 The \codeC{context} argument is a pointer to an opaque type. This is passed
     203The @context@ argument is a pointer to an opaque type. This is passed
    204204to the many helper functions that can be called inside the personality
    205205function.
     
    218218functions traversing the stack new-to-old until a function finds a handler or
    219219the end of the stack is reached. In the latter case raise exception will
    220 return with \codeC{_URC_END_OF_STACK}.
     220return with @_URC_END_OF_STACK@.
    221221
    222222Once a handler has been found raise exception continues onto the the cleanup
     
    227227
    228228If an error is encountered raise exception will return either
    229 \codeC{_URC_FATAL_PHASE1_ERROR} or \codeC{_URC_FATAL_PHASE2_ERROR} depending
     229@_URC_FATAL_PHASE1_ERROR@ or @_URC_FATAL_PHASE2_ERROR@ depending
    230230on when the error occured.
    231231
     
    259259been unwound.
    260260
    261 Each time it is called the stop function should return \codeC{_URC_NO_REASON}
     261Each time it is called the stop function should return @_URC_NO_REASON@
    262262or transfer control directly to other code outside of libunwind. The
    263263framework does not provide any assistance here.
    264264
    265265Its arguments are the same as the paired personality function.
    266 The actions \codeC{_UA_CLEANUP_PHASE} and \codeC{_UA_FORCE_UNWIND} are always
     266The actions @_UA_CLEANUP_PHASE@ and @_UA_FORCE_UNWIND@ are always
    267267set when it is called. By the official standard that is all but both GCC and
    268268Clang add an extra action on the last call at the end of the stack:
    269 \codeC{_UA_END_OF_STACK}.
     269@_UA_END_OF_STACK@.
    270270
    271271\section{Exception Context}
     
    280280Each stack has its own exception context. In a purely sequental program, using
    281281only core Cforall, there is only one stack and the context is global. However
    282 if the library \texttt{libcfathread} is linked then there can be multiple
     282if the library @libcfathread@ is linked then there can be multiple
    283283stacks so they will each need their own.
    284284
    285285To handle this code always gets the exception context from the function
    286 \codeC{this_exception_context}. The main exception handling code is in
    287 \texttt{libcfa} and that library also defines the function as a weak symbol
    288 so it acts as a default. Meanwhile in \texttt{libcfathread} the function is
     286@this_exception_context@. The main exception handling code is in
     287@libcfa@ and that library also defines the function as a weak symbol
     288so it acts as a default. Meanwhile in @libcfathread@ the function is
    289289defined as a strong symbol that replaces it when the libraries are linked
    290290together.
    291291
    292 The version of the function defined in \texttt{libcfa} is very simple. It
     292The version of the function defined in @libcfa@ is very simple. It
    293293returns a pointer to a global static variable. With only one stack this
    294294global instance is associated with the only stack.
    295295
    296 The version of the function defined in \texttt{libcfathread} has to handle
     296The version of the function defined in @libcfathread@ has to handle
    297297more as there are multiple stacks. The exception context is included as
    298298part of the per-stack data stored as part of coroutines. In the cold data
    299299section, stored at the base of each stack, is the exception context for that
    300 stack. The \codeC{this_exception_context} uses the concurrency library to get
     300stack. The @this_exception_context@ uses the concurrency library to get
    301301the current coroutine and through it the cold data section and the exception
    302302context.
     
    323323to store the exception. Macros with pointer arthritic and type cast are
    324324used to move between the components or go from the embedded
    325 \codeC{_Unwind_Exception} to the entire node.
     325@_Unwind_Exception@ to the entire node.
    326326
    327327All of these nodes are strung together in a linked list. One linked list per
     
    347347C which is what the \CFA compiler outputs so a work-around is used.
    348348
    349 This work around is a function called \codeC{__cfaehm_try_terminate} in the
     349This work around is a function called @__cfaehm_try_terminate@ in the
    350350standard library. The contents of a try block and the termination handlers
    351351are converted into functions. These are then passed to the try terminate
     
    385385
    386386These nested functions and all other functions besides
    387 \codeC{__cfaehm_try_terminate} in \CFA use the GCC personality function and
    388 the \texttt{-fexceptions} flag to generate the LSDA. This allows destructors
     387@__cfaehm_try_terminate@ in \CFA use the GCC personality function and
     388the @-fexceptions@ flag to generate the LSDA. This allows destructors
    389389to be implemented with the cleanup attribute.
    390390
     
    401401
    402402The handler function does both the matching and catching. It tries each
    403 the condition of \codeCFA{catchResume} in order, top-to-bottom and until it
     403the condition of @catchResume@ in order, top-to-bottom and until it
    404404finds a handler that matches. If no handler matches then the function returns
    405405false. Otherwise the matching handler is run, if it completes successfully
    406 the function returns true. Rethrows, through the \codeCFA{throwResume;}
     406the function returns true. Rethrows, through the @throwResume;@
    407407statement, cause the function to return true.
     408
     409% Recursive Resumption Stuff:
     410Blocking out part of the stack is accomplished by updating the front of the
     411list as the search continues. Before the handler at a node is called the head
     412of the list is updated to the next node of the current node. After the search
     413is complete, successful or not, the head of the list is reset.
     414
     415This means the current handler and every handler that has already been
     416checked are not on the list while a handler is run. If a resumption is thrown
     417during the handling of another resumption the active handlers and all the
     418other handler checked up to this point will not be checked again.
     419
     420This structure also supports new handler added while the resumption is being
     421handled. These are added to the front of the list, pointing back along the
     422stack -- the first one will point over all the checked handlers -- and the
     423ordering is maintained.
    408424
    409425\subsection{Libunwind Compatibility}
     
    438454
    439455Cancellation also uses libunwind to do its stack traversal and unwinding,
    440 however it uses a different primary function \codeC{_Unwind_ForcedUnwind}.
     456however it uses a different primary function @_Unwind_ForcedUnwind@.
    441457Details of its interface can be found in the unwind section.
    442458
  • doc/theses/andrew_beach_MMath/unwinding.tex

    rb6a8b31 rd95969a  
    1 \chapter{Unwinding in \CFA}
     1\chapter{\texorpdfstring{Unwinding in \CFA}{Unwinding in Cforall}}
    22
    33Stack unwinding is the process of removing things from the stack. Within
     
    1010Even this is fairly simple if nothing needs to happen when the stack unwinds.
    1111Traditional C can unwind the stack by saving and restoring state (with
    12 \codeC{setjmp} \& \codeC{longjmp}). However many languages define actions that
     12@setjmp@ \& @longjmp@). However many languages define actions that
    1313have to be taken when something is removed from the stack, such as running
    14 a variable's destructor or a \codeCFA{try} statement's \codeCFA{finally}
     14a variable's destructor or a @try@ statement's @finally@
    1515clause. Handling this requires walking the stack going through each stack
    1616frame.
     
    2929
    3030\CFA uses two primary functions in libunwind to create most of its
    31 exceptional control-flow: \codeC{_Unwind_RaiseException} and
    32 \codeC{_Unwind_ForcedUnwind}.
     31exceptional control-flow: @_Unwind_RaiseException@ and
     32@_Unwind_ForcedUnwind@.
    3333Their operation is divided into two phases: search and clean-up. The search
    3434phase -- phase 1 -- is used to scan the stack but not unwinding it. The
     
    4444A personality function performs three tasks, although not all have to be
    4545present. The tasks performed are decided by the actions provided.
    46 \codeC{_Unwind_Action} is a bitmask of possible actions and an argument of
     46@_Unwind_Action@ is a bitmask of possible actions and an argument of
    4747this type is passed into the personality function.
    4848\begin{itemize}
    49 \item\codeC{_UA_SEARCH_PHASE} is passed in search phase and tells the
     49\item@_UA_SEARCH_PHASE@ is passed in search phase and tells the
    5050personality function to check for handlers. If there is a handler in this
    5151stack frame, as defined by the language, the personality function should
    52 return \codeC{_URC_HANDLER_FOUND}. Otherwise it should return
    53 \codeC{_URC_CONTINUE_UNWIND}.
    54 \item\codeC{_UA_CLEANUP_PHASE} is passed in during the clean-up phase and
     52return @_URC_HANDLER_FOUND@. Otherwise it should return
     53@_URC_CONTINUE_UNWIND@.
     54\item@_UA_CLEANUP_PHASE@ is passed in during the clean-up phase and
    5555means part or all of the stack frame is removed. The personality function
    5656should do whatever clean-up the language defines
    5757(such as running destructors/finalizers) and then generally returns
    58 \codeC{_URC_CONTINUE_UNWIND}.
    59 \item\codeC{_UA_HANDLER_FRAME} means the personality function must install
     58@_URC_CONTINUE_UNWIND@.
     59\item@_UA_HANDLER_FRAME@ means the personality function must install
    6060a handler. It is also passed in during the clean-up phase and is in addition
    6161to the clean-up action. libunwind provides several helpers for the personality
    6262function here. Once it is done, the personality function must return
    63 \codeC{_URC_INSTALL_CONTEXT}.
     63@_URC_INSTALL_CONTEXT@.
    6464\end{itemize}
    6565The personality function is given a number of other arguments. Some are for
    66 compatability and there is the \codeC{struct _Unwind_Context} pointer which
     66compatability and there is the @struct _Unwind_Context@ pointer which
    6767passed to many helpers to get information about the current stack frame.
    6868
     
    7272raise-exception but with some extras.
    7373The first it passes in an extra action to the personality function on each
    74 stack frame, \codeC{_UA_FORCE_UNWIND}, which means a handler cannot be
     74stack frame, @_UA_FORCE_UNWIND@, which means a handler cannot be
    7575installed.
    7676
     
    8383stack frames have been removed. By the standard API this is marked by setting
    8484the stack pointer inside the context passed to the stop function. However both
    85 GCC and Clang add an extra action for this case \codeC{_UA_END_OF_STACK}.
     85GCC and Clang add an extra action for this case @_UA_END_OF_STACK@.
    8686
    8787Each time function the stop function is called it can do one or two things.
    88 When it is not the end of the stack it can return \codeC{_URC_NO_REASON} to
     88When it is not the end of the stack it can return @_URC_NO_REASON@ to
    8989continue unwinding.
    9090% Is there a reason that NO_REASON is used instead of CONTINUE_UNWIND?
     
    9393are provided to do it.
    9494
    95 \section{\CFA Implementation}
     95\section{\texorpdfstring{\CFA Implementation}{Cforall Implementation}}
    9696
    9797To use libunwind, \CFA provides several wrappers, its own storage,
     
    113113
    114114The stop function is very simple. It checks the end of stack flag to see if
    115 it is finished unwinding. If so, it calls \codeC{exit} to end the process,
     115it is finished unwinding. If so, it calls @exit@ to end the process,
    116116otherwise it returns with no-reason to continue unwinding.
    117117% Yeah, this is going to have to change.
     
    128128location of the instruction pointer and stack layout, which varies with
    129129compiler and optimization levels. So for frames where there are only
    130 destructors, GCC's attribute cleanup with the \texttt{-fexception} flag is
     130destructors, GCC's attribute cleanup with the @-fexception@ flag is
    131131sufficient to handle unwinding.
    132132
    133133The only functions that require more than that are those that contain
    134 \codeCFA{try} statements. A \codeCFA{try} statement has a \codeCFA{try}
    135 clause, some number of \codeCFA{catch} clauses and \codeCFA{catchResume}
    136 clauses and may have a \codeCFA{finally} clause. Of these only \codeCFA{try}
    137 statements with \codeCFA{catch} clauses need to be transformed and only they
    138 and the \codeCFA{try} clause are involved.
     134@try@ statements. A @try@ statement has a @try@
     135clause, some number of @catch@ clauses and @catchResume@
     136clauses and may have a @finally@ clause. Of these only @try@
     137statements with @catch@ clauses need to be transformed and only they
     138and the @try@ clause are involved.
    139139
    140 The \codeCFA{try} statement is converted into a series of closures which can
     140The @try@ statement is converted into a series of closures which can
    141141access other parts of the function according to scoping rules but can be
    142 passed around. The \codeCFA{try} clause is converted into the try functions,
    143 almost entirely unchanged. The \codeCFA{catch} clauses are converted into two
     142passed around. The @try@ clause is converted into the try functions,
     143almost entirely unchanged. The @catch@ clauses are converted into two
    144144functions; the match function and the catch function.
    145145
     
    153153runs the handler's body.
    154154
    155 These three functions are passed to \codeC{try_terminate}. This is an
     155These three functions are passed to @try_terminate@. This is an
    156156% Maybe I shouldn't quote that, it isn't its actual name.
    157157internal hand-written function that has its own personality function and
     
    167167handler was found in this frame. If it was then the personality function
    168168installs the handler, which is setting the instruction pointer in
    169 \codeC{try_terminate} to an otherwise unused section that calls the catch
     169@try_terminate@ to an otherwise unused section that calls the catch
    170170function, passing it the current exception and handler index.
    171 \codeC{try_terminate} returns as soon as the catch function returns.
     171@try_terminate@ returns as soon as the catch function returns.
    172172
    173173At this point control has returned to normal control flow.
  • doc/theses/fangren_yu_COOP_F20/Report.tex

    rb6a8b31 rd95969a  
    1717\usepackage[usenames]{color}
    1818\input{common}                                          % common CFA document macros
    19 \usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref}
     19\usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref}
    2020\usepackage{breakurl}
    2121\urlstyle{sf}
     
    7676\renewcommand{\subsectionmark}[1]{\markboth{\thesubsection\quad #1}{\thesubsection\quad #1}}
    7777\pagenumbering{roman}
    78 \linenumbers                                            % comment out to turn off line numbering
     78%\linenumbers                                            % comment out to turn off line numbering
    7979
    8080\maketitle
    8181\pdfbookmark[1]{Contents}{section}
    82 \tableofcontents
    83 
    84 \clearpage
     82
    8583\thispagestyle{plain}
    8684\pagenumbering{arabic}
    8785
    8886\begin{abstract}
     87\CFA is an evolutionary, non-object-oriented extension of the C programming language, featuring a parametric type-system, and is currently under active development. The reference compiler for the \CFA language, @cfa-cc@, has some of its major components dated back to the early 2000s, which are based on inefficient data structures and algorithms. This report introduces improvements targeting the expression resolution algorithm, suggested by a recent prototype experiment on a simplified model, which are implemented in @cfa-cc@ to support the full \CFA language. These optimizations speed up the compiler by a factor of 20 across the existing \CFA codebase, bringing the compilation time of a mid-sized \CFA source file down to the 10-second level. A few problem cases derived from realistic code examples are analyzed in detail, with proposed solutions. This work is a critical step in the \CFA project development to achieve its eventual goal of being used alongside C for large software systems.
    8988\end{abstract}
    9089
     90\clearpage
     91\section*{Acknowledgements}
     92\begin{sloppypar}
     93I would like to thank everyone in the \CFA team for their contribution towards this project. Programming language design and development is a tough subject and requires a lot of teamwork. Without the collaborative efforts from the team, this project could not have been a success. Specifically, I would like to thank Andrew Beach for introducing me to the \CFA codebase, Thierry Delisle for maintaining the test and build automation framework, Michael Brooks for providing example programs of various experimental language and type system features, and most importantly, Professor Martin Karsten for recommending me to the \CFA team, and my supervisor, Professor Peter Buhr for encouraging me to explore deeply into intricate compiler algorithms. Finally, I gratefully acknowledge the help from Aaron Moss, former graduate from the team and the author of the precedent thesis work, to participate in the \CFA team's virtual conferences and email correspondence, and provide many critical arguments and suggestions. 2020 had been an unusually challenging year for everyone and we managed to keep a steady pace.
     94\end{sloppypar}
     95
     96\clearpage
     97\tableofcontents
     98
     99\clearpage
    91100\section{Introduction}
    92101
    93 \section{Completed work}
     102\CFA language, developed by the Programming Language Group at the University of Waterloo, has a long history, with the initial language design in 1992 by Glen Ditchfield~\cite{Ditchfield92} and the first proof-of-concept compiler built in 2003 by Richard Bilson~\cite{Bilson03}. Many new features have been added to the language over time, but the core of \CFA's type-system --- parametric functions introduced by the @forall@ clause (hence the name of the language) providing parametric overloading --- remains mostly unchanged.
     103
     104The current \CFA reference compiler, @cfa-cc@, is designed using the visitor pattern~\cite{vistorpattern} over an abstract syntax tree (AST), where multiple passes over the AST modify it for subsequent passes. @cfa-cc@ still includes many parts taken directly from the original Bilson implementation, which served as the starting point for this enhancement work to the type system. Unfortunately, the prior implementation did not provide the efficiency required for the language to be practical: a \CFA source file of approximately 1000 lines of code can take a multiple minutes to compile. The cause of the problem is that the old compiler used inefficient data structures and algorithms for expression resolution, which involved significant copying and redundant work.
     105
     106This report presents a series of optimizations to the performance-critical parts of the resolver, with a major rework of the compiler data-structures using a functional-programming approach to reduce memory complexity. The improvements were suggested by running the compiler builds with a performance profiler against the \CFA standard-library source-code and a test suite to find the most underperforming components in the compiler algorithm.
     107
     108The \CFA team endorses a pragmatic philosophy that focuses on practical implications of language design and implementation rather than theoretical limits. In particular, the compiler is designed to be expressive with respect to code reuse while maintaining type safety, but compromise theoretical soundness in extreme corner cases. However, when these corner cases do appear in actual usage, they need to be thoroughly investigated. A case-by-case analysis is presented for several of these corner cases, some of which point to certain weaknesses in the language design with solutions proposed based on experimental results.
     109
     110\section{AST restructuring}
    94111
    95112\subsection{Memory model with sharing}
    96113
    97 A major rework of the abstract syntax tree (AST) data structure in the compiler is completed as the first step of the project. The majority of work were documented in the reference manual of the compiler~\cite{cfa-cc}. To summarize:
    98 \begin{itemize}
    99 \item
    100 AST nodes (and therefore subtrees) can be shared without copying when reused.
    101 \item
    102 Modifications apply the functional programming principle, making copies for local changes without affecting the original data shared by other owners. In-place mutations are permitted as a special case when sharing does not happen. The logic is implemented by reference counting.
    103 \item
    104 Memory allocation and freeing are performed automatically using smart pointers.
    105 \end{itemize}
    106 The resolver algorithm designed for overload resolution naturally introduces a significant amount of reused intermediate representations, especially in the following two places:
    107 \begin{itemize}
    108 \item
    109 Function overload candidates are computed by combining the argument candidates bottom-up, with many of them being a common term. For example, if $n$ overloads of a function @f@ all take an integer for the first parameter but different types for the second (@f( int, int )@, @f( int, double )@, etc.) the first term is reused $n$ times for each of the generated candidate expressions. This effect is particularly bad for deep expression trees.
    110 \item
    111 In the unification algorithm and candidate elimination step, actual types are obtained by substituting the type parameters by their bindings. Let $n$ be the complexity (\ie number of nodes in representation) of the original type, $m$ be the complexity of bound type for parameters, and $k$ be the number of occurrences of type parameters in the original type. If everything needs to be deep-copied, the substitution step takes $O(n+mk)$ time and memory, while using shared nodes it is reduced to $O(n)$ time and $O(k)$ memory.
    112 \end{itemize}
    113 One of the worst examples for the old compiler is a long chain of I/O operations
    114 \begin{cfa}
    115 sout | 1 | 2 | 3 | 4 | ...
    116 \end{cfa}
    117 The pipe operator is overloaded by \CFA I/O library for every primitive type in C language, as well as I/O manipulators defined by the library. In total there are around 50 overloads for the output stream operation. On resolving the $n$-th pipe operator in the sequence, the first term, which is the result of sub-expression containing $n-1$ pipe operators, is reused to resolve every overload. Therefore at least $O(n^2)$ copies of expression nodes are made during resolution, not even counting type unification cost; combined with two large factors from number of overloads of pipe operators, and that the ``output stream type'' in \CFA is a trait with 27 assertions (which adds to complexity of the pipe operator's type) this makes compiling a long output sequence extremely slow. In new AST representation only $O(n)$ copies are required and type of pipe operator is not copied at all.
    118 
    119 Reduction in space complexity is especially important, as preliminary profiling result on the old compiler build shows that over half of time spent in expression resolution are on memory allocations.
    120  
     114A major rework of the AST data-structure in the compiler was completed as the first step of the project. The majority of this work is documented in my prior report documenting the compiler reference-manual~\cite{cfa-cc}. To summarize:
     115\begin{itemize}
     116\item
     117AST nodes (and therefore subtrees) can be shared without copying.
     118\item
     119Modifications are performed using functional-programming principles, making copies for local changes without affecting the original data shared by other owners. In-place mutations are permitted as a special case when there is no sharing. The logic is implemented by reference counting.
     120\item
     121Memory allocation and freeing are performed automatically using smart pointers~\cite{smartpointers}.
     122\end{itemize}
     123
     124The resolver algorithm, designed for overload resolution, uses a significant amount of reused, and hence copying, for the intermediate representations, especially in the following two places:
     125\begin{itemize}
     126\item
     127Function overload candidates are computed by combining the argument candidates bottom-up, with many being a common term. For example, if $n$ overloads of a function @f@ all take an integer for the first parameter but different types for the second, \eg @f( int, int )@, @f( int, double )@, etc., the first term is copied $n$ times for each of the generated candidate expressions. This copying is particularly bad for deep expression trees.
     128\item
     129In the unification algorithm and candidate elimination step, actual types are obtained by substituting the type parameters by their bindings. Let $n$ be the complexity (\ie number of nodes in representation) of the original type, $m$ be the complexity of the bound type for parameters, and $k$ be the number of occurrences of type parameters in the original type. If every substitution needs to be deep-copied, these copy step takes $O(n+mk)$ time and memory, while using shared nodes it is reduced to $O(n)$ time and $O(k)$ memory.
     130\end{itemize}
     131One of the worst examples for the old compiler is a long chain of I/O operations:
     132\begin{cfa}
     133sout | 1 | 2 | 3 | 4 | ...;   // print integer constants
     134\end{cfa}
     135The pipe operator is overloaded by the \CFA I/O library for every primitive type in the C language, as well as I/O manipulators defined by the library. In total, there are around 50 overloads for the output stream operation. On resolving the $n$-th pipe operator in the sequence, the first term, which is the result of sub-expression containing $n-1$ pipe operators, is reused to resolve every overload. Therefore at least $O(n^2)$ copies of expression nodes are made during resolution, not even counting type unification cost; combined with the two large factors from number of overloads of pipe operators, and that the ``output stream type'' in \CFA is a trait with 27 assertions (which adds to complexity of the pipe operator's type) this makes compiling a long output sequence extremely slow. In the new AST representation, only $O(n)$ copies are required and the type of the pipe operator is not copied at all.
     136Reduction in space complexity is especially important, as preliminary profiling results on the old compiler build showed over half of the time spent in expression resolution is on memory allocations.
     137
     138Since the compiler codebase is large and the new memory model mostly benefits expression resolution, some of the old data structures are still kept, and a conversion pass happens before and after the general resolve phase. Rewriting every compiler module will take longer, and whether the new model is correct was unknown when this project started, therefore only the resolver is currently implemented with the new data structure.
     139
    121140
    122141\subsection{Merged resolver calls}
    123142
    124 The pre-resolve phase of compilation, inadequately called ``validate'' in the compiler source code, does more than just simple syntax validation, as it also normalizes input program. Some of them, however, requires type information on expressions and therefore needs to call the resolver before the general resolve phase. There are three notable places where the resolver is invoked:
    125 \begin{itemize}
    126 \item
    127 Attempt to generate default constructor, copy constructor and destructor for user-defined @struct@ types
    128 \item
    129 Resolve @with@ statements (the same as in Python, which introduces fields of a structure directly in scope)
     143The pre-resolve phase of compilation, inappropriately called ``validate'' in the compiler source code, has a number of passes that do more than simple syntax and semantic validation; some passes also normalizes the input program. A few of these passes require type information for expressions, and therefore, need to call the resolver before the general resolve phase. There are three notable places where the resolver is invoked:
     144\begin{itemize}
     145\item
     146Generate default constructor, copy constructor and destructor for user-defined @struct@ types.
     147\item
     148Resolve @with@ statements (the same as in Pascal~\cite{pascal}), which introduces fields of a structure directly into a scope.
    130149\item
    131150Resolve @typeof@ expressions (cf. @decltype@ in \CC); note that this step may depend on symbols introduced by @with@ statements.
    132151\end{itemize}
    133 Since the compiler codebase is large and the new memory model mostly only benefits expression resolution, the old data structure is still kept, and a conversion pass happens before and after resolve phase. Rewriting every compiler module will take a long time, and whether the new model is correct is still unknown when started, therefore only the resolver is implemented with the new data structure.
    134 
    135 Since the constructor calls were one of the most expensive to resolve (reason will be shown in the next section), pre-resolve phase were taking more time after resolver moves to the more efficient new implementation. To better facilitate the new resolver, every step that requires type information are reintegrated as part of resolver.
    136 
    137 A by-product of this work is that the reversed dependence of @with@ statement and @typeof@ can now be handled. Previously, the compiler is unable to handle cases such as
     152
     153Since the constructor calls are one of the most expensive to resolve (reason given in~\VRef{s:SpecialFunctionLookup}), this pre-resolve phase was taking a large amount of time even after the resolver was changed to the more efficient new implementation. The problem is that multiple resolutions repeat a significant amount of work. Therefore, to better facilitate the new resolver, every step that requires type information should be integrated as part of the general resolver phase.
     154
     155A by-product of this work is that reversed dependence between @with@ statement and @typeof@ can now be handled. Previously, the compiler was unable to handle cases such as:
    138156\begin{cfa}
    139157struct S { int x; };
    140158S foo();
    141159typeof( foo() ) s; // type is S
    142 with (s) { 
     160with (s) {
    143161        x; // refers to s.x
    144162}
    145163\end{cfa}
    146 since type of @s@ is still unresolved when handling @with@ expressions. Instead, the new (and correct) approach is to evaluate @typeof@ expressions when the declaration is first seen, and it suffices because of the declaration-before-use rule.
     164since the type of @s@ is unresolved when handling @with@ expressions because the @with@ pass follows the @typeof@ pass (interchanging passes only interchanges the problem). Instead, the new (and correct) approach is to evaluate @typeof@ expressions when the declaration is first seen during resolution, and it suffices because of the declaration-before-use rule.
    147165
    148166
    149167\subsection{Special function lookup}
    150 
    151 Reducing the number of functions looked up for overload resolution is an effective way to gain performance when there are many overloads but most of them are trivially wrong. In practice, most functions have few (if any) overloads but there are notable exceptions. Most importantly, constructor @?{}@, destructor @^?{}@, and assignment @?=?@ are generated for every user-defined type, and in a large source file there can be hundreds of them. Furthermore, many calls to them are generated for initializing variables and passing arguments. This fact makes them the most overloaded and most called functions.
    152 
    153 In an object-oriented programming language, object has methods declared with their types, so a call such as @obj.f()@ only needs to perform lookup in the method table corresponding to type of @obj@. \CFA on the other hand, does not have methods, and all types are open (\ie new operations can be defined on them), so a similar approach will not work in general. However, the ``big 3'' operators have a unique property enforced by the language rules, such that the first parameter must have a reference type. Since \CFA does not have class inheritance, reference type must always match exactly. Therefore, argument-dependent lookup can be implemented for these operators, by using a dedicated symbol table.
    154 
    155 The lookup key used for the special functions is the mangled type name of the first parameter, which acts as the @this@ parameter in an object-oriented language. To handle generic types, the type parameters are stripped off, and only the base type is matched. Note that a constructor (destructor, assignment operator) taking arbitrary @this@ argument, for example @forall( dtype T ) void ?{}( T & );@ is not allowed, and it guarantees that if the @this@ type is known, all possible overloads can be found by searching with the given type. In case that the @this@ argument itself is overloaded, it is resolved first and all possible result types are used for lookup.
    156 
    157 Note that for the generated expressions, the particular variable for @this@ argument is fully known, without overloads, so the majority of constructor call resolutions only need to check for one given object type. Explicit constructor calls and assignment statements sometimes may require lookup for multiple types. In the extremely rare case that type of @this@ argument is yet unbound, everything will have to be checked, just like without the argument-dependent lookup algorithm; fortunately, this case almost never happens in practice. An example is found in the library function @new@:
     168\label{s:SpecialFunctionLookup}
     169
     170Reducing the number of function looked ups for overload resolution is an effective way to gain performance when there are many overloads but most of them are trivially wrong. In practice, most functions have few (if any) overloads but there are notable exceptions. Most importantly, constructor @?{}@, destructor @^?{}@, and assignment @?=?@ are generated for every user-defined type (@struct@ and @union@ in C), and in a large source file there can be hundreds of them. Furthermore, many calls are generated for initializing variables, passing arguments and copying values. This fact makes them the most overloaded and most called functions.
     171
     172In an object-oriented programming language, the object-method types are scoped within a class, so a call such as @obj.f()@ only needs to perform lookup in the method table corresponding to the type of @obj@. \CFA on the other hand, does not have methods, and all types are open, \ie new operations can be defined on them without inheritance; at best a \CFA type can be constrained by a translation unit. However, the ``big 3'' operators have a unique property enforced by the language rules: the first parameter must be a reference to its associated type, which acts as the @this@ parameter in an object-oriented language. Since \CFA does not have class inheritance, the reference type must always match exactly. Therefore, argument-dependent lookup can be implemented for these operators by using a dedicated, fast symbol-table.
     173
     174The lookup key for the special functions is the mangled type name of the first parameter. To handle generic types, the type parameters are stripped off, and only the base type is matched. Note a constructor (destructor, assignment operator) may not take an arbitrary @this@ argument, \eg @forall( dtype T ) void ?{}( T & )@, thus guaranteeing that if the @this@ type is known, all possible overloads can be found by searching with this given type. In the case where the @this@ argument itself is overloaded, it is resolved first and all possible result types are used for lookup.
     175
     176Note that for a generated expression, the particular variable for the @this@ argument is fully known, without overloads, so the majority of constructor-call resolutions only need to check for one given object type. Explicit constructor calls and assignment statements sometimes require lookup for multiple types. In the extremely rare case that the @this@-argument type is unbound, all necessary types are guaranteed to be checked, as for the previous lookup without the argument-dependent lookup; fortunately, this complex case almost never happens in practice. An example is found in the library function @new@:
    158177\begin{cfa}
    159178forall( dtype T | sized( T ), ttype TT | { void ?{}( T &, TT ); } )
    160179T * new( TT p ) { return &(*malloc()){ p }; }
    161180\end{cfa}
    162 as @malloc@ may return a pointer to any type, depending on context. 
    163 
    164 Interestingly, this particular line of code actually caused another complicated issue, where the unusually massive work of checking every constructor in presence makes the case even worse. Section~\ref{s:TtypeResolutionInfiniteRecursion} presents a detailed analysis for the problem.
    165 
    166 The ``callable'' operator @?()@ (cf. @operator()@ in \CC) could also be included in the special operator list, as it is usually only on user-defined types, and the restriction that first argument must be a reference seems reasonable in this case.
     181as @malloc@ may return a pointer to any type, depending on context.
     182
     183Interestingly, this particular declaration actually causes another complicated issue, making the complex checking of every constructor even worse. \VRef[Section]{s:TtypeResolutionInfiniteRecursion} presents a detailed analysis of this problem.
     184
     185The ``callable'' operator @?()@ (cf. @operator()@ in \CC) can also be included in this special operator list, as it is usually only on user-defined types, and the restriction that the first argument must be a reference seems reasonable in this case.
    167186
    168187
    169188\subsection{Improvement of function type representation}
    170189
    171 Since substituting type parameters with their bound types is one fundamental operation in many parts of resolver algorithm (particularly unification and environment binding), making as few copies of type nodes as possible helps reducing memory complexity. Even with the new memory management model, allocation is still a significant factor of resolver performance. Conceptually, operations on type nodes of AST should be performed in functional programming style, treating the data structure as immutable and only copy when necessary. The in-place mutation is a mere optimization that does not change logic of operations.
    172 The model was broken on function types by an inappropriate design. Function types require some special treatment due to the existence of assertions. In particular, it must be able to distinguish two different kinds of type parameter usage:
     190Since substituting type parameters with their bound types is one fundamental operation in many parts of resolver algorithm (particularly unification and environment binding), making as few copies of type nodes as possible helps reducing memory complexity. Even with the new memory management model, allocation is still a significant factor of resolver performance. Conceptually, operations on type nodes of the AST should be performed in functional-programming style, treating the data structure as immutable and only copying when necessary. The in-place mutation is a mere optimization that does not change the logic for operations.
     191
     192However, the model was broken for function types by an inappropriate design. Function types require special treatment due to the existence of assertions that constrain the types it supports. Specifically, it must be possible to distinguish two different kinds of type parameter usage:
    173193\begin{cfa}
    174194forall( dtype T ) void foo( T * t ) {
    175         forall( dtype U ) void bar( T * t, U * u ) { ... }
    176 }
    177 \end{cfa}
    178 Here, only @U@ is a free parameter in declaration of @bar@, as it appears in the function's own forall clause; while @T@ is not free.
    179 
    180 Moreover, the resolution algorithm also has to distinguish type bindings of multiple calls to the same function, for example with
     195        forall( dtype U ) void bar( @T@ * t, @U@ * u ) { ... }
     196}
     197\end{cfa}
     198Here, only @U@ is a free parameter in the nested declaration of function @bar@, as @T@ must be bound at the call site when resolving @bar@.
     199
     200Moreover, the resolution algorithm also has to distinguish type bindings of multiple calls to the same function, \eg:
    181201\begin{cfa}
    182202forall( dtype T ) int foo( T x );
    183 foo( foo( 1.0 ) );
    184 \end{cfa}
    185 The inner call has binding (T: double) while the outer call has binding (T: int). Therefore a unique representation of free parameters in each expression is required. This was previously done by creating a copy of the parameter declarations inside function type, and fixing references afterwards. However, fixing references is an inherently deep operation that does not work well with functional programming model, as it must be evaluated eagerly on the entire syntax tree representing the function type.
    186 
    187 The revised approach generates a unique ID value for each function call expression instance and represents an occurrence of free parameter type with a pair of generated ID and the original parameter declaration, so that references do not need to be fixed, and a shallow copy of function type is possible.
    188 
    189 Note that after the change, all declaration nodes in syntax tree representation maps one-to-one with the actual declarations in the program, and therefore are guaranteed to be unique. Such property can potentially enable more optimizations, and some related ideas are presented after Section~\ref{s:SharedSub-ExpressionCaseUniqueExpressions}.
     203int i = foo( foo( 1.0 ) );
     204\end{cfa}
     205The inner call has binding (T: double) while the outer call has binding (T: int). Therefore a unique representation for the free parameters is required in each expression. This type binding was previously done by creating a copy of the parameter declarations inside the function type and fixing references afterwards. However, fixing references is an inherently deep operation that does not work well with the functional-programming style, as it forces eager evaluation on the entire syntax tree representing the function type.
     206
     207The revised approach generates a unique ID value for each function call expression instance and represents an occurrence of a free-parameter type with a pair of generated ID and original parameter declaration, so references are unique and a shallow copy of the function type is possible.
     208
     209Note that after the change, all declaration nodes in the syntax-tree representation now map one-to-one with the actual declarations in the program, and therefore are guaranteed to be unique. This property can potentially enable more optimizations, and some related ideas are presented at the end of \VRef{s:SharedSub-ExpressionCaseUniqueExpressions}.
    190210
    191211
    192212\subsection{Improvement of pruning steps}
    193213
    194 A minor improvement for candidate elimination is to skip the step on the function overloads themselves and only perform on results of function application. As function calls are usually by name, the name resolution rule dictates that every function candidate necessarily has a different type; indirect function calls are rare, and when they do appear, they usually will not have many possible interpretations, and those rarely matches exactly in argument type. Since function types have a much more complex representation than data types (with multiple parameters and assertions), checking equality on them also takes longer.
    195 
    196 A brief test of this approach shows that the number of function overloads considered in expression resolution increases by a negligible amount of less than 1 percent, while type comparisons in candidate elimination are cut by more than half. Improvement is consistent over all \CFA source files in the test suite.
     214A minor improvement for candidate elimination is to skip the step on the function overloads and only check the results of function application. As function calls are usually by name (versus pointers to functions), the name resolution rule dictates that every function candidate necessarily has a different type; indirect function calls are rare, and when they do appear, there are even fewer cases with multiple interpretations, and these rarely match exactly in argument type. Since function types have a much more complex representation (with multiple parameters and assertions) than data types, checking equality on them also takes longer.
     215
     216A brief test of this approach shows that the number of function overloads considered in expression resolution increases by an amount of less than 1 percent, while type comparisons in candidate elimination are reduced by more than half. This improvement is consistent over all \CFA source files in the test suite.
    197217
    198218
     
    200220\label{s:SharedSub-ExpressionCaseUniqueExpressions}
    201221
    202 Unique expression denotes an expression that must be evaluated only once, to prevent unwanted side effects. It is currently only a compiler artifact, generated on tuple member expression of the form
     222Unique expression denotes an expression evaluated only once to prevent unwanted side effects. It is currently only a compiler artifact, generated for tuple-member expression of the form:
    203223\begin{cfa}
    204224struct S { int a; int b; };
     
    206226s.[a, b]; // tuple member expression, type is [int, int]
    207227\end{cfa}
    208 If the aggregate expression contains function calls, it cannot be evaluated multiple times:
     228If the aggregate expression is function call, it cannot be evaluated multiple times:
    209229\begin{cfa}
    210230S makeS();
    211 makeS().[a, b]; // this should only make one S
     231makeS().[a, b]; // this should only generate a unique S
    212232\end{cfa}
    213233Before code generation, the above expression is internally represented as
     
    226246\end{cfa}
    227247at code generation, where @_unique_var@ and @_unique_var_evaluated@ are generated variables whose scope covers all appearances of the same expression.
    228 
    229 Note that although the unique expression is only used for tuple expansion now, it is a generally useful construction, and can be seen in other languages, such as Scala's @lazy val@~\cite{Scala}; therefore it could be worthwhile to introduce the unique expression to a broader context in \CFA and even make it directly available to programmers.
    230 
    231 In the compiler's visitor pattern, however, this creates a problem where multiple paths to a logically unique expression exist, so it may be modified more than once and become ill-formed; some specific intervention is required to ensure that unique expressions are only visited once. Furthermore, a unique expression appearing in more than one places will be copied on mutation so its representation is no longer unique. Some hacks are required to keep it in sync, and the methods are different when mutating the unique expression instance itself or its underlying expression.
    232 
    233 Example when mutating the underlying expression (visit-once guard)
     248The conditional check ensures a single call to @makeS()@ even though there are logically multiple calls because of the tuple field expansion.
     249
     250Note that although the unique expression is only used for tuple expansion now, it is a generally useful construction, and is seen in other programming languages, such as Scala's @lazy val@~\cite{Scala}; therefore it may be worthwhile to introduce the unique expression to a broader context in \CFA and even make it directly available to programmers.
     251
     252In the compiler's visitor pattern, however, this creates a problem where multiple paths to a logically unique expression exist, so it may be modified more than once and become ill-formed; some specific intervention is required to ensure unique expressions are only visited once. Furthermore, a unique expression appearing in more than one places is copied on mutation so its representation is no longer unique.
     253
     254Currently, special cases are required to keep everything synchronized, and the methods are different when mutating the unique expression instance itself or its underlying expression:
     255\begin{itemize}
     256\item
     257When mutating the underlying expression (visit-once guard)
    234258\begin{cfa}
    235259void InsertImplicitCalls::previsit( const ast::UniqueExpr * unqExpr ) {
    236         if ( visitedIds.count( unqExpr->id ) ) visit_children = false;
     260        @if ( visitedIds.count( unqExpr->id ) ) visit_children = false;@
    237261        else visitedIds.insert( unqExpr->id );
    238262}
    239263\end{cfa}
    240 Example when mutating the unique instance itself, which actually creates copies
     264\item
     265When mutating the unique instance itself, which actually creates copies
    241266\begin{cfa}
    242267auto mutExpr = mutate( unqExpr ); // internally calls copy when shared
    243 if ( ! unqMap.count( unqExpr->id ) ) {
     268@if ( ! unqMap.count( unqExpr->id ) ) {@
    244269        ...
    245270} else {
     
    248273}
    249274\end{cfa}
    250 Such workaround seems difficult to be fit into a common visitor template. This suggests the memory model may need different kinds of nodes to accurately represent the syntax tree.
    251 
    252 Together with the fact that declaration nodes are always unique, it is possible that AST nodes can be classified by three different types:
    253 \begin{itemize}
    254 \item
    255 \textbf{Strictly unique} with only one owner (declarations);
    256 \item
    257 \textbf{Logically unique} with (possibly) many owners but should not be copied (unique expression example presented here);
    258 \item
    259 \textbf{Shared} by functional programming model, which assume immutable data structure and are copied on mutation.
     275\end{itemize}
     276Such workarounds are difficult to fit into the common visitor pattern, which suggests the memory model may need different kinds of nodes to accurately represent this feature in the AST.
     277
     278Given that declaration nodes are unique, it is possible for AST nodes to be divided into three different types:
     279\begin{itemize}
     280\item
     281\textbf{Singleton} with only one owner (declarations);
     282\item
     283\textbf{No-copy} with multiple owners but cannot be copied (unique expression example presented here);
     284\item
     285\textbf{Copy} by functional-programming style, which assumes immutable data structures that are copied on mutation.
    260286\end{itemize}
    261287The boilerplate code can potentially handle these three cases differently.
     
    264290\section{Analysis of resolver algorithm complexity}
    265291
    266 The focus of this chapter is to identify and analyze some realistic cases that cause resolver algorithm to have an exponential run time. As previous work has shown [3], the overload resolution problem in \CFA has worst-case exponential complexity; however, only few specific patterns can trigger the exponential complexity in practice. Implementing heuristic-based optimization for those selected cases is helpful to alleviate the problem.
     292The focus of this section is to identify and analyze some realistic cases that cause the resolver algorithm to have an exponential runtime. As previous work has shown~\cite[\S~4.2.1]{Moss19}, the overload resolution problem in \CFA has worst-case exponential complexity; however, only few specific patterns can trigger the exponential complexity in practice. Implementing heuristic-based optimization for those selected cases is helpful to alleviate the problem.
    267293
    268294
     
    270296\label{s:UnboundReturnType}
    271297
    272 The interaction of return type overloading and polymorphic functions creates this problem of function calls with unbound return type, and is further complicated by the presence of assertions.
     298The interaction of return-type overloading and polymorphic functions creates function calls with unbounded return-type, and is further complicated by the presence of assertions.
    273299The prime example of a function with unbound return type is the type-safe version of C @malloc@:
    274300\begin{cfa}
    275 // size deduced from type, so no need to provide the size argument
    276 forall( dtype T | sized( T ) ) T * malloc( void );
    277 \end{cfa}
    278 Unbound return type can be problematic in resolver algorithm complexity because a single match of function call with unbound return type may create multiple candidates. In the worst case, consider a function declared to return any @otype@:
     301forall( dtype T | sized( T ) )
     302T * malloc( void ) { return (T *)malloc( sizeof(T) ); } // call C malloc
     303int * i = malloc();  // type deduced from left-hand size $\Rightarrow$ no size argument or return cast
     304\end{cfa}
     305An unbound return-type is problematic in resolver complexity because a single match of a function call with an unbound return type may create multiple candidates. In the worst case, consider a function declared that returns any @otype@ (defined \VPageref{otype}):
    279306\begin{cfa}
    280307forall( otype T ) T anyObj( void );
    281308\end{cfa}
    282 As the resolver attempts to satisfy the otype constraint on @T@, a single call to @anyObj()@ without the result type known creates at least as many candidates as the number of complete types currently in scope; with generic types it becomes even worse, for example, assuming a declaration of generic pair is available at that point:
     309As the resolver attempts to satisfy the otype constraint on @T@, a call to @anyObj()@ in an expression, without the result type known, creates at least as many candidates as the number of complete types currently in scope; with generic types it becomes even worse, \eg assuming a declaration of a generic @pair@ is available at that point:
    283310\begin{cfa}
    284311forall( otype T, otype U ) struct pair { T first; U second; };
    285312\end{cfa}
    286 Then an @anyObj()@ call can result in arbitrarily complex types, such as @pair( pair( int,int ), pair( int,int ) )@, and the depth can grow indefinitely until the specified parameter depth limit, thus creating exponentially many candidates. However, the expected types allowed by parent expressions are practically very few, so most of those interpretations are invalid; if the result type is never bound up to top level, by the semantic rules it is ambiguous if there are more than one valid bindings, and resolution can fail fast. It is therefore reasonable to delay resolving assertions on an unbound parameter in return type; however, with the current cost model, such behavior may further cause irregularities in candidate selection, such that the presence of assertions can change the preferred candidate, even when order of expression costs are supposed to stay the same. Detailed analysis of this issue will be presented later, in the correctness part.
     313Then an @anyObj()@ call can result in arbitrarily complex types, such as @pair( pair( int, int ), pair( int, int ) )@, and the depth can grow indefinitely until a specified parameter-depth limit, thus creating exponentially many candidates. However, the expected types allowed by parent expressions are practically very few, so most of those interpretations are invalid; if the result type is never bound up to the top level, by the semantic rules it is ambiguous if there is more than one valid binding and resolution fails quickly. It is therefore reasonable to delay resolving assertions on an unbound parameter in a return type; however, with the current cost model, such behavior may further cause irregularities in candidate selection, such that the presence of assertions can change the preferred candidate, even when order of expression costs are supposed to stay the same. A detailed analysis of this issue is presented in \VRef{s:AnalysisTypeSystemCorrectness}.
    287314
    288315
     
    290317\label{s:TtypeResolutionInfiniteRecursion}
    291318
    292 @ttype@ (``tuple type'') is a relatively new addition to the language that attempts to provide type-safe variadic argument semantics. Unlike regular @dtype@ parameters, @ttype@ is only valid in function parameter list, and may only appear once as the type of last parameter. At the call site, a @ttype@ parameter is bound to the tuple type of all remaining function call arguments.
     319@ttype@ (``tuple type'') is a relatively new addition to the language that attempts to provide type-safe variadic argument semantics. Unlike regular @dtype@ parameters, @ttype@ is only valid in a function parameter-list, and may only appear once as the last parameter type. At the call site, a @ttype@ parameter is bound to the tuple type of all remaining function-call arguments.
    293320
    294321There are two kinds of idiomatic @ttype@ usage: one is to provide flexible argument forwarding, similar to the variadic template in \CC (\lstinline[language=C++]|template<typename... args>|), as shown below in the implementation of @unique_ptr@
     
    298325        T * data;
    299326};
    300 forall( dtype T | sized( T ), ttype Args | { void ?{}( T &, Args ); })
    301 void ?{}( unique_ptr( T ) & this, Args args ) {
    302         this.data = new( args );
    303 }
    304 \end{cfa}
    305 the other is to implement structural recursion in the first-rest manner:
    306 \begin{cfa}
    307 forall( otype T, ttype Params | { void process( T ); void func( Params ); })
     327forall( dtype T | sized( T ), @ttype Args@ | { void ?{}( T &, Args ); })
     328void ?{}( unique_ptr( T ) & this, Args @args@ ) {
     329        this.data = new( @args@ );  // forward constructor arguments to dynamic allocator
     330}
     331\end{cfa}
     332The other usage is to implement structural recursion in the first-rest pattern:
     333\begin{cfa}
     334forall( otype T, @ttype Params@ | { void process( T ); void func( Params ); })
    308335void func( T arg1, Params p ) {
    309336        process( arg1 );
    310         func( p );
    311 }
    312 \end{cfa}
    313 For the second use case, it is important that the number of parameters in the recursive call go down, since the call site must deduce all assertion candidates, and that is only possible if by just looking at argument types (and not their values), the recursion is known to be completed in a finite number of steps.
    314 
    315 In recent experiments, however, some flaw in the type binding rules can lead to the first kind of @ttype@ use case produce an invalid candidate that the resolver enters an infinite loop.
    316 
    317 This bug was discovered in an attempt to raise assertion recursive depth limit and one of the library program takes exponentially longer time to compile. The cause of the problem is identified to be the following set of functions.
    318 File @memory.cfa@ contains
    319 \begin{cfa}
    320 #include "memory.hfa"
    321 #include "stdlib.hfa"
    322 \end{cfa}
    323 where file @memory.hfa@ contains the @unique_ptr@ declaration above, and two other similar functions with @ttype@ parameter:
    324 \begin{cfa}
    325 forall( dtype T | sized( T ), ttype Args | { void ?{}( T &, Args ); }) {
     337        func( @p@ );  // recursive call until base case of one argument
     338}
     339\end{cfa}
     340For the second use case, it is imperative the number of parameters in the recursive call goes down, since the call site must deduce all assertion candidates, and that is only possible if by observation of the argument types (and not their values), the recursion is known to be completed in a finite number of steps.
     341
     342In recent experiments, however, a flaw in the type-binding rules can lead to the first kind of @ttype@ use case producing an invalid candidate and the resolver enters an infinite loop.
     343This bug was discovered in an attempt to raise the assertion recursive-depth limit and one of the library programs took exponentially longer to compile. The cause of the problem is the following set of functions:
     344\begin{cfa}
     345// unique_ptr  declaration from above
     346
     347forall( dtype T | sized( T ), ttype Args | { void ?{}( T &, Args ); } ) { // distribute forall clause
    326348        void ?{}( counter_data( T ) & this, Args args );
    327349        void ?{}( counter_ptr( T ) & this, Args args );
    328350        void ?{}( unique_ptr( T ) & this, Args args );
    329351}
    330 \end{cfa}
    331 File @stdlib.hfa@ contains
    332 \begin{cfa}
     352
    333353forall( dtype T | sized( T ), ttype TT | { void ?{}( T &, TT ); } )
    334 T * new( TT p ) { return &(*malloc()){ p }; }
    335 \end{cfa}
    336 
    337 In the expression @(*malloc()){p}@, the type of object being constructed is yet unknown, since the return type information is not immediately provided. That caused every constructor to be searched, and while normally a bound @ttype@ cannot be unified with any free parameter, it is possible with another free @ttype@. Therefore in addition to the correct option provided by assertion, 3 wrong options are examined, each of which again requires the same assertion, for an unknown base type T and @ttype@ arguments, and that becomes an infinite loop, until the specified recursion limit and resolution is forced to fail. Moreover, during the recursion steps, number of candidates grows exponentially, since there are always 3 options at each step.
    338 
    339 Unfortunately, @ttype@ to @ttype@ binding is necessary, to allow calling the function provided by assertion indirectly.
    340 \begin{cfa}
    341 forall( dtype T | sized( T ), ttype Args | { void ?{}( T &, Args ); })
    342 void ?{}( unique_ptr( T ) & this, Args args ) { this.data = (T * )new( args ); }
    343 \end{cfa}
    344 Here the constructor assertion is used for the @new( args )@ call.
     354T * new( TT p ) { return @&(*malloc()){ p };@ }
     355\end{cfa}
     356In the expression @(*malloc()){p}@, the type of the object being constructed is unknown, since the return-type information is not immediately available. That causes every constructor to be searched, and while normally a bound @ttype@ cannot be unified with any free parameter, it is possible with another free @ttype@. Therefore, in addition to the correct option provided by the assertion, 3 wrong options are examined, each of which again requires the same assertion, for an unknown base-type @T@ and @ttype@ argument, which becomes an infinite loop until the specified recursion limit and resolution is fails. Moreover, during the recursion steps, the number of candidates grows exponentially, since there are always 3 options at each step.
     357
     358Unfortunately, @ttype@ to @ttype@ binding is necessary, to allow indirectly calling a function provided in an assertion.
     359\begin{cfa}
     360forall( dtype T | sized( T ), ttype Args | { @void ?{}( T &, Args );@ })
     361void ?{}( unique_ptr( T ) & this, Args args ) { this.data = (T *)@new( args )@; } // constructor call
     362\end{cfa}
     363Here the constructor assertion is used by the @new( args )@ call to indirectly call the constructor on the allocated storage.
    345364Therefore, it is hard, perhaps impossible, to solve this problem by tweaking the type binding rules. An assertion caching algorithm can help improve this case by detecting cycles in recursion.
    346365
    347 Meanwhile, without the caching algorithm implemented, some changes in the \CFA source code are enough to eliminate this problem, at least in the current codebase. Note that the issue only happens with an overloaded variadic function, which rarely appears in practice, since the idiomatic use cases are for argument forwarding and self-recursion. The only overloaded @ttype@ function so far discovered in all of \CFA standard library code is the constructor, and by utilizing the argument-dependent lookup process described in Section~\ref{s:UnboundReturnType}, adding a cast before constructor call gets rid of the issue.
    348 \begin{cfa}
    349 T * new( TT p ) { return &(*(T * )malloc()){ p }; }
     366Meanwhile, without a caching algorithm implemented, some changes in the \CFA source code are enough to eliminate this problem, at least in the current codebase. Note that the issue only happens with an overloaded variadic function, which rarely appears in practice, since the idiomatic use cases are for argument forwarding and self-recursion. The only overloaded @ttype@ function so far discovered in all of \CFA standard library is the constructor, and by utilizing the argument-dependent lookup process described in \VRef{s:UnboundReturnType}, adding a cast before the constructor call removes the issue.
     367\begin{cfa}
     368T * new( TT p ) { return &(*@(T * )@malloc()){ p }; }
    350369\end{cfa}
    351370
     
    353372\subsection{Reused assertions in nested generic type}
    354373
    355 The following test of deeply nested dynamic generic type reveals that locally caching reused assertions is necessary, rather than just a resolver optimization, because recomputing assertions can result in bloated generated code size:
     374The following test of deeply nested, dynamic generic type reveals that locally caching reused assertions is necessary, rather than just a resolver optimization, because recomputing assertions can result in bloated generated code size:
    356375\begin{cfa}
    357376struct nil {};
     
    361380int main() {
    362381        #if   N==0
    363         nil x;   
     382        nil @x@;
    364383        #elif N==1
    365         cons( size_t, nil ) x;
     384        cons( size_t, nil ) @x@;
    366385        #elif N==2
    367         cons( size_t, cons( size_t, nil ) ) x;
     386        cons( size_t, cons( size_t, nil ) ) @x@;
    368387        #elif N==3
    369         cons( size_t, cons( size_t, cons( size_t, nil ) ) ) x;
     388        cons( size_t, cons( size_t, cons( size_t, nil ) ) ) @x@;
    370389        // similarly for N=4,5,6
    371390        #endif
    372391}
    373392\end{cfa}
    374 At the declaration of @x@, it is implicitly initialized by generated constructor call, whose signature is given by
     393At the declaration of @x@, it is implicitly initialized by generated constructor call, with signature:
    375394\begin{cfa}
    376395forall( otype L, otype R ) void ?{}( cons( L, R ) & );
    377396\end{cfa}
    378 Note that the @otype@ constraint contains 4 assertions:
     397where the @otype@ constraint contains the 4 assertions:\label{otype}
    379398\begin{cfa}
    380399void ?{}( L & ); // default constructor
     
    383402L & ?=?( L &, L & ); // assignment
    384403\end{cfa}
    385 Now since the right hand side of outermost cons is again a cons, recursive assertions are required. When the compiler cannot cache and reuse already resolved assertions, it becomes a problem, as each of those 4 pending assertions again asks for 4 more assertions one level below. Without any caching, number of resolved assertions grows exponentially, while that is obviously unnecessary since there are only $n+1$ different types involved. Even worse, this causes exponentially many wrapper functions generated later at the codegen step, and results in huge compiled binary.
    386 
    387 \begin{table}[h]
     404
     405\begin{table}[htb]
     406\centering
    388407\caption{Compilation results of nested cons test}
     408\label{t:NestedConsTest}
    389409\begin{tabular}{|r|r|r|}
    390410\hline
     
    402422\end{table}
    403423
    404 As the local functions are implemented by emitting executable code on the stack~\cite{gcc-nested-func}, it eventually means that compiled code also has exponential run time. This problem has evident practical implications, as nested collection types are frequently used in real production code.
    405 
     424Now since the right hand side of outermost cons is again a cons, recursive assertions are required. \VRef[Table]{t:NestedConsTest} shows when the compiler does not cache and reuse already resolved assertions, it becomes a problem, as each of these 4 pending assertions again asks for 4 more assertions one level below. Without caching, the number of resolved assertions grows exponentially, which is unnecessary since there are only $n+1$ different types involved. Even worse, this problem causes exponentially many wrapper functions to be generated at the backend, resulting in a huge binary. As the local functions are implemented by emitting executable code on the stack~\cite{gcc-nested-func}, it means that compiled code also has exponential run time. This problem has practical implications, as nested collection types are frequently used in real production code.
    406425
    407426\section{Analysis of type system correctness}
     427\label{s:AnalysisTypeSystemCorrectness}
    408428
    409429In Moss' thesis~\cite[\S~4.1.2,~p.~45]{Moss19}, the author presents the following example:
     
    422442From the set of candidates whose parameter and argument types have been unified and whose assertions have been satisfied, those whose sub-expression interpretations have the smallest total cost of conversion are selected ... The total cost of conversion for each of these candidates is then calculated based on the implicit conversions and polymorphism involved in adapting the types of the sub-expression interpretations to the formal parameter types.
    423443\end{quote}
    424 With this model, the algorithm picks @g1@ in resolving the @f( g( 42 ) )@ call, which seems to be undesirable.
    425 
    426 There are further evidence that shows the Bilson model is fundamentally incorrect, following the discussion of unbound return type in Section~\ref{s:UnboundReturnType}. By the conversion cost specification, a binding from a polymorphic type parameter to a concrete type incurs a polymorphic cost of 1. It remains unspecified \emph{when} the type parameters should become bound. When the parameterized types appear in the function parameters, they can be deduced from the argument type, and there is no ambiguity. In the unbound return case, however, the binding may happen at any stage in expression resolution, therefore it is impossible to define a unique local conversion cost. Note that type binding happens exactly once per parameter in resolving the entire expression, so the global binding cost is unambiguously 1.
    427 
    428 As per the current compiler implementation, it does have a notable inconsistency in handling such case. For any unbound parameter that does \emph{not} come with an associated assertion, it remains unbound to the parent expression; for those that does however, they are immediately bound in the assertion resolution step, and concrete result types are used in the parent expressions.
    429 
     444With this model, the algorithm picks @g1@ in resolving the @f( g( 42 ) )@ call, which is undesirable.
     445
     446There is further evidence that shows the Bilson model is fundamentally incorrect, following the discussion of unbound return type in \VRef{s:UnboundReturnType}. By the conversion-cost specification, a binding from a polymorphic type-parameter to a concrete type incurs a polymorphic cost of 1. It remains unspecified \emph{when} the type parameters should become bound. When the parameterized types appear in function parameters, they can be deduced from the argument type, and there is no ambiguity. In the unbound return case, however, the binding may happen at any stage in expression resolution, therefore it is impossible to define a unique local conversion cost. Note that type binding happens exactly once per parameter in resolving the entire expression, so the global binding cost is unambiguously 1.
     447
     448In the current compiler implementation, there is a notable inconsistency in handling this case. For any unbound parameter that does \emph{not} come with an associated assertion, it remains unbound to the parent expression; for those that do, however, they are immediately bound in the assertion resolution step, and concrete result types are used in the parent expressions.
    430449Consider the following example:
    431450\begin{cfa}
     
    433452void h( int * );
    434453\end{cfa}
    435 The expression @h( f() )@ eventually has a total cost of 1 from binding (T: int), but in the eager resolution model, the cost of 1 may occur either at call to @f@ or at call to @h@, and with the assertion resolution triggering a binding, the local cost of @f()@ is (0 poly, 0 spec) with no assertions, but (1 poly, -1 spec) with an assertion:
    436 \begin{cfa}
    437 forall( dtype T | { void g( T * ); } ) T * f( void );
     454The expression @h( f() )@ eventually has a total cost of 1 from binding (T: int), but in the eager-resolution model, the cost of 1 may occur either at the call to @f@ or at call to @h@, and with the assertion resolution triggering a binding, the local cost of @f()@ is (0 poly, 0 spec) with no assertions, but (1 poly, -1 spec) with an assertion:
     455\begin{cfa}
     456forall( dtype T | @{ void g( T * ); }@ ) T * f( void );
    438457void g( int * );
    439458void h( int * );
    440459\end{cfa}
    441 and that contradicts the principle that adding assertions should make expression cost lower. Furthermore, the time at which type binding and assertion resolution happens is an implementation detail of the compiler, but not a part of language definition. That means two compliant \CFA compilers, one performing immediate assertion resolution at each step, and one delaying assertion resolution on unbound types, can produce different expression costs and therefore different candidate selection, making the language rule itself partially undefined and therefore unsound. By the above reasoning, the updated cost model using global sum of costs should be accepted as the standard. It also allows the compiler to freely choose when to resolve assertions, as the sum of total costs is independent of that choice; more optimizations regarding assertion resolution can also be implemented.
     460and that contradicts the principle that adding assertions should make expression cost lower. Furthermore, the time at which type binding and assertion resolution happens is an implementation detail of the compiler, not part of the language definition. That means two compliant \CFA compilers, one performing immediate assertion resolution at each step, and one delaying assertion resolution on unbound types, can produce different expression costs and therefore different candidate selection, making the language rule itself partially undefined, and therefore, unsound. By the above reasoning, the updated cost model using global sum of costs should be accepted as the standard. It also allows the compiler to freely choose when to resolve assertions, as the sum of total costs is independent of that choice; more optimizations regarding assertion resolution can also be implemented.
    442461
    443462
    444463\section{Timing results}
    445464
    446 For the timing results presented here, the \CFA compiler is built with gcc 9.3.0, and tested on a server machine running Ubuntu 20.04, 64GB RAM and 32-core 2.2 GHz CPU, results reported by the time command, and using only 8 cores in parallel such that the time is close to the case with 100% CPU utilization on a single thread.
    447 
    448 On the most recent build, the \CFA standard library (~1.3 MB of source code) compiles in 4 minutes 47 seconds total processor time (single thread equivalent), with the slowest file taking 13 seconds. The test suite (178 test cases, ~2.2MB of source code) completes within 25 minutes total processor time,\footnote{Including a few runtime tests; total time spent in compilation is approximately 21 minutes.} with the slowest file taking 23 seconds. In contrast, the library build on old compiler takes 85 minutes total, 5 minutes for the slowest file. Full test suite takes too long with old compiler build and is therefore not run, but the slowest test cases take approximately 5 minutes. Overall, the most recent build compared to old build in April 2020, before the project started, is consistently faster by a factor of 20.
    449 
    450 Additionally, 6 selected \CFA source files with distinct features from library and test suite are used to test compiler performance after each of the optimizations are implemented. Test files are from the most recent build and run through C preprocessor to eliminate the factor of header file changes. The selected tests are:
    451 \begin{itemize}
    452 \item
    453 @lib/fstream@ (112 KB)\footnote{File sizes are after preprocessing, with no line information (\lstinline|gcc -E -P|).}: implementation of I/O library
     465For the timing results presented here, the \CFA compiler is built with gcc 9.3.0, and tested on a server machine running Ubuntu 20.04, 64GB RAM and 32-core 2.2 GHz CPU.
     466Timing is reported by the @time@ command and an experiment is run using 8 cores, where each core is at 100\% CPU utilization.
     467
     468On the most recent build, the \CFA standard library ($\approx$1.3 MB of source code) compiles in 4 minutes 47 seconds total processor time (single thread equivalent), with the slowest file taking 13 seconds. The test suite (178 test cases, $\approx$2.2MB of source code) completes within 25 minutes total processor time,
     469% PAB: I do not understand this footnote.
     470%\footnote{Including a few runtime tests; total time spent in compilation is approximately 21 minutes.}
     471with the slowest file taking 23 seconds. In contrast, the library build with the old compiler takes 85 minutes total, 5 minutes for the slowest file. The full test-suite takes too long with old compiler build and is therefore not run, but the slowest test cases take approximately 5 minutes. Overall, the most recent build compared to an old build is consistently faster by a factor of 20.
     472
     473Additionally, 6 selected \CFA source files with distinct features from the library and test suite are used to illustrate the compiler performance change after each of the implemented optimizations. Test files are from the most recent build and run through the C preprocessor to expand header file, perform macro expansions, but no line number information (@gcc -E -P@).
     474\VRef[Table]{t:SelectedFileByCompilerBuild} shows the selected tests:
     475\begin{itemize}
     476\item
     477@lib/fstream@ (112 KB)
    454478\item
    455479@lib/mutex@ (166 KB): implementation of concurrency primitive
     
    459483@lib/stdlib@ (64 KB): type-safe wrapper to @void *@-based C standard library functions
    460484\item
    461 @test/ISO2@ (55 KB): application of I/O library
     485@test/io2@ (55 KB): application of I/O library
    462486\item
    463487@test/thread@ (188 KB): application of threading library
    464488\end{itemize}
    465 
    466 The \CFA compiler builds are picked from git commit history that passed the test suite, and implement the optimizations incrementally:
    467 \begin{itemize}
    468 \item
    469 \#0 is the first working build of new AST data structure
     489versus \CFA compiler builds picked from the git commit history that implement the optimizations incrementally:
     490\begin{itemize}
     491\item
     492old resolver
     493\item
     494\#0 is the first working build of the new AST data structure
    470495\item
    471496\#1 implements special symbol table and argument-dependent lookup
    472497\item
    473 \#2 implements late assertion satisfaction
    474 \item
    475 \#3 implements revised function type representation
    476 \item
    477 \#4 skips pruning on expressions with function type (most recent build)
    478 \end{itemize}
    479 The old resolver with no memory sharing and none of the optimizations above is also tested.
    480 \begin{table}
     498\#2 implements late assertion-satisfaction
     499\item
     500\#3 implements revised function-type representation
     501\item
     502\#4 skips pruning on expressions for function types (most recent build)
     503\end{itemize}
     504Reading left to right for a test shows the benefit of each optimization on the cost of compilation.
     505
     506\begin{table}[htb]
     507\centering
    481508\caption{Compile time of selected files by compiler build, in seconds}
     509\label{t:SelectedFileByCompilerBuild}
    482510\begin{tabular}{|l|r|r|r|r|r|r|}
    483511\hline
     
    502530\end{table}
    503531
    504 
    505532\section{Conclusion}
    506533
    507 Over the course of 8 months of active research and development in \CFA type system and compiler algorithm, performance of the reference \CFA compiler, cfa-cc, has been greatly improved, allowing mid-sized \CFA programs to be compiled and built reasonably fast. As there are also ongoing efforts in the team on building a standard library, evaluating the runtime performance, and attempting to incorporate \CFA with existing software written in C, this project is especially meaningful for practical purposes.
    508 
    509 Analysis conducted in the project were based significantly on heuristics and practical evidence, as the theoretical bounds and average cases for the expression resolution problem differ. This approach was difficult at start to follow, with an unacceptably slow compiler, since running the program through debugger and validation tools (\eg @gdb@, @valgrind@) adds another order of magnitude to run time, which was already in minutes. However, near the end of the project, many significant improvements have already been made and new optimizations can be tested immediately. The positive feedback in development cycle benefits the \CFA team as a whole, more than just for the compiler optimizations.
    510 
    511 Some potential issues of the language that may happen frequently in practice have been identified. Due to the time constraint and complex nature of these problems, a handful of them remain unsolved, but some constructive proposals are made. Notably, introducing a local assertion cache in the resolver is a common solution for a few remaining problems, so that should be the focus of work soon.
    512 
    513 The \CFA team are planning on a public alpha release of the language as the compiler performance becomes promising, and other parts of the system, such as a standard library, are also being enhanced. Ideally, the remaining problems should be resolved before release, and the solutions will also be integral to drafting a formal specification.
     534Over the course of 8 months of active research and development of the \CFA type system and compiler algorithms, performance of the reference \CFA compiler, cfa-cc, has been greatly improved. Now, mid-sized \CFA programs are compiled reasonably fast. Currently, there are ongoing efforts by the \CFA team to augment the standard library and evaluate its runtime performance, and incorporate \CFA with existing software written in C; therefore this project is especially meaningful for these practical purposes.
     535
     536Accomplishing this work was difficult. Analysis conducted in the project is based significantly on heuristics and practical evidence, as the theoretical bounds and average cases for the expression resolution problem differ. As well, the slowness of the initial compiler made attempts to understand why and where problems exist extremely difficult because both debugging and validation tools (\eg @gdb@, @valgrind@, @pref@) further slowed down compilation time. However, by the end of the project, I had found and fixed several significant problems and new optimizations are easier to introduce and test. The reduction in the development cycle benefits the \CFA team as a whole.
     537
     538Some potential issues of the language, which happen frequently in practice, have been identified. Due to the time constraint and complex nature of these problems, a handful of them remain unsolved, but some constructive proposals are made. Notably, introducing a local assertion cache in the resolver is a reasonable solution for a few remaining problems, so that should be the focus of future work.
     539
     540The \CFA team are planning on a public alpha release of the language as the compiler performance, given my recent improvements, is now useable. Other parts of the system, such as the standard library, have made significant gains due to the speed up in the development cycle. Ideally, the remaining problems should be resolved before release, and the solutions will also be integral to drafting a formal specification.
    514541
    515542\addcontentsline{toc}{section}{\refname}
  • doc/theses/fangren_yu_COOP_S20/Report.tex

    rb6a8b31 rd95969a  
    1717\usepackage[usenames]{color}
    1818\input{common}                                          % common CFA document macros
    19 \usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref}
     19\usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref}
    2020\usepackage{breakurl}
    2121\urlstyle{sf}
  • driver/cfa.cc

    rb6a8b31 rd95969a  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Nov 17 14:27:28 2020
    13 // Update Count     : 440
     12// Last Modified On : Sat Jan 16 07:30:19 2021
     13// Update Count     : 442
    1414//
    1515
     
    499499                args[nargs++] = "-no-integrated-cpp";
    500500                args[nargs++] = "-Wno-deprecated";
     501                args[nargs++] = "-Wno-strict-aliasing";                 // casting from one type to another
    501502                #ifdef HAVE_CAST_FUNCTION_TYPE
    502503                args[nargs++] = "-Wno-cast-function-type";
  • libcfa/prelude/builtins.c

    rb6a8b31 rd95969a  
    1818// type that wraps a pointer and a destructor-like function - used in generating implicit destructor calls for struct members in user-defined functions
    1919// Note: needs to occur early, because it is used to generate destructor calls during code generation
    20 forall(dtype T)
     20forall(T &)
    2121struct __Destructor {
    2222        T * object;
     
    2525
    2626// defined destructor in the case that non-generated code wants to use __Destructor
    27 forall(dtype T)
     27forall(T &)
    2828static inline void ^?{}(__Destructor(T) & x) {
    2929        if (x.object && x.dtor) {
     
    3434// easy interface into __Destructor's destructor for easy codegen purposes
    3535extern "C" {
    36         forall(dtype T)
     36        forall(T &)
    3737        static inline void __destroy_Destructor(__Destructor(T) * dtor) {
    3838                ^(*dtor){};
     
    5151void abort( const char fmt[], ... ) __attribute__ (( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
    5252
    53 forall(dtype T)
     53forall(T &)
    5454static inline T & identity(T & i) {
    5555        return i;
     
    6464static inline void ^?{}($generator &) {}
    6565
    66 trait is_generator(dtype T) {
     66trait is_generator(T &) {
    6767      void main(T & this);
    6868      $generator * get_generator(T & this);
    6969};
    7070
    71 forall(dtype T | is_generator(T))
     71forall(T & | is_generator(T))
    7272static inline T & resume(T & gen) {
    7373        main(gen);
     
    7878
    7979static inline {
    80         forall( dtype DT | { DT & ?+=?( DT &, one_t ); } )
     80        forall( DT & | { DT & ?+=?( DT &, one_t ); } )
    8181        DT & ++?( DT & x ) { return x += 1; }
    8282
    83         forall( dtype DT | sized(DT) | { void ?{}( DT &, DT ); void ^?{}( DT & ); DT & ?+=?( DT &, one_t ); } )
     83        forall( DT & | sized(DT) | { void ?{}( DT &, DT ); void ^?{}( DT & ); DT & ?+=?( DT &, one_t ); } )
    8484        DT & ?++( DT & x ) { DT tmp = x; x += 1; return tmp; }
    8585
    86         forall( dtype DT | { DT & ?-=?( DT &, one_t ); } )
     86        forall( DT & | { DT & ?-=?( DT &, one_t ); } )
    8787        DT & --?( DT & x ) { return x -= 1; }
    8888
    89         forall( dtype DT | sized(DT) | { void ?{}( DT &, DT ); void ^?{}( DT & ); DT & ?-=?( DT &, one_t ); } )
     89        forall( DT & | sized(DT) | { void ?{}( DT &, DT ); void ^?{}( DT & ); DT & ?-=?( DT &, one_t ); } )
    9090        DT & ?--( DT & x ) { DT tmp = x; x -= 1; return tmp; }
    9191
    92         forall( dtype DT | { int ?!=?( const DT &, zero_t ); } )
     92        forall( DT & | { int ?!=?( const DT &, zero_t ); } )
    9393        int !?( const DT & x ) { return !( x != 0 ); }
    9494} // distribution
    9595
    9696// universal typed pointer constant
    97 static inline forall( dtype DT ) DT * intptr( uintptr_t addr ) { return (DT *)addr; }
     97static inline forall( DT & ) DT * intptr( uintptr_t addr ) { return (DT *)addr; }
    9898static inline forall( ftype FT ) FT * intptr( uintptr_t addr ) { return (FT *)addr; }
    9999
     
    156156#define __CFA_EXP_OVERFLOW__()
    157157
    158 static inline forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) {
     158static inline forall( OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) {
    159159        OT ?\?( OT ep, unsigned int y ) { __CFA_EXP__(); }
    160160        OT ?\?( OT ep, unsigned long int y ) { __CFA_EXP__(); }
  • libcfa/prelude/prelude-gen.cc

    rb6a8b31 rd95969a  
    159159int main() {
    160160        cout << "# 2 \"prelude.cfa\"  // needed for error messages from this file" << endl;
    161         cout << "trait sized(dtype T) {};" << endl;
     161        cout << "trait sized(T &) {};" << endl;
    162162
    163163        cout << "//////////////////////////" << endl;
     
    264264                for (auto cvq : qualifiersPair) {
    265265                        for (auto is_vol : { "        ", "volatile" }) {
    266                                 cout << "forall(dtype DT) void  ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl;
     266                                cout << "forall(DT &) void  ?{}(" << cvq.first << type << " * " << is_vol << " &, " << cvq.second << "DT *);" << endl;
    267267                        }
    268268                }
     
    279279        for (auto cvq : qualifiersSingle) {
    280280                for (auto is_vol : { "        ", "volatile" }) {
    281                         cout << "forall(dtype DT) void  ?{}(" << cvq << "  DT" << " * " << is_vol << " &);" << endl;
     281                        cout << "forall(DT &) void  ?{}(" << cvq << "  DT" << " * " << is_vol << " &);" << endl;
    282282                }
    283283                for (auto is_vol : { "        ", "volatile" }) {
    284                         cout << "forall(dtype DT) void ^?{}(" << cvq << "  DT" << " * " << is_vol << " &);" << endl;
     284                        cout << "forall(DT &) void ^?{}(" << cvq << "  DT" << " * " << is_vol << " &);" << endl;
    285285                }
    286286        }
     
    290290                for (auto is_vol : { "        ", "volatile" }) {
    291291                        for (auto cvq : qualifiersSingle) {
    292                                 cout << "forall(dtype DT) void ?{}( " << cvq << type << " * " << is_vol << " &, zero_t);" << endl;
     292                                cout << "forall(DT &) void ?{}( " << cvq << type << " * " << is_vol << " &, zero_t);" << endl;
    293293                        }
    294294                }
     
    317317        for (auto op : pointerOperators) {
    318318                auto forall = [&op]() {
    319                         cout << "forall(dtype DT" << op.sized << ") ";
     319                        cout << "forall(DT &" << op.sized << ") ";
    320320                };
    321321                for (auto type : { "DT"/*, "void"*/ } ) {
     
    408408        for (auto is_vol : { "        ", "volatile" }) {
    409409                for (auto cvq : qualifiersPair) {
    410                                 cout << "forall(dtype DT) " << cvq.first << "void * ?=?( " << cvq.first << "void * " << is_vol << " &, " << cvq.second << "DT *);" << endl;
     410                                cout << "forall(DT &) " << cvq.first << "void * ?=?( " << cvq.first << "void * " << is_vol << " &, " << cvq.second << "DT *);" << endl;
    411411                }
    412412                for (auto cvq : qualifiersSingle) {
    413                         cout << "forall(dtype DT) " << cvq <<   "  DT * ?=?( " << cvq << "  DT * " << is_vol << " &, zero_t);" << endl;
     413                        cout << "forall(DT &) " << cvq <<   "  DT * ?=?( " << cvq << "  DT * " << is_vol << " &, zero_t);" << endl;
    414414                }
    415415        }
  • libcfa/prelude/prelude.old.cf

    rb6a8b31 rd95969a  
    2323// ------------------------------------------------------------
    2424
    25 trait sized(dtype T) {};
     25trait sized(T &) {};
    2626
    2727// ------------------------------------------------------------
     
    6868long double _Complex    ?--( long double _Complex & ),          ?--( volatile long double _Complex & );
    6969
    70 forall( dtype T | sized(T) ) T *                         ?++(                T *& );
    71 forall( dtype T | sized(T) ) const T *           ?++( const          T *& );
    72 forall( dtype T | sized(T) ) volatile T *                ?++(       volatile T *& );
    73 forall( dtype T | sized(T) ) const volatile T *  ?++( const volatile T *& );
    74 forall( dtype T | sized(T) ) T *                         ?--(                T *& );
    75 forall( dtype T | sized(T) ) const T *           ?--( const          T *& );
    76 forall( dtype T | sized(T) ) volatile T *                ?--(       volatile T *& );
    77 forall( dtype T | sized(T) ) const volatile T *  ?--( const volatile T *& );
    78 
    79 forall( dtype T | sized(T) ) T &                 ?[?](                T *,          ptrdiff_t );
    80 forall( dtype T | sized(T) ) const T &   ?[?]( const          T *,          ptrdiff_t );
    81 forall( dtype T | sized(T) ) volatile T &        ?[?](       volatile T *,          ptrdiff_t );
    82 forall( dtype T | sized(T) ) const volatile T & ?[?]( const volatile T *,           ptrdiff_t );
    83 forall( dtype T | sized(T) ) T &                 ?[?](          ptrdiff_t,                T * );
    84 forall( dtype T | sized(T) ) const T &   ?[?](          ptrdiff_t, const          T * );
    85 forall( dtype T | sized(T) ) volatile T &        ?[?](          ptrdiff_t,       volatile T * );
    86 forall( dtype T | sized(T) ) const volatile T & ?[?](           ptrdiff_t, const volatile T * );
     70forall( T & | sized(T) ) T *                     ?++(                T *& );
     71forall( T & | sized(T) ) const T *               ?++( const          T *& );
     72forall( T & | sized(T) ) volatile T *            ?++(       volatile T *& );
     73forall( T & | sized(T) ) const volatile T *      ?++( const volatile T *& );
     74forall( T & | sized(T) ) T *                     ?--(                T *& );
     75forall( T & | sized(T) ) const T *               ?--( const          T *& );
     76forall( T & | sized(T) ) volatile T *            ?--(       volatile T *& );
     77forall( T & | sized(T) ) const volatile T *      ?--( const volatile T *& );
     78
     79forall( T & | sized(T) ) T &             ?[?](                T *,          ptrdiff_t );
     80forall( T & | sized(T) ) const T &       ?[?]( const          T *,          ptrdiff_t );
     81forall( T & | sized(T) ) volatile T &    ?[?](       volatile T *,          ptrdiff_t );
     82forall( T & | sized(T) ) const volatile T & ?[?]( const volatile T *,       ptrdiff_t );
     83forall( T & | sized(T) ) T &             ?[?](          ptrdiff_t,                T * );
     84forall( T & | sized(T) ) const T &       ?[?](          ptrdiff_t, const          T * );
     85forall( T & | sized(T) ) volatile T &    ?[?](          ptrdiff_t,       volatile T * );
     86forall( T & | sized(T) ) const volatile T & ?[?](               ptrdiff_t, const volatile T * );
    8787
    8888// ------------------------------------------------------------
     
    107107long double _Complex    ++?( long double _Complex & ),          --?( long double _Complex & );
    108108
    109 forall( dtype T | sized(T) ) T *                         ++?(                T *& );
    110 forall( dtype T | sized(T) ) const T *           ++?( const          T *& );
    111 forall( dtype T | sized(T) ) volatile T *                ++?(       volatile T *& );
    112 forall( dtype T | sized(T) ) const volatile T *  ++?( const volatile T *& );
    113 forall( dtype T | sized(T) ) T *                         --?(                T *& );
    114 forall( dtype T | sized(T) ) const T *           --?( const          T *& );
    115 forall( dtype T | sized(T) ) volatile T *                --?(       volatile T *& );
    116 forall( dtype T | sized(T) ) const volatile T *  --?( const volatile T *& );
    117 
    118 forall( dtype T | sized(T) ) T &                 *?(                 T * );
    119 forall( dtype T | sized(T) ) const T &           *?( const           T * );
    120 forall( dtype T | sized(T) ) volatile T &        *?(       volatile  T * );
    121 forall( dtype T | sized(T) ) const volatile T & *?( const volatile  T * );
     109forall( T & | sized(T) ) T *                     ++?(                T *& );
     110forall( T & | sized(T) ) const T *               ++?( const          T *& );
     111forall( T & | sized(T) ) volatile T *            ++?(       volatile T *& );
     112forall( T & | sized(T) ) const volatile T *      ++?( const volatile T *& );
     113forall( T & | sized(T) ) T *                     --?(                T *& );
     114forall( T & | sized(T) ) const T *               --?( const          T *& );
     115forall( T & | sized(T) ) volatile T *            --?(       volatile T *& );
     116forall( T & | sized(T) ) const volatile T *      --?( const volatile T *& );
     117
     118forall( T & | sized(T) ) T &             *?(                 T * );
     119forall( T & | sized(T) ) const T &               *?( const           T * );
     120forall( T & | sized(T) ) volatile T &    *?(       volatile  T * );
     121forall( T & | sized(T) ) const volatile T & *?( const volatile  T * );
    122122forall( ftype FT ) FT &          *?( FT * );
    123123
     
    142142                !?( float _Complex ),           !?( double _Complex ),          !?( long double _Complex );
    143143
    144 forall( dtype DT ) int !?(                DT * );
    145 forall( dtype DT ) int !?( const          DT * );
    146 forall( dtype DT ) int !?(       volatile DT * );
    147 forall( dtype DT ) int !?( const volatile DT * );
     144forall( DT & ) int !?(                DT * );
     145forall( DT & ) int !?( const          DT * );
     146forall( DT & ) int !?(       volatile DT * );
     147forall( DT & ) int !?( const volatile DT * );
    148148forall( ftype FT ) int !?( FT * );
    149149
     
    191191long double _Complex    ?+?( long double _Complex, long double _Complex ),      ?-?( long double _Complex, long double _Complex );
    192192
    193 forall( dtype T | sized(T) ) T *                ?+?(                T *,          ptrdiff_t );
    194 forall( dtype T | sized(T) ) T *                ?+?(          ptrdiff_t,                T * );
    195 forall( dtype T | sized(T) ) const T *          ?+?( const          T *,          ptrdiff_t );
    196 forall( dtype T | sized(T) ) const T *          ?+?(          ptrdiff_t, const          T * );
    197 forall( dtype T | sized(T) ) volatile T *       ?+?(       volatile T *,          ptrdiff_t );
    198 forall( dtype T | sized(T) ) volatile T *       ?+?(          ptrdiff_t,       volatile T * );
    199 forall( dtype T | sized(T) ) const volatile T * ?+?( const volatile T *,          ptrdiff_t );
    200 forall( dtype T | sized(T) ) const volatile T * ?+?(          ptrdiff_t, const volatile T * );
    201 forall( dtype T | sized(T) ) T *                ?-?(                T *,          ptrdiff_t );
    202 forall( dtype T | sized(T) ) const T *          ?-?( const          T *,          ptrdiff_t );
    203 forall( dtype T | sized(T) ) volatile T *       ?-?(       volatile T *,          ptrdiff_t );
    204 forall( dtype T | sized(T) ) const volatile T * ?-?( const volatile T *,          ptrdiff_t );
    205 forall( dtype T | sized(T) ) ptrdiff_t          ?-?( const volatile T *, const volatile T * );
     193forall( T & | sized(T) ) T *            ?+?(                T *,          ptrdiff_t );
     194forall( T & | sized(T) ) T *            ?+?(          ptrdiff_t,                T * );
     195forall( T & | sized(T) ) const T *              ?+?( const          T *,          ptrdiff_t );
     196forall( T & | sized(T) ) const T *              ?+?(          ptrdiff_t, const          T * );
     197forall( T & | sized(T) ) volatile T *   ?+?(       volatile T *,          ptrdiff_t );
     198forall( T & | sized(T) ) volatile T *   ?+?(          ptrdiff_t,       volatile T * );
     199forall( T & | sized(T) ) const volatile T *     ?+?( const volatile T *,          ptrdiff_t );
     200forall( T & | sized(T) ) const volatile T *     ?+?(          ptrdiff_t, const volatile T * );
     201forall( T & | sized(T) ) T *            ?-?(                T *,          ptrdiff_t );
     202forall( T & | sized(T) ) const T *              ?-?( const          T *,          ptrdiff_t );
     203forall( T & | sized(T) ) volatile T *   ?-?(       volatile T *,          ptrdiff_t );
     204forall( T & | sized(T) ) const volatile T *     ?-?( const volatile T *,          ptrdiff_t );
     205forall( T & | sized(T) ) ptrdiff_t              ?-?( const volatile T *, const volatile T * );
    206206
    207207// ------------------------------------------------------------
     
    255255           ?>?( long double, long double ),                             ?>=?( long double, long double );
    256256
    257 forall( dtype DT ) signed int ?<?(                 DT *,                DT * );
    258 forall( dtype DT ) signed int ?<?(  const          DT *, const          DT * );
    259 forall( dtype DT ) signed int ?<?(        volatile DT *,       volatile DT * );
    260 forall( dtype DT ) signed int ?<?(  const volatile DT *, const volatile DT * );
    261 
    262 forall( dtype DT ) signed int ?>?(                 DT *,                DT * );
    263 forall( dtype DT ) signed int ?>?(  const          DT *, const          DT * );
    264 forall( dtype DT ) signed int ?>?(        volatile DT *,       volatile DT * );
    265 forall( dtype DT ) signed int ?>?(  const volatile DT *, const volatile DT * );
    266 
    267 forall( dtype DT ) signed int ?<=?(                 DT *,                DT * );
    268 forall( dtype DT ) signed int ?<=?(  const          DT *, const          DT * );
    269 forall( dtype DT ) signed int ?<=?(        volatile DT *,       volatile DT * );
    270 forall( dtype DT ) signed int ?<=?( const volatile DT *, const volatile DT * );
    271 
    272 forall( dtype DT ) signed int ?>=?(                 DT *,                DT * );
    273 forall( dtype DT ) signed int ?>=?(  const          DT *, const          DT * );
    274 forall( dtype DT ) signed int ?>=?(        volatile DT *,       volatile DT * );
    275 forall( dtype DT ) signed int ?>=?( const volatile DT *, const volatile DT * );
     257forall( DT & ) signed int ?<?(                 DT *,                DT * );
     258forall( DT & ) signed int ?<?(  const          DT *, const          DT * );
     259forall( DT & ) signed int ?<?(        volatile DT *,       volatile DT * );
     260forall( DT & ) signed int ?<?(  const volatile DT *, const volatile DT * );
     261
     262forall( DT & ) signed int ?>?(                 DT *,                DT * );
     263forall( DT & ) signed int ?>?(  const          DT *, const          DT * );
     264forall( DT & ) signed int ?>?(        volatile DT *,       volatile DT * );
     265forall( DT & ) signed int ?>?(  const volatile DT *, const volatile DT * );
     266
     267forall( DT & ) signed int ?<=?(                 DT *,                DT * );
     268forall( DT & ) signed int ?<=?(  const          DT *, const          DT * );
     269forall( DT & ) signed int ?<=?(        volatile DT *,       volatile DT * );
     270forall( DT & ) signed int ?<=?( const volatile DT *, const volatile DT * );
     271
     272forall( DT & ) signed int ?>=?(                 DT *,                DT * );
     273forall( DT & ) signed int ?>=?(  const          DT *, const          DT * );
     274forall( DT & ) signed int ?>=?(        volatile DT *,       volatile DT * );
     275forall( DT & ) signed int ?>=?( const volatile DT *, const volatile DT * );
    276276
    277277// ------------------------------------------------------------
     
    302302signed int ?==?( one_t, one_t ),                                                        ?!=?( one_t, one_t );
    303303
    304 forall( dtype DT ) signed int ?==?(                DT *,                DT * );
    305 forall( dtype DT ) signed int ?==?( const          DT *, const          DT * );
    306 forall( dtype DT ) signed int ?==?(       volatile DT *,       volatile DT * );
    307 forall( dtype DT ) signed int ?==?( const volatile DT *, const volatile DT * );
     304forall( DT & ) signed int ?==?(            DT *,                DT * );
     305forall( DT & ) signed int ?==?( const      DT *, const          DT * );
     306forall( DT & ) signed int ?==?(       volatile DT *,       volatile DT * );
     307forall( DT & ) signed int ?==?( const volatile DT *, const volatile DT * );
    308308forall( ftype FT ) signed int ?==?( FT *, FT * );
    309 forall( dtype DT ) signed int ?!=?(                DT *,                DT * );
    310 forall( dtype DT ) signed int ?!=?( const          DT *, const          DT * );
    311 forall( dtype DT ) signed int ?!=?(       volatile DT *,       volatile DT * );
    312 forall( dtype DT ) signed int ?!=?( const volatile DT *, const volatile DT * );
     309forall( DT & ) signed int ?!=?(            DT *,                DT * );
     310forall( DT & ) signed int ?!=?( const      DT *, const          DT * );
     311forall( DT & ) signed int ?!=?(       volatile DT *,       volatile DT * );
     312forall( DT & ) signed int ?!=?( const volatile DT *, const volatile DT * );
    313313forall( ftype FT ) signed int ?!=?( FT *, FT * );
    314314
     
    376376
    377377forall( ftype FT ) FT *                 ?=?( FT *&, FT * );
    378 forall( ftype FT ) FT *                 ?=?( FT * volatile &, FT * );
    379 
    380 forall( dtype DT ) DT *                 ?=?(                 DT *          &,                   DT * );
    381 forall( dtype DT ) DT *                 ?=?(                 DT * volatile &,                   DT * );
    382 forall( dtype DT ) const DT *           ?=?( const           DT *          &,                   DT * );
    383 forall( dtype DT ) const DT *           ?=?( const           DT * volatile &,                   DT * );
    384 forall( dtype DT ) const DT *           ?=?( const           DT *          &, const             DT * );
    385 forall( dtype DT ) const DT *           ?=?( const           DT * volatile &, const             DT * );
    386 forall( dtype DT ) volatile DT *        ?=?(       volatile  DT *          &,                   DT * );
    387 forall( dtype DT ) volatile DT *        ?=?(       volatile  DT * volatile &,                   DT * );
    388 forall( dtype DT ) volatile DT *        ?=?(       volatile  DT *          &,       volatile    DT * );
    389 forall( dtype DT ) volatile DT *        ?=?(       volatile  DT * volatile &,       volatile    DT * );
    390 
    391 forall( dtype DT ) const volatile DT *  ?=?( const volatile  DT *          &,                   DT * );
    392 forall( dtype DT ) const volatile DT *  ?=?( const volatile  DT * volatile &,                   DT * );
    393 forall( dtype DT ) const volatile DT *  ?=?( const volatile  DT *          &, const             DT * );
    394 forall( dtype DT ) const volatile DT *  ?=?( const volatile  DT * volatile &, const             DT * );
    395 forall( dtype DT ) const volatile DT *  ?=?( const volatile  DT *          &,       volatile    DT * );
    396 forall( dtype DT ) const volatile DT *  ?=?( const volatile  DT * volatile &,       volatile    DT * );
    397 forall( dtype DT ) const volatile DT *  ?=?( const volatile  DT *          &, const volatile    DT * );
    398 forall( dtype DT ) const volatile DT *  ?=?( const volatile  DT * volatile &, const volatile    DT * );
    399 
    400 forall( dtype DT ) void *                ?=?(                void *          &,                 DT * );
    401 forall( dtype DT ) void *                ?=?(                void * volatile &,                 DT * );
    402 forall( dtype DT ) const void *          ?=?( const          void *          &,                 DT * );
    403 forall( dtype DT ) const void *          ?=?( const          void * volatile &,                 DT * );
    404 forall( dtype DT ) const void *          ?=?( const          void *          &, const           DT * );
    405 forall( dtype DT ) const void *          ?=?( const          void * volatile &, const           DT * );
    406 forall( dtype DT ) volatile void *       ?=?(       volatile void *          &,                 DT * );
    407 forall( dtype DT ) volatile void *       ?=?(       volatile void * volatile &,                 DT * );
    408 forall( dtype DT ) volatile void *       ?=?(       volatile void *          &,       volatile  DT * );
    409 forall( dtype DT ) volatile void *       ?=?(       volatile void * volatile &,       volatile  DT * );
    410 forall( dtype DT ) const volatile void * ?=?( const volatile void *          &,                 DT * );
    411 forall( dtype DT ) const volatile void * ?=?( const volatile void * volatile &,                 DT * );
    412 forall( dtype DT ) const volatile void * ?=?( const volatile void *          &, const           DT * );
    413 forall( dtype DT ) const volatile void * ?=?( const volatile void * volatile &, const           DT * );
    414 forall( dtype DT ) const volatile void * ?=?( const volatile void *          &,       volatile  DT * );
    415 forall( dtype DT ) const volatile void * ?=?( const volatile void * volatile &,       volatile  DT * );
    416 forall( dtype DT ) const volatile void * ?=?( const volatile void *          &, const volatile  DT * );
    417 forall( dtype DT ) const volatile void * ?=?( const volatile void * volatile &, const volatile  DT * );
     378forall( ftyep FT ) FT *                 ?=?( FT * volatile &, FT * );
     379
     380forall( DT & ) DT *                     ?=?(                 DT *          &,                   DT * );
     381forall( DT & ) DT *                     ?=?(                 DT * volatile &,                   DT * );
     382forall( DT & ) const DT *               ?=?( const           DT *          &,                   DT * );
     383forall( DT & ) const DT *               ?=?( const           DT * volatile &,                   DT * );
     384forall( DT & ) const DT *               ?=?( const           DT *          &, const             DT * );
     385forall( DT & ) const DT *               ?=?( const           DT * volatile &, const             DT * );
     386forall( DT & ) volatile DT *    ?=?(       volatile  DT *          &,                   DT * );
     387forall( DT & ) volatile DT *    ?=?(       volatile  DT * volatile &,                   DT * );
     388forall( DT & ) volatile DT *    ?=?(       volatile  DT *          &,       volatile    DT * );
     389forall( DT & ) volatile DT *    ?=?(       volatile  DT * volatile &,       volatile    DT * );
     390
     391forall( DT & ) const volatile DT *      ?=?( const volatile  DT *          &,                   DT * );
     392forall( DT & ) const volatile DT *  ?=?( const volatile  DT * volatile &,                       DT * );
     393forall( DT & ) const volatile DT *  ?=?( const volatile  DT *      &, const             DT * );
     394forall( DT & ) const volatile DT *  ?=?( const volatile  DT * volatile &, const         DT * );
     395forall( DT & ) const volatile DT *  ?=?( const volatile  DT *      &,       volatile    DT * );
     396forall( DT & ) const volatile DT *  ?=?( const volatile  DT * volatile &,           volatile    DT * );
     397forall( DT & ) const volatile DT *  ?=?( const volatile  DT *      &, const volatile    DT * );
     398forall( DT & ) const volatile DT *  ?=?( const volatile  DT * volatile &, const volatile        DT * );
     399
     400forall( DT & ) void *            ?=?(                void *          &,                 DT * );
     401forall( DT & ) void *            ?=?(                void * volatile &,                 DT * );
     402forall( DT & ) const void *              ?=?( const          void *          &,                 DT * );
     403forall( DT & ) const void *              ?=?( const          void * volatile &,                 DT * );
     404forall( DT & ) const void *              ?=?( const          void *          &, const           DT * );
     405forall( DT & ) const void *              ?=?( const          void * volatile &, const           DT * );
     406forall( DT & ) volatile void *   ?=?(       volatile void *          &,                 DT * );
     407forall( DT & ) volatile void *   ?=?(       volatile void * volatile &,                 DT * );
     408forall( DT & ) volatile void *   ?=?(       volatile void *          &,       volatile  DT * );
     409forall( DT & ) volatile void *   ?=?(       volatile void * volatile &,       volatile  DT * );
     410forall( DT & ) const volatile void * ?=?( const volatile void *      &,                 DT * );
     411forall( DT & ) const volatile void * ?=?( const volatile void * volatile &,                     DT * );
     412forall( DT & ) const volatile void * ?=?( const volatile void *      &, const           DT * );
     413forall( DT & ) const volatile void * ?=?( const volatile void * volatile &, const               DT * );
     414forall( DT & ) const volatile void * ?=?( const volatile void *      &,       volatile  DT * );
     415forall( DT & ) const volatile void * ?=?( const volatile void * volatile &,           volatile  DT * );
     416forall( DT & ) const volatile void * ?=?( const volatile void *      &, const volatile  DT * );
     417forall( DT & ) const volatile void * ?=?( const volatile void * volatile &, const volatile      DT * );
    418418
    419419//forall( dtype DT ) DT *                       ?=?(                DT *          &, zero_t );
    420420//forall( dtype DT ) DT *                       ?=?(                DT * volatile &, zero_t );
    421 forall( dtype DT ) const DT *           ?=?( const          DT *          &, zero_t );
    422 forall( dtype DT ) const DT *           ?=?( const          DT * volatile &, zero_t );
     421forall( DT & ) const DT *               ?=?( const          DT *          &, zero_t );
     422forall( DT & ) const DT *               ?=?( const          DT * volatile &, zero_t );
    423423//forall( dtype DT ) volatile DT *      ?=?( volatile       DT *          &, zero_t );
    424424//forall( dtype DT ) volatile DT *      ?=?( volatile       DT * volatile &, zero_t );
    425 forall( dtype DT ) const volatile DT *  ?=?( const volatile DT *          &, zero_t );
    426 forall( dtype DT ) const volatile DT *  ?=?( const volatile DT * volatile &, zero_t );
     425forall( DT & ) const volatile DT *      ?=?( const volatile DT *          &, zero_t );
     426forall( DT & ) const volatile DT *      ?=?( const volatile DT * volatile &, zero_t );
    427427
    428428forall( ftype FT ) FT *                 ?=?( FT *          &, zero_t );
    429429forall( ftype FT ) FT *                 ?=?( FT * volatile &, zero_t );
    430430
    431 forall( dtype T | sized(T) ) T *                ?+=?(                T *          &, ptrdiff_t );
    432 forall( dtype T | sized(T) ) T *                ?+=?(                T * volatile &, ptrdiff_t );
    433 forall( dtype T | sized(T) ) const T *          ?+=?( const          T *          &, ptrdiff_t );
    434 forall( dtype T | sized(T) ) const T *          ?+=?( const          T * volatile &, ptrdiff_t );
    435 forall( dtype T | sized(T) ) volatile T *       ?+=?(       volatile T *          &, ptrdiff_t );
    436 forall( dtype T | sized(T) ) volatile T *       ?+=?(       volatile T * volatile &, ptrdiff_t );
    437 forall( dtype T | sized(T) ) const volatile T * ?+=?( const volatile T *          &, ptrdiff_t );
    438 forall( dtype T | sized(T) ) const volatile T * ?+=?( const volatile T * volatile &, ptrdiff_t );
    439 forall( dtype T | sized(T) ) T *                ?-=?(                T *          &, ptrdiff_t );
    440 forall( dtype T | sized(T) ) T *                ?-=?(                T * volatile &, ptrdiff_t );
    441 forall( dtype T | sized(T) ) const T *          ?-=?( const          T *          &, ptrdiff_t );
    442 forall( dtype T | sized(T) ) const T *          ?-=?( const          T * volatile &, ptrdiff_t );
    443 forall( dtype T | sized(T) ) volatile T *       ?-=?(       volatile T *          &, ptrdiff_t );
    444 forall( dtype T | sized(T) ) volatile T *       ?-=?(       volatile T * volatile &, ptrdiff_t );
    445 forall( dtype T | sized(T) ) const volatile T * ?-=?( const volatile T *          &, ptrdiff_t );
    446 forall( dtype T | sized(T) ) const volatile T * ?-=?( const volatile T * volatile &, ptrdiff_t );
     431forall( T & | sized(T) ) T *            ?+=?(                T *          &, ptrdiff_t );
     432forall( T & | sized(T) ) T *            ?+=?(                T * volatile &, ptrdiff_t );
     433forall( T & | sized(T) ) const T *              ?+=?( const          T *          &, ptrdiff_t );
     434forall( T & | sized(T) ) const T *              ?+=?( const          T * volatile &, ptrdiff_t );
     435forall( T & | sized(T) ) volatile T *   ?+=?(       volatile T *          &, ptrdiff_t );
     436forall( T & | sized(T) ) volatile T *   ?+=?(       volatile T * volatile &, ptrdiff_t );
     437forall( T & | sized(T) ) const volatile T *     ?+=?( const volatile T *          &, ptrdiff_t );
     438forall( T & | sized(T) ) const volatile T *     ?+=?( const volatile T * volatile &, ptrdiff_t );
     439forall( T & | sized(T) ) T *            ?-=?(                T *          &, ptrdiff_t );
     440forall( T & | sized(T) ) T *            ?-=?(                T * volatile &, ptrdiff_t );
     441forall( T & | sized(T) ) const T *              ?-=?( const          T *          &, ptrdiff_t );
     442forall( T & | sized(T) ) const T *              ?-=?( const          T * volatile &, ptrdiff_t );
     443forall( T & | sized(T) ) volatile T *   ?-=?(       volatile T *          &, ptrdiff_t );
     444forall( T & | sized(T) ) volatile T *   ?-=?(       volatile T * volatile &, ptrdiff_t );
     445forall( T & | sized(T) ) const volatile T *     ?-=?( const volatile T *          &, ptrdiff_t );
     446forall( T & | sized(T) ) const volatile T *     ?-=?( const volatile T * volatile &, ptrdiff_t );
    447447
    448448_Bool                   ?=?( _Bool &, _Bool ),                                  ?=?( volatile _Bool &, _Bool );
     
    723723forall( ftype FT ) void ?{}( FT * volatile &, FT * );
    724724
    725 forall( dtype DT ) void ?{}(                 DT *          &,                   DT * );
    726 forall( dtype DT ) void ?{}( const           DT *          &,                   DT * );
    727 forall( dtype DT ) void ?{}( const           DT *          &, const             DT * );
    728 forall( dtype DT ) void ?{}(       volatile  DT *          &,                   DT * );
    729 forall( dtype DT ) void ?{}(       volatile  DT *          &,       volatile    DT * );
    730 forall( dtype DT ) void ?{}( const volatile  DT *          &,                   DT * );
    731 forall( dtype DT ) void ?{}( const volatile  DT *          &, const             DT * );
    732 forall( dtype DT ) void ?{}( const volatile  DT *          &,       volatile    DT * );
    733 forall( dtype DT ) void ?{}( const volatile  DT *          &, const volatile    DT * );
    734 
    735 forall( dtype DT ) void ?{}(                 void *          &,                 DT * );
    736 forall( dtype DT ) void ?{}( const           void *          &,                 DT * );
    737 forall( dtype DT ) void ?{}( const           void *          &, const           DT * );
    738 forall( dtype DT ) void ?{}(        volatile void *          &,                 DT * );
    739 forall( dtype DT ) void ?{}(        volatile void *          &,       volatile  DT * );
    740 forall( dtype DT ) void ?{}( const volatile void *           &,                 DT * );
    741 forall( dtype DT ) void ?{}( const volatile void *           &, const           DT * );
    742 forall( dtype DT ) void ?{}( const volatile void *           &,       volatile  DT * );
    743 forall( dtype DT ) void ?{}( const volatile void *           &, const volatile  DT * );
     725forall( DT & ) void ?{}(                     DT *          &,                   DT * );
     726forall( DT & ) void ?{}( const       DT *          &,                   DT * );
     727forall( DT & ) void ?{}( const       DT *          &, const             DT * );
     728forall( DT & ) void ?{}(           volatile  DT *          &,                   DT * );
     729forall( DT & ) void ?{}(           volatile  DT *          &,       volatile    DT * );
     730forall( DT & ) void ?{}( const volatile  DT *      &,                   DT * );
     731forall( DT & ) void ?{}( const volatile  DT *      &, const             DT * );
     732forall( DT & ) void ?{}( const volatile  DT *      &,       volatile    DT * );
     733forall( DT & ) void ?{}( const volatile  DT *      &, const volatile    DT * );
     734
     735forall( DT & ) void ?{}(                     void *          &,                 DT * );
     736forall( DT & ) void ?{}( const       void *          &,                 DT * );
     737forall( DT & ) void ?{}( const       void *          &, const           DT * );
     738forall( DT & ) void ?{}(            volatile void *          &,                 DT * );
     739forall( DT & ) void ?{}(            volatile void *          &,       volatile  DT * );
     740forall( DT & ) void ?{}( const volatile void *       &,                 DT * );
     741forall( DT & ) void ?{}( const volatile void *       &, const           DT * );
     742forall( DT & ) void ?{}( const volatile void *       &,       volatile  DT * );
     743forall( DT & ) void ?{}( const volatile void *       &, const volatile  DT * );
    744744
    745745//forall( dtype DT ) void ?{}(              DT *          &, zero_t );
    746746//forall( dtype DT ) void ?{}(              DT * volatile &, zero_t );
    747 forall( dtype DT ) void ?{}( const          DT *          &, zero_t );
     747forall( DT & ) void ?{}( const      DT *          &, zero_t );
    748748//forall( dtype DT ) void ?{}( volatile     DT *          &, zero_t );
    749749//forall( dtype DT ) void ?{}( volatile     DT * volatile &, zero_t );
    750 forall( dtype DT ) void ?{}( const volatile DT *          &, zero_t );
     750forall( DT & ) void ?{}( const volatile DT *      &, zero_t );
    751751
    752752forall( ftype FT ) void ?{}( FT *          &, zero_t );
     
    755755forall( ftype FT ) void ?{}( FT *          & );
    756756
    757 forall( dtype DT ) void ?{}(                 DT *          &);
    758 forall( dtype DT ) void ?{}( const           DT *          &);
    759 forall( dtype DT ) void ?{}(       volatile  DT *          &);
    760 forall( dtype DT ) void ?{}( const volatile  DT *          &);
     757forall( DT & ) void     ?{}(                 DT *          &);
     758forall( DT & ) void     ?{}( const           DT *          &);
     759forall( DT & ) void     ?{}(       volatile  DT *          &);
     760forall( DT & ) void ?{}( const volatile  DT *      &);
    761761
    762762void    ?{}(                void *          &);
     
    768768forall( ftype FT ) void ^?{}( FT *         & );
    769769
    770 forall( dtype DT ) void ^?{}(                DT *          &);
    771 forall( dtype DT ) void ^?{}( const          DT *          &);
    772 forall( dtype DT ) void ^?{}(      volatile  DT *          &);
    773 forall( dtype DT ) void ^?{}( const volatile  DT *         &);
     770forall( DT & ) void     ^?{}(                DT *          &);
     771forall( DT & ) void     ^?{}( const          DT *          &);
     772forall( DT & ) void     ^?{}(      volatile  DT *          &);
     773forall( DT & ) void ^?{}( const volatile  DT *     &);
    774774
    775775void ^?{}(                  void *          &);
  • libcfa/prelude/sync-builtins.cf

    rb6a8b31 rd95969a  
    206206_Bool __sync_bool_compare_and_swap(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
    207207#endif
    208 forall(dtype T) _Bool __sync_bool_compare_and_swap(T * volatile *, T *, T*, ...);
     208forall(T &) _Bool __sync_bool_compare_and_swap(T * volatile *, T *, T*, ...);
    209209
    210210char __sync_val_compare_and_swap(volatile char *, char, char,...);
     
    223223unsigned __int128 __sync_val_compare_and_swap(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
    224224#endif
    225 forall(dtype T) T * __sync_val_compare_and_swap(T * volatile *, T *, T*,...);
     225forall(T &) T * __sync_val_compare_and_swap(T * volatile *, T *, T*,...);
    226226
    227227char __sync_lock_test_and_set(volatile char *, char,...);
     
    326326void __atomic_exchange(volatile unsigned __int128 *, volatile unsigned __int128 *, volatile unsigned __int128 *, int);
    327327#endif
    328 forall(dtype T) T * __atomic_exchange_n(T * volatile *, T *, int);
    329 forall(dtype T) void __atomic_exchange(T * volatile *, T * volatile *, T * volatile *, int);
     328forall(T &) T * __atomic_exchange_n(T * volatile *, T *, int);
     329forall(T &) void __atomic_exchange(T * volatile *, T * volatile *, T * volatile *, int);
    330330
    331331_Bool __atomic_load_n(const volatile _Bool *, int);
     
    359359void __atomic_load(const volatile unsigned __int128 *, volatile unsigned __int128 *, int);
    360360#endif
    361 forall(dtype T) T * __atomic_load_n(T * const volatile *, int);
    362 forall(dtype T) void __atomic_load(T * const volatile *, T **, int);
     361forall(T &) T * __atomic_load_n(T * const volatile *, int);
     362forall(T &) void __atomic_load(T * const volatile *, T **, int);
    363363
    364364_Bool __atomic_compare_exchange_n(volatile char *, char *, char, _Bool, int, int);
     
    390390_Bool __atomic_compare_exchange   (volatile unsigned __int128 *, unsigned __int128 *, unsigned __int128 *, _Bool, int, int);
    391391#endif
    392 forall(dtype T) _Bool __atomic_compare_exchange_n (T * volatile *, T **, T*, _Bool, int, int);
    393 forall(dtype T) _Bool __atomic_compare_exchange   (T * volatile *, T **, T**, _Bool, int, int);
     392forall(T &) _Bool __atomic_compare_exchange_n (T * volatile *, T **, T*, _Bool, int, int);
     393forall(T &) _Bool __atomic_compare_exchange   (T * volatile *, T **, T**, _Bool, int, int);
    394394
    395395void __atomic_store_n(volatile _Bool *, _Bool, int);
     
    423423void __atomic_store(volatile unsigned __int128 *, unsigned __int128 *, int);
    424424#endif
    425 forall(dtype T) void __atomic_store_n(T * volatile *, T *, int);
    426 forall(dtype T) void __atomic_store(T * volatile *, T **, int);
     425forall(T &) void __atomic_store_n(T * volatile *, T *, int);
     426forall(T &) void __atomic_store(T * volatile *, T **, int);
    427427
    428428char __atomic_add_fetch  (volatile char *, char, int);
  • libcfa/src/Makefile.am

    rb6a8b31 rd95969a  
    7676        stdlib.hfa \
    7777        time.hfa \
     78        bits/weakso_locks.hfa \
    7879        containers/maybe.hfa \
    7980        containers/pair.hfa \
  • libcfa/src/bitmanip.hfa

    rb6a8b31 rd95969a  
    100100        unsigned long long int floor2( unsigned long long int n, unsigned long long int align ) { verify( is_pow2( align ) ); return n & -align; }
    101101
    102         // forall( otype T | { T ?&?( T, T ); T -?( T ); } )
     102        // forall( T | { T ?&?( T, T ); T -?( T ); } )
    103103        // T floor2( T n, T align ) { verify( is_pow2( align ) ); return n & -align; }
    104104
     
    115115        unsigned long long int ceiling2( unsigned long long int n, unsigned long long int align ) { verify( is_pow2( align ) ); return -floor2( -n, align ); }
    116116
    117         // forall( otype T | { T floor2( T, T ); T -?( T ); } )
     117        // forall( T | { T floor2( T, T ); T -?( T ); } )
    118118        // T ceiling2( T n, T align ) { verify( is_pow2( align ) ); return -floor2( -n, align ); }
    119119} // distribution
  • libcfa/src/bits/algorithm.hfa

    rb6a8b31 rd95969a  
    1717
    1818#ifdef SAFE_SORT
    19 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sort2( T * arr );
    20 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sort3( T * arr );
    21 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sort4( T * arr );
    22 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sort5( T * arr );
    23 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sort6( T * arr );
    24 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sortN( T * arr, size_t dim );
     19forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sort2( T * arr );
     20forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sort3( T * arr );
     21forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sort4( T * arr );
     22forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sort5( T * arr );
     23forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sort6( T * arr );
     24forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } ) static inline void __libcfa_small_sortN( T * arr, size_t dim );
    2525
    26 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } )
     26forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } )
    2727static inline void __libcfa_small_sort( T * arr, size_t dim ) {
    2828        switch( dim ) {
     
    4141#define SWAP(x,y) { T a = min(arr[x], arr[y]); T b = max(arr[x], arr[y]); arr[x] = a; arr[y] = b;}
    4242
    43 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } )
     43forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } )
    4444static inline void __libcfa_small_sort2( T * arr ) {
    4545        SWAP(0, 1);
    4646}
    4747
    48 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } )
     48forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } )
    4949static inline void __libcfa_small_sort3( T * arr ) {
    5050        SWAP(1, 2);
     
    5353}
    5454
    55 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } )
     55forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } )
    5656static inline void __libcfa_small_sort4( T * arr ) {
    5757        SWAP(0, 1);
     
    6262}
    6363
    64 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } )
     64forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } )
    6565static inline void __libcfa_small_sort5( T * arr ) {
    6666        SWAP(0, 1);
     
    7575}
    7676
    77 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } )
     77forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } )
    7878static inline void __libcfa_small_sort6( T * arr ) {
    7979        SWAP(1, 2);
     
    9191}
    9292
    93 forall( otype T | {  int ?<?( T, T ); int ?>?( T, T ); } )
     93forall( T | {  int ?<?( T, T ); int ?>?( T, T ); } )
    9494static inline void __libcfa_small_sortN( T * arr, size_t dim ) {
    9595        int i, j;
     
    112112static inline void __libcfa_small_sortN( void* * arr, size_t dim );
    113113
    114 forall( dtype T )
     114forall( T & )
    115115static inline void __libcfa_small_sort( T* * arr, size_t dim ) {
    116116        switch( dim ) {
  • libcfa/src/bits/collection.hfa

    rb6a8b31 rd95969a  
     1//
     2// Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
     3//
     4// The contents of this file are covered under the licence agreement in the
     5// file "LICENCE" distributed with Cforall.
     6//
     7// bits/collection.hfa -- PUBLIC
     8// Intrusive singly-linked list
     9//
     10// Author           : Colby Alexander Parsons & Peter A. Buhr
     11// Created On       : Thu Jan 21 19:46:50 2021
     12// Last Modified By :
     13// Last Modified On :
     14// Update Count     :
     15//
     16
    117#pragma once
    2 #include <stdio.h> // REMOVE THIS AFTER DEBUGGING
    3 
    418
    519struct Colable {
    6         struct Colable * next;                                                                          // next node in the list
     20        // next node in the list
    721        // invariant: (next != 0) <=> listed()
     22        struct Colable * next;
    823};
    924#ifdef __cforall
     
    3146
    3247        // // wrappers to make Collection have T
    33         // forall( dtype T ) {
     48        // forall( T & ) {
    3449        //      T *& Next( T * n ) {
    3550        //              return (T *)Next( (Colable *)n );
     
    3853} // distribution
    3954
    40 forall( dtype T | { T *& Next ( T * ); } ) {
     55static inline forall( T & | { T *& Next ( T * ); } ) {
    4156        bool listed( T * n ) {
    4257                return Next( n ) != 0p;
     
    5368        Collection & ?=?( const Collection & ) = void;          // no assignment
    5469
    55         void ?{}( Collection & collection ) with( collection ) {       
     70        void ?{}( Collection & collection ) with( collection ) {
    5671                root = 0p;
    5772        } // post: empty()
     
    7691        } // post: elts = null
    7792
    78         forall( dtype T ) {
     93        forall( T & ) {
    7994                T * Curr( ColIter & ci ) with( ci ) {
    8095                        return (T *)curr;
  • libcfa/src/bits/containers.hfa

    rb6a8b31 rd95969a  
    2323
    2424#ifdef __cforall
    25         forall(dtype T)
     25        forall(T &)
    2626#else
    2727        #define T void
     
    4040
    4141#ifdef __cforall
    42         // forall(otype T | sized(T))
     42        // forall(T | sized(T))
    4343        // static inline void ?{}(__small_array(T) & this) {}
    4444
    45         forall(dtype T | sized(T))
     45        forall(T & | sized(T))
    4646        static inline T & ?[?]( __small_array(T) & this, __lock_size_t idx ) {
    4747                return ((typeof(this.data))this.data)[idx];
    4848        }
    4949
    50         forall(dtype T | sized(T))
     50        forall(T & | sized(T))
    5151        static inline T & ?[?]( const __small_array(T) & this, __lock_size_t idx ) {
    5252                return ((typeof(this.data))this.data)[idx];
    5353        }
    5454
    55         forall(dtype T)
     55        forall(T &)
    5656        static inline T * begin( const __small_array(T) & this ) {
    5757                return ((typeof(this.data))this.data);
    5858        }
    5959
    60         forall(dtype T | sized(T))
     60        forall(T & | sized(T))
    6161        static inline T * end( const __small_array(T) & this ) {
    6262                return ((typeof(this.data))this.data) + this.size;
     
    6969
    7070#ifdef __cforall
    71         trait is_node(dtype T) {
     71        trait is_node(T &) {
    7272                T *& get_next( T & );
    7373        };
     
    7878//-----------------------------------------------------------------------------
    7979#ifdef __cforall
    80         forall(dtype TYPE)
     80        forall(TYPE &)
    8181        #define T TYPE
    8282#else
     
    9595
    9696#ifdef __cforall
    97         forall(dtype T)
     97        forall(T &)
    9898        static inline void ?{}( __stack(T) & this ) {
    9999                (this.top){ 0p };
    100100        }
    101101
    102         static inline forall( dtype T | is_node(T) ) {
     102        static inline forall( T & | is_node(T) ) {
    103103                void push( __stack(T) & this, T * val ) {
    104104                        verify( !get_next( *val ) );
     
    126126//-----------------------------------------------------------------------------
    127127#ifdef __cforall
    128         forall(dtype TYPE)
     128        forall(TYPE &)
    129129        #define T TYPE
    130130#else
     
    144144
    145145#ifdef __cforall
    146         static inline forall( dtype T | is_node(T) ) {
     146        static inline forall( T & | is_node(T) ) {
    147147                void ?{}( __queue(T) & this ) with( this ) {
    148148                        (this.head){ 1p };
     
    215215//-----------------------------------------------------------------------------
    216216#ifdef __cforall
    217         forall(dtype TYPE)
     217        forall(TYPE &)
    218218        #define T TYPE
    219219        #define __getter_t * [T * & next, T * & prev] ( T & )
     
    237237
    238238#ifdef __cforall
    239         forall(dtype T )
     239        forall(T & )
    240240        static inline [void] ?{}( __dllist(T) & this, * [T * & next, T * & prev] ( T & ) __get ) {
    241241                (this.head){ 0p };
     
    245245        #define next 0
    246246        #define prev 1
    247         static inline forall(dtype T) {
     247        static inline forall(T &) {
    248248                void push_front( __dllist(T) & this, T & node ) with( this ) {
    249249                        verify(__get);
  • libcfa/src/bits/defs.hfa

    rb6a8b31 rd95969a  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // defs.hfa --
     7// defs.hfa -- Commen macros, functions and typedefs
     8// Most files depend on them and they are always useful to have.
     9//
     10//  *** Must not contain code specific to libcfathread ***
    811//
    912// Author           : Thierry Delisle
     
    6265        #endif
    6366}
     67
     68// pause to prevent excess processor bus usage
     69#if defined( __i386 ) || defined( __x86_64 )
     70        #define Pause() __asm__ __volatile__ ( "pause" : : : )
     71#elif defined( __ARM_ARCH )
     72        #define Pause() __asm__ __volatile__ ( "YIELD" : : : )
     73#else
     74        #error unsupported architecture
     75#endif
  • libcfa/src/bits/locks.hfa

    rb6a8b31 rd95969a  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // bits/locks.hfa -- Fast internal locks.
     7// bits/locks.hfa -- Basic spinlocks that are reused in the system.
     8// Used for locks that aren't specific to cforall threads and can be used anywhere
     9//
     10//  *** Must not contain code specific to libcfathread ***
    811//
    912// Author           : Thierry Delisle
     
    1922#include "bits/defs.hfa"
    2023#include <assert.h>
    21 
    22 #ifdef __cforall
    23         extern "C" {
    24                 #include <pthread.h>
    25         }
    26 #endif
    27 
    28 // pause to prevent excess processor bus usage
    29 #if defined( __i386 ) || defined( __x86_64 )
    30         #define Pause() __asm__ __volatile__ ( "pause" : : : )
    31 #elif defined( __ARM_ARCH )
    32         #define Pause() __asm__ __volatile__ ( "YIELD" : : : )
    33 #else
    34         #error unsupported architecture
    35 #endif
    3624
    3725struct __spinlock_t {
     
    10492                enable_interrupts_noPoll();
    10593        }
    106 
    107 
    108         #ifdef __CFA_WITH_VERIFY__
    109                 extern bool __cfaabi_dbg_in_kernel();
    110         #endif
    111 
    112         extern "C" {
    113                 char * strerror(int);
    114         }
    115         #define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); }
    116 
    117         struct __bin_sem_t {
    118                 pthread_mutex_t         lock;
    119                 pthread_cond_t          cond;
    120                 int                     val;
    121         };
    122 
    123         static inline void ?{}(__bin_sem_t & this) with( this ) {
    124                 // Create the mutex with error checking
    125                 pthread_mutexattr_t mattr;
    126                 pthread_mutexattr_init( &mattr );
    127                 pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP);
    128                 pthread_mutex_init(&lock, &mattr);
    129 
    130                 pthread_cond_init (&cond, (const pthread_condattr_t *)0p);  // workaround trac#208: cast should not be required
    131                 val = 0;
    132         }
    133 
    134         static inline void ^?{}(__bin_sem_t & this) with( this ) {
    135                 CHECKED( pthread_mutex_destroy(&lock) );
    136                 CHECKED( pthread_cond_destroy (&cond) );
    137         }
    138 
    139         static inline void wait(__bin_sem_t & this) with( this ) {
    140                 verify(__cfaabi_dbg_in_kernel());
    141                 CHECKED( pthread_mutex_lock(&lock) );
    142                         while(val < 1) {
    143                                 pthread_cond_wait(&cond, &lock);
    144                         }
    145                         val -= 1;
    146                 CHECKED( pthread_mutex_unlock(&lock) );
    147         }
    148 
    149         static inline bool post(__bin_sem_t & this) with( this ) {
    150                 bool needs_signal = false;
    151 
    152                 CHECKED( pthread_mutex_lock(&lock) );
    153                         if(val < 1) {
    154                                 val += 1;
    155                                 pthread_cond_signal(&cond);
    156                                 needs_signal = true;
    157                         }
    158                 CHECKED( pthread_mutex_unlock(&lock) );
    159 
    160                 return needs_signal;
    161         }
    162 
    163         #undef CHECKED
    164 
    165         struct $thread;
    166         extern void park( void );
    167         extern void unpark( struct $thread * this );
    168         static inline struct $thread * active_thread ();
    169 
    170         // Semaphore which only supports a single thread
    171         struct single_sem {
    172                 struct $thread * volatile ptr;
    173         };
    174 
    175         static inline {
    176                 void  ?{}(single_sem & this) {
    177                         this.ptr = 0p;
    178                 }
    179 
    180                 void ^?{}(single_sem &) {}
    181 
    182                 bool wait(single_sem & this) {
    183                         for() {
    184                                 struct $thread * expected = this.ptr;
    185                                 if(expected == 1p) {
    186                                         if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    187                                                 return false;
    188                                         }
    189                                 }
    190                                 else {
    191                                         /* paranoid */ verify( expected == 0p );
    192                                         if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    193                                                 park();
    194                                                 return true;
    195                                         }
    196                                 }
    197 
    198                         }
    199                 }
    200 
    201                 bool post(single_sem & this) {
    202                         for() {
    203                                 struct $thread * expected = this.ptr;
    204                                 if(expected == 1p) return false;
    205                                 if(expected == 0p) {
    206                                         if(__atomic_compare_exchange_n(&this.ptr, &expected, 1p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    207                                                 return false;
    208                                         }
    209                                 }
    210                                 else {
    211                                         if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    212                                                 unpark( expected );
    213                                                 return true;
    214                                         }
    215                                 }
    216                         }
    217                 }
    218         }
    219 
    220         // Synchronozation primitive which only supports a single thread and one post
    221         // Similar to a binary semaphore with a 'one shot' semantic
    222         // is expected to be discarded after each party call their side
    223         struct oneshot {
    224                 // Internal state :
    225                 //     0p     : is initial state (wait will block)
    226                 //     1p     : fulfilled (wait won't block)
    227                 // any thread : a thread is currently waiting
    228                 struct $thread * volatile ptr;
    229         };
    230 
    231         static inline {
    232                 void  ?{}(oneshot & this) {
    233                         this.ptr = 0p;
    234                 }
    235 
    236                 void ^?{}(oneshot &) {}
    237 
    238                 // Wait for the post, return immidiately if it already happened.
    239                 // return true if the thread was parked
    240                 bool wait(oneshot & this) {
    241                         for() {
    242                                 struct $thread * expected = this.ptr;
    243                                 if(expected == 1p) return false;
    244                                 /* paranoid */ verify( expected == 0p );
    245                                 if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    246                                         park();
    247                                         /* paranoid */ verify( this.ptr == 1p );
    248                                         return true;
    249                                 }
    250                         }
    251                 }
    252 
    253                 // Mark as fulfilled, wake thread if needed
    254                 // return true if a thread was unparked
    255                 bool post(oneshot & this) {
    256                         struct $thread * got = __atomic_exchange_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
    257                         if( got == 0p ) return false;
    258                         unpark( got );
    259                         return true;
    260                 }
    261         }
    262 
    263         // base types for future to build upon
    264         // It is based on the 'oneshot' type to allow multiple futures
    265         // to block on the same instance, permitting users to block a single
    266         // thread on "any of" [a given set of] futures.
    267         // does not support multiple threads waiting on the same future
    268         struct future_t {
    269                 // Internal state :
    270                 //     0p      : is initial state (wait will block)
    271                 //     1p      : fulfilled (wait won't block)
    272                 //     2p      : in progress ()
    273                 //     3p      : abandoned, server should delete
    274                 // any oneshot : a context has been setup to wait, a thread could wait on it
    275                 struct oneshot * volatile ptr;
    276         };
    277 
    278         static inline {
    279                 void  ?{}(future_t & this) {
    280                         this.ptr = 0p;
    281                 }
    282 
    283                 void ^?{}(future_t &) {}
    284 
    285                 void reset(future_t & this) {
    286                         // needs to be in 0p or 1p
    287                         __atomic_exchange_n( &this.ptr, 0p, __ATOMIC_SEQ_CST);
    288                 }
    289 
    290                 // check if the future is available
    291                 bool available( future_t & this ) {
    292                         return this.ptr == 1p;
    293                 }
    294 
    295                 // Prepare the future to be waited on
    296                 // intented to be use by wait, wait_any, waitfor, etc. rather than used directly
    297                 bool setup( future_t & this, oneshot & wait_ctx ) {
    298                         /* paranoid */ verify( wait_ctx.ptr == 0p );
    299                         // The future needs to set the wait context
    300                         for() {
    301                                 struct oneshot * expected = this.ptr;
    302                                 // Is the future already fulfilled?
    303                                 if(expected == 1p) return false; // Yes, just return false (didn't block)
    304 
    305                                 // The future is not fulfilled, try to setup the wait context
    306                                 /* paranoid */ verify( expected == 0p );
    307                                 if(__atomic_compare_exchange_n(&this.ptr, &expected, &wait_ctx, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    308                                         return true;
    309                                 }
    310                         }
    311                 }
    312 
    313                 // Stop waiting on a future
    314                 // When multiple futures are waited for together in "any of" pattern
    315                 // futures that weren't fulfilled before the thread woke up
    316                 // should retract the wait ctx
    317                 // intented to be use by wait, wait_any, waitfor, etc. rather than used directly
    318                 void retract( future_t & this, oneshot & wait_ctx ) {
    319                         // Remove the wait context
    320                         struct oneshot * got = __atomic_exchange_n( &this.ptr, 0p, __ATOMIC_SEQ_CST);
    321 
    322                         // got == 0p: future was never actually setup, just return
    323                         if( got == 0p ) return;
    324 
    325                         // got == wait_ctx: since fulfil does an atomic_swap,
    326                         // if we got back the original then no one else saw context
    327                         // It is safe to delete (which could happen after the return)
    328                         if( got == &wait_ctx ) return;
    329 
    330                         // got == 1p: the future is ready and the context was fully consumed
    331                         // the server won't use the pointer again
    332                         // It is safe to delete (which could happen after the return)
    333                         if( got == 1p ) return;
    334 
    335                         // got == 2p: the future is ready but the context hasn't fully been consumed
    336                         // spin until it is safe to move on
    337                         if( got == 2p ) {
    338                                 while( this.ptr != 1p ) Pause();
    339                                 return;
    340                         }
    341 
    342                         // got == any thing else, something wen't wrong here, abort
    343                         abort("Future in unexpected state");
    344                 }
    345 
    346                 // Mark the future as abandoned, meaning it will be deleted by the server
    347                 bool abandon( future_t & this ) {
    348                         /* paranoid */ verify( this.ptr != 3p );
    349 
    350                         // Mark the future as abandonned
    351                         struct oneshot * got = __atomic_exchange_n( &this.ptr, 3p, __ATOMIC_SEQ_CST);
    352 
    353                         // If the future isn't already fulfilled, let the server delete it
    354                         if( got == 0p ) return false;
    355 
    356                         // got == 2p: the future is ready but the context hasn't fully been consumed
    357                         // spin until it is safe to move on
    358                         if( got == 2p ) {
    359                                 while( this.ptr != 1p ) Pause();
    360                                 got = 1p;
    361                         }
    362 
    363                         // The future is completed delete it now
    364                         /* paranoid */ verify( this.ptr != 1p );
    365                         free( &this );
    366                         return true;
    367                 }
    368 
    369                 // from the server side, mark the future as fulfilled
    370                 // delete it if needed
    371                 bool fulfil( future_t & this ) {
    372                         for() {
    373                                 struct oneshot * expected = this.ptr;
    374                                 // was this abandoned?
    375                                 #if defined(__GNUC__) && __GNUC__ >= 7
    376                                         #pragma GCC diagnostic push
    377                                         #pragma GCC diagnostic ignored "-Wfree-nonheap-object"
    378                                 #endif
    379                                         if( expected == 3p ) { free( &this ); return false; }
    380                                 #if defined(__GNUC__) && __GNUC__ >= 7
    381                                         #pragma GCC diagnostic pop
    382                                 #endif
    383 
    384                                 /* paranoid */ verify( expected != 1p ); // Future is already fulfilled, should not happen
    385                                 /* paranoid */ verify( expected != 2p ); // Future is bein fulfilled by someone else, this is even less supported then the previous case.
    386 
    387                                 // If there is a wait context, we need to consume it and mark it as consumed after
    388                                 // If there is no context then we can skip the in progress phase
    389                                 struct oneshot * want = expected == 0p ? 1p : 2p;
    390                                 if(__atomic_compare_exchange_n(&this.ptr, &expected, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    391                                         if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return false; }
    392                                         bool ret = post( *expected );
    393                                         __atomic_store_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
    394                                         return ret;
    395                                 }
    396                         }
    397 
    398                 }
    399 
    400                 // Wait for the future to be fulfilled
    401                 bool wait( future_t & this ) {
    402                         oneshot temp;
    403                         if( !setup(this, temp) ) return false;
    404 
    405                         // Wait context is setup, just wait on it
    406                         bool ret = wait( temp );
    407 
    408                         // Wait for the future to tru
    409                         while( this.ptr == 2p ) Pause();
    410                         // Make sure the state makes sense
    411                         // Should be fulfilled, could be in progress but it's out of date if so
    412                         // since if that is the case, the oneshot was fulfilled (unparking this thread)
    413                         // and the oneshot should not be needed any more
    414                         __attribute__((unused)) struct oneshot * was = this.ptr;
    415                         /* paranoid */ verifyf( was == 1p, "Expected this.ptr to be 1p, was %p\n", was );
    416 
    417                         // Mark the future as fulfilled, to be consistent
    418                         // with potential calls to avail
    419                         // this.ptr = 1p;
    420                         return ret;
    421                 }
    422         }
    42394#endif
  • libcfa/src/bits/queue.hfa

    rb6a8b31 rd95969a  
    99// instead of being null.
    1010
    11 forall( dtype T | { T *& Next ( T * ); } ) {
     11forall( T & | { T *& Next ( T * ); } ) {
    1212        struct Queue {
    1313                inline Collection;                                                              // Plan 9 inheritance
     
    151151} // distribution
    152152
    153 forall( dtype T | { T *& Next ( T * ); } ) {
     153forall( T & | { T *& Next ( T * ); } ) {
    154154        struct QueueIter {
    155155                inline ColIter;                                                                 // Plan 9 inheritance
  • libcfa/src/bits/sequence.hfa

    rb6a8b31 rd95969a  
     1//
     2// Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
     3//
     4// The contents of this file are covered under the licence agreement in the
     5// file "LICENCE" distributed with Cforall.
     6//
     7// bits/sequence.hfa -- PUBLIC
     8// Intrusive doubly-linked list
     9//
     10// Author           : Colby Alexander Parsons & Peter A. Buhr
     11// Created On       : Thu Jan 21 19:46:50 2021
     12// Last Modified By :
     13// Last Modified On :
     14// Update Count     :
     15//
     16
    117#pragma once
    218
     
    622struct Seqable {
    723        __cfa_anonymous_object(Colable);
    8         struct Seqable * back;                                                                          // pointer to previous node in the list
     24        // pointer to previous node in the list
     25        struct Seqable * back;
    926};
    1027
     
    2744                return sq->back;
    2845        }
    29 
    30         // // wrappers to make Collection have T
    31         // forall( dtype T ) {
    32         //      T *& Back( T * n ) {
    33         //              return (T *)Back( (Seqable *)n );
    34         //      }
    35         // } // distribution
    3646} // distribution
    3747
     
    4353// and the back field of the last node points at the first node (circular).
    4454
    45 forall( dtype T | { T *& Back ( T * ); T *& Next ( T * ); } ) {
     55forall( T & ) {
    4656        struct Sequence {
    47                 inline Collection;                                                              // Plan 9 inheritance
     57                // Plan 9 inheritance
     58                inline Collection;
    4859        };
    4960
    5061        static inline {
     62                void ?{}( Sequence(T) &, const Sequence(T) & ) = void; // no copy
     63                Sequence(T) & ?=?( const Sequence(T) & ) = void; // no assignment
     64
     65                void ?{}( Sequence(T) & s ) with( s ) {
     66                        ((Collection &)s){};
     67                }       // post: isEmpty()
     68        }
     69
     70        static inline forall(| { T *& Back ( T * ); T *& Next ( T * ); }) {
    5171                // wrappers to make Collection have T
    5272                T & head( Sequence(T) & s ) with( s ) {
    5373                        return *(T *)head( (Collection &)s );
    5474                } // post: empty() & head() == 0 | !empty() & head() in *s
    55 
    56                 void ?{}( Sequence(T) &, const Sequence(T) & ) = void; // no copy
    57                 Sequence(T) & ?=?( const Sequence(T) & ) = void; // no assignment
    58 
    59                 void ?{}( Sequence(T) & s ) with( s ) {
    60                         ((Collection &)s){};
    61                 }       // post: isEmpty()
    6275
    6376                // Return a pointer to the last sequence element, without removing it.
     
    145158                        return n;
    146159                } // post: n->listed() & *n in *s & succ(n) == bef
    147                
     160
    148161                // pre: n->listed() & *n in *s
    149162                T & remove( Sequence(T) & s, T & n ) with( s ) { // O(1)
     
    231244} // distribution
    232245
    233 forall( dtype T | { T *& Back ( T * ); T *& Next ( T * ); } ) {
     246forall( T & | { T *& Back ( T * ); T *& Next ( T * ); } ) {
    234247        // SeqIter(T) is used to iterate over a Sequence(T) in head-to-tail order.
    235248        struct SeqIter {
     
    285298
    286299        static inline {
    287                 void ?{}( SeqIterRev(T) & si ) with( si ) {     
     300                void ?{}( SeqIterRev(T) & si ) with( si ) {
    288301                        ((ColIter &)si){};
    289302                        seq = 0p;
     
    291304
    292305                // Create a iterator active in sequence s.
    293                 void ?{}( SeqIterRev(T) & si, Sequence(T) & s ) with( si ) {   
     306                void ?{}( SeqIterRev(T) & si, Sequence(T) & s ) with( si ) {
    294307                        ((ColIter &)si){};
    295308                        seq = &s;
     
    297310                } // post: elts = null
    298311
    299                 void ?{}( SeqIterRev(T) & si, Sequence(T) & s, T & start ) with( si ) { 
     312                void ?{}( SeqIterRev(T) & si, Sequence(T) & s, T & start ) with( si ) {
    300313                        ((ColIter &)si){};
    301314                        seq = &s;
  • libcfa/src/bits/stack.hfa

    rb6a8b31 rd95969a  
    99// instead of being null.
    1010
    11 forall( dtype T | { T *& Next ( T * ); } ) {
     11forall( T & | { T *& Next ( T * ); } ) {
    1212        struct Stack {
    1313                inline Collection;                                                              // Plan 9 inheritance
     
    6767// order returned by drop().
    6868
    69 forall( dtype T | { T *& Next ( T * ); } ) {
     69forall( T & | { T *& Next ( T * ); } ) {
    7070        struct StackIter {
    7171                inline ColIter;                                                                 // Plan 9 inheritance
  • libcfa/src/common.cfa

    rb6a8b31 rd95969a  
    2323[ long int, long int ] div( long int num, long int denom ) { ldiv_t qr = ldiv( num, denom ); return [ qr.quot, qr.rem ]; }
    2424[ long long int, long long int ] div( long long int num, long long int denom ) { lldiv_t qr = lldiv( num, denom ); return [ qr.quot, qr.rem ]; }
    25 forall( otype T | { T ?/?( T, T ); T ?%?( T, T ); } )
     25forall( T | { T ?/?( T, T ); T ?%?( T, T ); } )
    2626[ T, T ] div( T num, T denom ) { return [ num / denom, num % denom ]; }
    2727
  • libcfa/src/common.hfa

    rb6a8b31 rd95969a  
    2121[ long int, long int ] div( long int num, long int denom );
    2222[ long long int, long long int ] div( long long int num, long long int denom );
    23 forall( otype T | { T ?/?( T, T ); T ?%?( T, T ); } )
     23forall( T | { T ?/?( T, T ); T ?%?( T, T ); } )
    2424[ T, T ] div( T num, T demon );
    2525
     
    6161} // distribution
    6262
    63 forall( otype T | { void ?{}( T &, zero_t ); int ?<?( T, T ); T -?( T ); } )
     63forall( T | { void ?{}( T &, zero_t ); int ?<?( T, T ); T -?( T ); } )
    6464T abs( T );
    6565
     
    7070        intptr_t min( intptr_t t1, intptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
    7171        uintptr_t min( uintptr_t t1, uintptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
    72         forall( otype T | { int ?<?( T, T ); } )
     72        forall( T | { int ?<?( T, T ); } )
    7373        T min( T t1, T t2 ) { return t1 < t2 ? t1 : t2; }
    7474
     
    7676        intptr_t max( intptr_t t1, intptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
    7777        uintptr_t max( uintptr_t t1, uintptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
    78         forall( otype T | { int ?>?( T, T ); } )
     78        forall( T | { int ?>?( T, T ); } )
    7979        T max( T t1, T t2 ) { return t1 > t2 ? t1 : t2; }
    8080
    81         forall( otype T | { T min( T, T ); T max( T, T ); } )
     81        forall( T | { T min( T, T ); T max( T, T ); } )
    8282        T clamp( T value, T min_val, T max_val ) { return max( min_val, min( value, max_val ) ); }
    8383
    84         forall( otype T )
     84        forall( T )
    8585        void swap( T & v1, T & v2 ) { T temp = v1; v1 = v2; v2 = temp; }
    8686} // distribution
  • libcfa/src/concurrency/coroutine.cfa

    rb6a8b31 rd95969a  
    4646
    4747//-----------------------------------------------------------------------------
    48 FORALL_DATA_INSTANCE(CoroutineCancelled, (dtype coroutine_t), (coroutine_t))
    49 
    50 forall(dtype T)
     48FORALL_DATA_INSTANCE(CoroutineCancelled, (coroutine_t &), (coroutine_t))
     49
     50forall(T &)
    5151void mark_exception(CoroutineCancelled(T) *) {}
    5252
    53 forall(dtype T)
     53forall(T &)
    5454void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {
    5555        dst->virtual_table = src->virtual_table;
     
    5858}
    5959
    60 forall(dtype T)
     60forall(T &)
    6161const char * msg(CoroutineCancelled(T) *) {
    6262        return "CoroutineCancelled(...)";
     
    6464
    6565// This code should not be inlined. It is the error path on resume.
    66 forall(dtype T | is_coroutine(T))
     66forall(T & | is_coroutine(T))
    6767void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ) {
    6868        verify( desc->cancellation );
     
    148148// Part of the Public API
    149149// Not inline since only ever called once per coroutine
    150 forall(dtype T | is_coroutine(T))
     150forall(T & | is_coroutine(T))
    151151void prime(T& cor) {
    152152        $coroutine* this = get_coroutine(cor);
  • libcfa/src/concurrency/coroutine.hfa

    rb6a8b31 rd95969a  
    2222//-----------------------------------------------------------------------------
    2323// Exception thrown from resume when a coroutine stack is cancelled.
    24 FORALL_DATA_EXCEPTION(CoroutineCancelled, (dtype coroutine_t), (coroutine_t)) (
     24FORALL_DATA_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (
    2525        coroutine_t * the_coroutine;
    2626        exception_t * the_exception;
    2727);
    2828
    29 forall(dtype T)
     29forall(T &)
    3030void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src);
    3131
    32 forall(dtype T)
     32forall(T &)
    3333const char * msg(CoroutineCancelled(T) *);
    3434
     
    3737// Anything that implements this trait can be resumed.
    3838// Anything that is resumed is a coroutine.
    39 trait is_coroutine(dtype T | IS_RESUMPTION_EXCEPTION(CoroutineCancelled, (T))) {
     39trait is_coroutine(T & | IS_RESUMPTION_EXCEPTION(CoroutineCancelled, (T))) {
    4040        void main(T & this);
    4141        $coroutine * get_coroutine(T & this);
     
    6060//-----------------------------------------------------------------------------
    6161// Public coroutine API
    62 forall(dtype T | is_coroutine(T))
     62forall(T & | is_coroutine(T))
    6363void prime(T & cor);
    6464
     
    7272        void __cfactx_invoke_coroutine(void (*main)(void *), void * this);
    7373
    74         forall(dtype T)
     74        forall(T &)
    7575        void __cfactx_start(void (*main)(T &), struct $coroutine * cor, T & this, void (*invoke)(void (*main)(void *), void *));
    7676
     
    129129}
    130130
    131 forall(dtype T | is_coroutine(T))
     131forall(T & | is_coroutine(T))
    132132void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc );
    133133
    134134// Resume implementation inlined for performance
    135 forall(dtype T | is_coroutine(T))
     135forall(T & | is_coroutine(T))
    136136static inline T & resume(T & cor) {
    137137        // optimization : read TLS once and reuse it
  • libcfa/src/concurrency/future.hfa

    rb6a8b31 rd95969a  
    1919#include "monitor.hfa"
    2020
    21 forall( otype T ) {
     21forall( T ) {
    2222        struct future {
    2323                inline future_t;
     
    5858}
    5959
    60 forall( otype T ) {
     60forall( T ) {
    6161        monitor multi_future {
    6262                inline future_t;
  • libcfa/src/concurrency/io.cfa

    rb6a8b31 rd95969a  
    4141        #include "io/types.hfa"
    4242
    43         static const char * opcodes[] = {
     43        __attribute__((unused)) static const char * opcodes[] = {
    4444                "OP_NOP",
    4545                "OP_READV",
     
    173173                        __cfadbg_print_safe(io_core, "Kernel I/O : IO_URING enter %d %u %u\n", ring.fd, to_submit, flags);
    174174                        ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, 0, flags, (sigset_t *)0p, _NSIG / 8);
     175                        __cfadbg_print_safe(io_core, "Kernel I/O : IO_URING %d returned %d\n", ring.fd, ret);
     176
    175177                        if( ret < 0 ) {
    176178                                switch((int)errno) {
    177179                                case EAGAIN:
    178180                                case EINTR:
     181                                case EBUSY:
    179182                                        ret = -1;
    180183                                        break;
     
    318321
    319322                __cfadbg_print_safe(io_core, "Kernel I/O : Fast poller %d (%p) stopping\n", this.ring->fd, &this);
     323
     324                __ioctx_unregister( this );
    320325        }
    321326
     
    389394
    390395                        block++;
    391 
    392                         abort( "Kernel I/O : all submit queue entries used, yielding\n" );
    393396
    394397                        yield();
     
    465468                                sqe->flags,
    466469                                sqe->ioprio,
    467                                 sqe->off,
    468                                 sqe->addr,
     470                                (void*)sqe->off,
     471                                (void*)sqe->addr,
    469472                                sqe->len,
    470473                                sqe->accept_flags,
     
    491494                }
    492495                else if( ring.eager_submits ) {
    493                         __u32 picked = __submit_to_ready_array( ring, idx, mask );
     496                        __attribute__((unused)) __u32 picked = __submit_to_ready_array( ring, idx, mask );
    494497
    495498                        #if defined(LEADER_LOCK)
     
    629632                                        sqe->flags,
    630633                                        sqe->ioprio,
    631                                         sqe->off,
    632                                         sqe->addr,
     634                                        (void*)sqe->off,
     635                                        (void*)sqe->addr,
    633636                                        sqe->len,
    634637                                        sqe->accept_flags,
     
    642645                        __atomic_thread_fence( __ATOMIC_SEQ_CST );
    643646                        // Release the consumed SQEs
     647
    644648                        __release_consumed_submission( ring );
    645649                        // ring.submit_q.sqes[idx].user_data = 3ul64;
  • libcfa/src/concurrency/io/setup.cfa

    rb6a8b31 rd95969a  
    4242        void ^?{}(io_context & this, bool cluster_context) {}
    4343
     44        void register_fixed_files( io_context &, int *, unsigned ) {}
     45        void register_fixed_files( cluster    &, int *, unsigned ) {}
     46
    4447#else
    4548        #include <errno.h>
     
    110113
    111114        static struct {
    112                 pthread_t     thrd;    // pthread handle to io poller thread
    113                 void *        stack;   // pthread stack for io poller thread
    114                 int           epollfd; // file descriptor to the epoll instance
    115                 volatile bool run;     // Whether or not to continue
     115                      pthread_t  thrd;    // pthread handle to io poller thread
     116                      void *     stack;   // pthread stack for io poller thread
     117                      int        epollfd; // file descriptor to the epoll instance
     118                volatile     bool run;     // Whether or not to continue
     119                volatile     bool stopped; // Whether the poller has finished running
     120                volatile uint64_t epoch;   // Epoch used for memory reclamation
    116121        } iopoll;
    117122
     
    126131                __cfadbg_print_safe(io_core, "Kernel : Starting io poller thread\n" );
    127132
    128                 iopoll.run = true;
    129                 iopoll.stack = __create_pthread( &iopoll.thrd, iopoll_loop, 0p );
     133                iopoll.stack   = __create_pthread( &iopoll.thrd, iopoll_loop, 0p );
     134                iopoll.run     = true;
     135                iopoll.stopped = false;
     136                iopoll.epoch   = 0;
    130137        }
    131138
     
    171178                while( iopoll.run ) {
    172179                        __cfadbg_print_safe(io_core, "Kernel I/O - epoll : waiting on io_uring contexts\n");
     180
     181                        // increment the epoch to notify any deleters we are starting a new cycle
     182                        __atomic_fetch_add(&iopoll.epoch, 1, __ATOMIC_SEQ_CST);
    173183
    174184                        // Wait for events
     
    197207                        }
    198208                }
     209
     210                __atomic_store_n(&iopoll.stopped, true, __ATOMIC_SEQ_CST);
    199211
    200212                __cfadbg_print_safe(io_core, "Kernel : IO poller thread stopping\n" );
     
    493505// I/O Context Sleep
    494506//=============================================================================================
    495         #define IOEVENTS EPOLLIN | EPOLLONESHOT
    496 
    497507        static inline void __ioctx_epoll_ctl($io_ctx_thread & ctx, int op, const char * error) {
    498508                struct epoll_event ev;
    499                 ev.events = IOEVENTS;
     509                ev.events = EPOLLIN | EPOLLONESHOT;
    500510                ev.data.u64 = (__u64)&ctx;
    501511                int ret = epoll_ctl(iopoll.epollfd, op, ctx.ring->efd, &ev);
     
    514524        }
    515525
     526        void __ioctx_unregister($io_ctx_thread & ctx) {
     527                // Read the current epoch so we know when to stop
     528                size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST);
     529
     530                // Remove the fd from the iopoller
     531                __ioctx_epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE");
     532
     533                // Notify the io poller thread of the shutdown
     534                iopoll.run = false;
     535                sigval val = { 1 };
     536                pthread_sigqueue( iopoll.thrd, SIGUSR1, val );
     537
     538                // Make sure all this is done
     539                __atomic_thread_fence(__ATOMIC_SEQ_CST);
     540
     541                // Wait for the next epoch
     542                while(curr == iopoll.epoch && !iopoll.stopped) Pause();
     543        }
     544
    516545//=============================================================================================
    517546// I/O Context Misc Setup
     
    520549                int ret = syscall( __NR_io_uring_register, ctx.thrd.ring->fd, IORING_REGISTER_FILES, files, count );
    521550                if( ret < 0 ) {
    522                         abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) );
     551                        abort( "KERNEL ERROR: IO_URING REGISTER - (%d) %s\n", (int)errno, strerror(errno) );
    523552                }
    524553
  • libcfa/src/concurrency/io/types.hfa

    rb6a8b31 rd95969a  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // io/types.hfa --
     7// io/types.hfa -- PRIVATE
     8// Types used by the I/O subsystem
    89//
    910// Author           : Thierry Delisle
     
    2122
    2223#include "bits/locks.hfa"
     24#include "kernel/fwd.hfa"
    2325
    2426#if defined(CFA_HAVE_LINUX_IO_URING_H)
     
    133135        struct $io_ctx_thread;
    134136        void __ioctx_register($io_ctx_thread & ctx);
     137        void __ioctx_unregister($io_ctx_thread & ctx);
    135138        void __ioctx_prepare_block($io_ctx_thread & ctx);
    136139        void __sqe_clean( volatile struct io_uring_sqe * sqe );
  • libcfa/src/concurrency/kernel.cfa

    rb6a8b31 rd95969a  
    140140                preemption_scope scope = { this };
    141141
     142                #if !defined(__CFA_NO_STATISTICS__)
     143                        unsigned long long last_tally = rdtscl();
     144                #endif
     145
     146
    142147                __cfadbg_print_safe(runtime_core, "Kernel : core %p started\n", this);
    143148
     
    206211                        // Are we done?
    207212                        if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     213
     214                        #if !defined(__CFA_NO_STATISTICS__)
     215                                unsigned long long curr = rdtscl();
     216                                if(curr > (last_tally + 500000000)) {
     217                                        __tally_stats(this->cltr->stats, __cfaabi_tls.this_stats);
     218                                        last_tally = curr;
     219                                }
     220                        #endif
    208221                }
    209222
     
    211224        }
    212225
    213         V( this->terminated );
     226        post( this->terminated );
    214227
    215228        if(this == mainProcessor) {
     
    611624// Unexpected Terminating logic
    612625//=============================================================================================
    613 static __spinlock_t kernel_abort_lock;
    614 static bool kernel_abort_called = false;
    615 
    616 void * kernel_abort(void) __attribute__ ((__nothrow__)) {
    617         // abort cannot be recursively entered by the same or different processors because all signal handlers return when
    618         // the globalAbort flag is true.
    619         lock( kernel_abort_lock __cfaabi_dbg_ctx2 );
    620 
    621         // disable interrupts, it no longer makes sense to try to interrupt this processor
    622         disable_interrupts();
    623 
    624         // first task to abort ?
    625         if ( kernel_abort_called ) {                    // not first task to abort ?
    626                 unlock( kernel_abort_lock );
    627 
    628                 sigset_t mask;
    629                 sigemptyset( &mask );
    630                 sigaddset( &mask, SIGALRM );            // block SIGALRM signals
    631                 sigaddset( &mask, SIGUSR1 );            // block SIGALRM signals
    632                 sigsuspend( &mask );                            // block the processor to prevent further damage during abort
    633                 _exit( EXIT_FAILURE );                          // if processor unblocks before it is killed, terminate it
    634         }
    635         else {
    636                 kernel_abort_called = true;
    637                 unlock( kernel_abort_lock );
    638         }
    639 
    640         return __cfaabi_tls.this_thread;
    641 }
    642 
    643 void kernel_abort_msg( void * kernel_data, char * abort_text, int abort_text_size ) {
    644         $thread * thrd = ( $thread * ) kernel_data;
     626void __kernel_abort_msg( char * abort_text, int abort_text_size ) {
     627        $thread * thrd = __cfaabi_tls.this_thread;
    645628
    646629        if(thrd) {
     
    662645}
    663646
    664 int kernel_abort_lastframe( void ) __attribute__ ((__nothrow__)) {
    665         return get_coroutine(kernelTLS().this_thread) == get_coroutine(mainThread) ? 4 : 2;
     647int __kernel_abort_lastframe( void ) __attribute__ ((__nothrow__)) {
     648        return get_coroutine(__cfaabi_tls.this_thread) == get_coroutine(mainThread) ? 4 : 2;
    666649}
    667650
     
    681664// Kernel Utilities
    682665//=============================================================================================
    683 //-----------------------------------------------------------------------------
    684 // Locks
    685 void  ?{}( semaphore & this, int count = 1 ) {
    686         (this.lock){};
    687         this.count = count;
    688         (this.waiting){};
    689 }
    690 void ^?{}(semaphore & this) {}
    691 
    692 bool P(semaphore & this) with( this ){
    693         lock( lock __cfaabi_dbg_ctx2 );
    694         count -= 1;
    695         if ( count < 0 ) {
    696                 // queue current task
    697                 append( waiting, active_thread() );
    698 
    699                 // atomically release spin lock and block
    700                 unlock( lock );
    701                 park();
    702                 return true;
    703         }
    704         else {
    705             unlock( lock );
    706             return false;
    707         }
    708 }
    709 
    710 bool V(semaphore & this) with( this ) {
    711         $thread * thrd = 0p;
    712         lock( lock __cfaabi_dbg_ctx2 );
    713         count += 1;
    714         if ( count <= 0 ) {
    715                 // remove task at head of waiting list
    716                 thrd = pop_head( waiting );
    717         }
    718 
    719         unlock( lock );
    720 
    721         // make new owner
    722         unpark( thrd );
    723 
    724         return thrd != 0p;
    725 }
    726 
    727 bool V(semaphore & this, unsigned diff) with( this ) {
    728         $thread * thrd = 0p;
    729         lock( lock __cfaabi_dbg_ctx2 );
    730         int release = max(-count, (int)diff);
    731         count += diff;
    732         for(release) {
    733                 unpark( pop_head( waiting ) );
    734         }
    735 
    736         unlock( lock );
    737 
    738         return thrd != 0p;
    739 }
    740 
    741666//-----------------------------------------------------------------------------
    742667// Debug
  • libcfa/src/concurrency/kernel.hfa

    rb6a8b31 rd95969a  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // kernel --
     7// kernel -- Header containing the core of the kernel API
    88//
    99// Author           : Thierry Delisle
     
    2424extern "C" {
    2525        #include <bits/pthreadtypes.h>
     26        #include <pthread.h>
    2627        #include <linux/types.h>
    2728}
    2829
    2930//-----------------------------------------------------------------------------
    30 // Locks
    31 struct semaphore {
    32         __spinlock_t lock;
    33         int count;
    34         __queue_t($thread) waiting;
    35 };
    36 
    37 void  ?{}(semaphore & this, int count = 1);
    38 void ^?{}(semaphore & this);
    39 bool   P (semaphore & this);
    40 bool   V (semaphore & this);
    41 bool   V (semaphore & this, unsigned count);
     31// Underlying Locks
     32#ifdef __CFA_WITH_VERIFY__
     33        extern bool __cfaabi_dbg_in_kernel();
     34#endif
     35
     36extern "C" {
     37        char * strerror(int);
     38}
     39#define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); }
     40
     41struct __bin_sem_t {
     42        pthread_mutex_t         lock;
     43        pthread_cond_t          cond;
     44        int                     val;
     45};
     46
     47static inline void ?{}(__bin_sem_t & this) with( this ) {
     48        // Create the mutex with error checking
     49        pthread_mutexattr_t mattr;
     50        pthread_mutexattr_init( &mattr );
     51        pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP);
     52        pthread_mutex_init(&lock, &mattr);
     53
     54        pthread_cond_init (&cond, (const pthread_condattr_t *)0p);  // workaround trac#208: cast should not be required
     55        val = 0;
     56}
     57
     58static inline void ^?{}(__bin_sem_t & this) with( this ) {
     59        CHECKED( pthread_mutex_destroy(&lock) );
     60        CHECKED( pthread_cond_destroy (&cond) );
     61}
     62
     63static inline void wait(__bin_sem_t & this) with( this ) {
     64        verify(__cfaabi_dbg_in_kernel());
     65        CHECKED( pthread_mutex_lock(&lock) );
     66                while(val < 1) {
     67                        pthread_cond_wait(&cond, &lock);
     68                }
     69                val -= 1;
     70        CHECKED( pthread_mutex_unlock(&lock) );
     71}
     72
     73static inline bool post(__bin_sem_t & this) with( this ) {
     74        bool needs_signal = false;
     75
     76        CHECKED( pthread_mutex_lock(&lock) );
     77                if(val < 1) {
     78                        val += 1;
     79                        pthread_cond_signal(&cond);
     80                        needs_signal = true;
     81                }
     82        CHECKED( pthread_mutex_unlock(&lock) );
     83
     84        return needs_signal;
     85}
     86
     87#undef CHECKED
    4288
    4389
     
    91137
    92138        // Termination synchronisation (user semaphore)
    93         semaphore terminated;
     139        oneshot terminated;
    94140
    95141        // pthread Stack
  • libcfa/src/concurrency/kernel/fwd.hfa

    rb6a8b31 rd95969a  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // kernel/fwd.hfa --
     7// kernel/fwd.hfa -- PUBLIC
     8// Fundamental code needed to implement threading M.E.S. algorithms.
    89//
    910// Author           : Thierry Delisle
     
    134135                extern uint64_t thread_rand();
    135136
     137                // Semaphore which only supports a single thread
     138                struct single_sem {
     139                        struct $thread * volatile ptr;
     140                };
     141
     142                static inline {
     143                        void  ?{}(single_sem & this) {
     144                                this.ptr = 0p;
     145                        }
     146
     147                        void ^?{}(single_sem &) {}
     148
     149                        bool wait(single_sem & this) {
     150                                for() {
     151                                        struct $thread * expected = this.ptr;
     152                                        if(expected == 1p) {
     153                                                if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     154                                                        return false;
     155                                                }
     156                                        }
     157                                        else {
     158                                                /* paranoid */ verify( expected == 0p );
     159                                                if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     160                                                        park();
     161                                                        return true;
     162                                                }
     163                                        }
     164
     165                                }
     166                        }
     167
     168                        bool post(single_sem & this) {
     169                                for() {
     170                                        struct $thread * expected = this.ptr;
     171                                        if(expected == 1p) return false;
     172                                        if(expected == 0p) {
     173                                                if(__atomic_compare_exchange_n(&this.ptr, &expected, 1p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     174                                                        return false;
     175                                                }
     176                                        }
     177                                        else {
     178                                                if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     179                                                        unpark( expected );
     180                                                        return true;
     181                                                }
     182                                        }
     183                                }
     184                        }
     185                }
     186
     187                // Synchronozation primitive which only supports a single thread and one post
     188                // Similar to a binary semaphore with a 'one shot' semantic
     189                // is expected to be discarded after each party call their side
     190                struct oneshot {
     191                        // Internal state :
     192                        //     0p     : is initial state (wait will block)
     193                        //     1p     : fulfilled (wait won't block)
     194                        // any thread : a thread is currently waiting
     195                        struct $thread * volatile ptr;
     196                };
     197
     198                static inline {
     199                        void  ?{}(oneshot & this) {
     200                                this.ptr = 0p;
     201                        }
     202
     203                        void ^?{}(oneshot &) {}
     204
     205                        // Wait for the post, return immidiately if it already happened.
     206                        // return true if the thread was parked
     207                        bool wait(oneshot & this) {
     208                                for() {
     209                                        struct $thread * expected = this.ptr;
     210                                        if(expected == 1p) return false;
     211                                        /* paranoid */ verify( expected == 0p );
     212                                        if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     213                                                park();
     214                                                /* paranoid */ verify( this.ptr == 1p );
     215                                                return true;
     216                                        }
     217                                }
     218                        }
     219
     220                        // Mark as fulfilled, wake thread if needed
     221                        // return true if a thread was unparked
     222                        bool post(oneshot & this) {
     223                                struct $thread * got = __atomic_exchange_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
     224                                if( got == 0p ) return false;
     225                                unpark( got );
     226                                return true;
     227                        }
     228                }
     229
     230                // base types for future to build upon
     231                // It is based on the 'oneshot' type to allow multiple futures
     232                // to block on the same instance, permitting users to block a single
     233                // thread on "any of" [a given set of] futures.
     234                // does not support multiple threads waiting on the same future
     235                struct future_t {
     236                        // Internal state :
     237                        //     0p      : is initial state (wait will block)
     238                        //     1p      : fulfilled (wait won't block)
     239                        //     2p      : in progress ()
     240                        //     3p      : abandoned, server should delete
     241                        // any oneshot : a context has been setup to wait, a thread could wait on it
     242                        struct oneshot * volatile ptr;
     243                };
     244
     245                static inline {
     246                        void  ?{}(future_t & this) {
     247                                this.ptr = 0p;
     248                        }
     249
     250                        void ^?{}(future_t &) {}
     251
     252                        void reset(future_t & this) {
     253                                // needs to be in 0p or 1p
     254                                __atomic_exchange_n( &this.ptr, 0p, __ATOMIC_SEQ_CST);
     255                        }
     256
     257                        // check if the future is available
     258                        bool available( future_t & this ) {
     259                                return this.ptr == 1p;
     260                        }
     261
     262                        // Prepare the future to be waited on
     263                        // intented to be use by wait, wait_any, waitfor, etc. rather than used directly
     264                        bool setup( future_t & this, oneshot & wait_ctx ) {
     265                                /* paranoid */ verify( wait_ctx.ptr == 0p );
     266                                // The future needs to set the wait context
     267                                for() {
     268                                        struct oneshot * expected = this.ptr;
     269                                        // Is the future already fulfilled?
     270                                        if(expected == 1p) return false; // Yes, just return false (didn't block)
     271
     272                                        // The future is not fulfilled, try to setup the wait context
     273                                        /* paranoid */ verify( expected == 0p );
     274                                        if(__atomic_compare_exchange_n(&this.ptr, &expected, &wait_ctx, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     275                                                return true;
     276                                        }
     277                                }
     278                        }
     279
     280                        // Stop waiting on a future
     281                        // When multiple futures are waited for together in "any of" pattern
     282                        // futures that weren't fulfilled before the thread woke up
     283                        // should retract the wait ctx
     284                        // intented to be use by wait, wait_any, waitfor, etc. rather than used directly
     285                        void retract( future_t & this, oneshot & wait_ctx ) {
     286                                // Remove the wait context
     287                                struct oneshot * got = __atomic_exchange_n( &this.ptr, 0p, __ATOMIC_SEQ_CST);
     288
     289                                // got == 0p: future was never actually setup, just return
     290                                if( got == 0p ) return;
     291
     292                                // got == wait_ctx: since fulfil does an atomic_swap,
     293                                // if we got back the original then no one else saw context
     294                                // It is safe to delete (which could happen after the return)
     295                                if( got == &wait_ctx ) return;
     296
     297                                // got == 1p: the future is ready and the context was fully consumed
     298                                // the server won't use the pointer again
     299                                // It is safe to delete (which could happen after the return)
     300                                if( got == 1p ) return;
     301
     302                                // got == 2p: the future is ready but the context hasn't fully been consumed
     303                                // spin until it is safe to move on
     304                                if( got == 2p ) {
     305                                        while( this.ptr != 1p ) Pause();
     306                                        return;
     307                                }
     308
     309                                // got == any thing else, something wen't wrong here, abort
     310                                abort("Future in unexpected state");
     311                        }
     312
     313                        // Mark the future as abandoned, meaning it will be deleted by the server
     314                        bool abandon( future_t & this ) {
     315                                /* paranoid */ verify( this.ptr != 3p );
     316
     317                                // Mark the future as abandonned
     318                                struct oneshot * got = __atomic_exchange_n( &this.ptr, 3p, __ATOMIC_SEQ_CST);
     319
     320                                // If the future isn't already fulfilled, let the server delete it
     321                                if( got == 0p ) return false;
     322
     323                                // got == 2p: the future is ready but the context hasn't fully been consumed
     324                                // spin until it is safe to move on
     325                                if( got == 2p ) {
     326                                        while( this.ptr != 1p ) Pause();
     327                                        got = 1p;
     328                                }
     329
     330                                // The future is completed delete it now
     331                                /* paranoid */ verify( this.ptr != 1p );
     332                                free( &this );
     333                                return true;
     334                        }
     335
     336                        // from the server side, mark the future as fulfilled
     337                        // delete it if needed
     338                        bool fulfil( future_t & this ) {
     339                                for() {
     340                                        struct oneshot * expected = this.ptr;
     341                                        // was this abandoned?
     342                                        #if defined(__GNUC__) && __GNUC__ >= 7
     343                                                #pragma GCC diagnostic push
     344                                                #pragma GCC diagnostic ignored "-Wfree-nonheap-object"
     345                                        #endif
     346                                                if( expected == 3p ) { free( &this ); return false; }
     347                                        #if defined(__GNUC__) && __GNUC__ >= 7
     348                                                #pragma GCC diagnostic pop
     349                                        #endif
     350
     351                                        /* paranoid */ verify( expected != 1p ); // Future is already fulfilled, should not happen
     352                                        /* paranoid */ verify( expected != 2p ); // Future is bein fulfilled by someone else, this is even less supported then the previous case.
     353
     354                                        // If there is a wait context, we need to consume it and mark it as consumed after
     355                                        // If there is no context then we can skip the in progress phase
     356                                        struct oneshot * want = expected == 0p ? 1p : 2p;
     357                                        if(__atomic_compare_exchange_n(&this.ptr, &expected, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     358                                                if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return false; }
     359                                                bool ret = post( *expected );
     360                                                __atomic_store_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
     361                                                return ret;
     362                                        }
     363                                }
     364
     365                        }
     366
     367                        // Wait for the future to be fulfilled
     368                        bool wait( future_t & this ) {
     369                                oneshot temp;
     370                                if( !setup(this, temp) ) return false;
     371
     372                                // Wait context is setup, just wait on it
     373                                bool ret = wait( temp );
     374
     375                                // Wait for the future to tru
     376                                while( this.ptr == 2p ) Pause();
     377                                // Make sure the state makes sense
     378                                // Should be fulfilled, could be in progress but it's out of date if so
     379                                // since if that is the case, the oneshot was fulfilled (unparking this thread)
     380                                // and the oneshot should not be needed any more
     381                                __attribute__((unused)) struct oneshot * was = this.ptr;
     382                                /* paranoid */ verifyf( was == 1p, "Expected this.ptr to be 1p, was %p\n", was );
     383
     384                                // Mark the future as fulfilled, to be consistent
     385                                // with potential calls to avail
     386                                // this.ptr = 1p;
     387                                return ret;
     388                        }
     389                }
     390
    136391                //-----------------------------------------------------------------------
    137392                // Statics call at the end of each thread to register statistics
  • libcfa/src/concurrency/kernel/startup.cfa

    rb6a8b31 rd95969a  
    199199        void ?{}(processor & this) with( this ) {
    200200                ( this.idle ){};
    201                 ( this.terminated ){ 0 };
     201                ( this.terminated ){};
    202202                ( this.runner ){};
    203203                init( this, "Main Processor", *mainCluster );
     
    528528void ?{}(processor & this, const char name[], cluster & _cltr) {
    529529        ( this.idle ){};
    530         ( this.terminated ){ 0 };
     530        ( this.terminated ){};
    531531        ( this.runner ){};
    532532
     
    549549                __wake_proc( &this );
    550550
    551                 P( terminated );
     551                wait( terminated );
    552552                /* paranoid */ verify( active_processor() != &this);
    553553        }
  • libcfa/src/concurrency/locks.cfa

    rb6a8b31 rd95969a  
     1//
     2// Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
     3//
     4// The contents of this file are covered under the licence agreement in the
     5// file "LICENCE" distributed with Cforall.
     6//
     7// locks.hfa -- LIBCFATHREAD
     8// Runtime locks that used with the runtime thread system.
     9//
     10// Author           : Colby Alexander Parsons
     11// Created On       : Thu Jan 21 19:46:50 2021
     12// Last Modified By :
     13// Last Modified On :
     14// Update Count     :
     15//
     16
     17#define __cforall_thread__
     18
    119#include "locks.hfa"
    220#include "kernel_private.hfa"
     
    725//-----------------------------------------------------------------------------
    826// info_thread
    9 forall(dtype L | is_blocking_lock(L)) {
     27forall(L & | is_blocking_lock(L)) {
    1028        struct info_thread {
    1129                // used to put info_thread on a dl queue (aka sequence)
     
    5674
    5775void ^?{}( blocking_lock & this ) {}
    58 void  ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };}
    59 void ^?{}( single_acquisition_lock & this ) {}
    60 void  ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };}
    61 void ^?{}( owner_lock & this ) {}
    62 void  ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };}
    63 void ^?{}( multiple_acquisition_lock & this ) {}
     76
    6477
    6578void lock( blocking_lock & this ) with( this ) {
     
    170183
    171184//-----------------------------------------------------------------------------
    172 // Overloaded routines for traits
    173 // These routines are temporary until an inheritance bug is fixed
    174 void   lock      ( single_acquisition_lock & this ) { lock   ( (blocking_lock &)this ); }
    175 void   unlock    ( single_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); }
    176 void   on_wait   ( single_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); }
    177 void   on_notify ( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
    178 void   set_recursion_count( single_acquisition_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); }
    179 size_t get_recursion_count( single_acquisition_lock & this ) { return get_recursion_count( (blocking_lock &)this ); }
    180 
    181 void   lock     ( owner_lock & this ) { lock   ( (blocking_lock &)this ); }
    182 void   unlock   ( owner_lock & this ) { unlock ( (blocking_lock &)this ); }
    183 void   on_wait  ( owner_lock & this ) { on_wait( (blocking_lock &)this ); }
    184 void   on_notify( owner_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
    185 void   set_recursion_count( owner_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); }
    186 size_t get_recursion_count( owner_lock & this ) { return get_recursion_count( (blocking_lock &)this ); }
    187 
    188 void   lock     ( multiple_acquisition_lock & this ) { lock   ( (blocking_lock &)this ); }
    189 void   unlock   ( multiple_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); }
    190 void   on_wait  ( multiple_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); }
    191 void   on_notify( multiple_acquisition_lock & this, struct $thread * t ){ on_notify( (blocking_lock &)this, t ); }
    192 void   set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
    193 size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
    194 
    195 //-----------------------------------------------------------------------------
    196185// alarm node wrapper
    197 forall(dtype L | is_blocking_lock(L)) {
     186forall(L & | is_blocking_lock(L)) {
    198187        struct alarm_node_wrap {
    199188                alarm_node_t alarm_node;
     
    239228//-----------------------------------------------------------------------------
    240229// condition variable
    241 forall(dtype L | is_blocking_lock(L)) {
     230forall(L & | is_blocking_lock(L)) {
    242231
    243232        void ?{}( condition_variable(L) & this ){
     
    356345        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time         ) with(this) { WAIT_TIME( info, &l , time ) }
    357346}
     347
     348//-----------------------------------------------------------------------------
     349// Semaphore
     350void  ?{}( semaphore & this, int count = 1 ) {
     351        (this.lock){};
     352        this.count = count;
     353        (this.waiting){};
     354}
     355void ^?{}(semaphore & this) {}
     356
     357bool P(semaphore & this) with( this ){
     358        lock( lock __cfaabi_dbg_ctx2 );
     359        count -= 1;
     360        if ( count < 0 ) {
     361                // queue current task
     362                append( waiting, active_thread() );
     363
     364                // atomically release spin lock and block
     365                unlock( lock );
     366                park();
     367                return true;
     368        }
     369        else {
     370            unlock( lock );
     371            return false;
     372        }
     373}
     374
     375bool V(semaphore & this) with( this ) {
     376        $thread * thrd = 0p;
     377        lock( lock __cfaabi_dbg_ctx2 );
     378        count += 1;
     379        if ( count <= 0 ) {
     380                // remove task at head of waiting list
     381                thrd = pop_head( waiting );
     382        }
     383
     384        unlock( lock );
     385
     386        // make new owner
     387        unpark( thrd );
     388
     389        return thrd != 0p;
     390}
     391
     392bool V(semaphore & this, unsigned diff) with( this ) {
     393        $thread * thrd = 0p;
     394        lock( lock __cfaabi_dbg_ctx2 );
     395        int release = max(-count, (int)diff);
     396        count += diff;
     397        for(release) {
     398                unpark( pop_head( waiting ) );
     399        }
     400
     401        unlock( lock );
     402
     403        return thrd != 0p;
     404}
  • libcfa/src/concurrency/locks.hfa

    rb6a8b31 rd95969a  
     1//
     2// Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
     3//
     4// The contents of this file are covered under the licence agreement in the
     5// file "LICENCE" distributed with Cforall.
     6//
     7// locks.hfa -- PUBLIC
     8// Runtime locks that used with the runtime thread system.
     9//
     10// Author           : Colby Alexander Parsons
     11// Created On       : Thu Jan 21 19:46:50 2021
     12// Last Modified By :
     13// Last Modified On :
     14// Update Count     :
     15//
     16
    117#pragma once
    218
    319#include <stdbool.h>
    420
    5 #include "bits/locks.hfa"
    6 #include "bits/sequence.hfa"
    7 
    8 #include "invoke.h"
     21#include "bits/weakso_locks.hfa"
    922
    1023#include "time_t.hfa"
    1124#include "time.hfa"
    1225
     26//----------
     27struct single_acquisition_lock {
     28        inline blocking_lock;
     29};
     30
     31static inline void  ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };}
     32static inline void ^?{}( single_acquisition_lock & this ) {}
     33static inline void   lock      ( single_acquisition_lock & this ) { lock   ( (blocking_lock &)this ); }
     34static inline void   unlock    ( single_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); }
     35static inline void   on_wait   ( single_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); }
     36static inline void   on_notify ( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
     37static inline void   set_recursion_count( single_acquisition_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); }
     38static inline size_t get_recursion_count( single_acquisition_lock & this ) { return get_recursion_count( (blocking_lock &)this ); }
     39
     40//----------
     41struct owner_lock {
     42        inline blocking_lock;
     43};
     44
     45static inline void  ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };}
     46static inline void ^?{}( owner_lock & this ) {}
     47static inline void   lock     ( owner_lock & this ) { lock   ( (blocking_lock &)this ); }
     48static inline void   unlock   ( owner_lock & this ) { unlock ( (blocking_lock &)this ); }
     49static inline void   on_wait  ( owner_lock & this ) { on_wait( (blocking_lock &)this ); }
     50static inline void   on_notify( owner_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
     51static inline void   set_recursion_count( owner_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); }
     52static inline size_t get_recursion_count( owner_lock & this ) { return get_recursion_count( (blocking_lock &)this ); }
     53
    1354//-----------------------------------------------------------------------------
    1455// is_blocking_lock
    15 trait is_blocking_lock(dtype L | sized(L)) {
     56trait is_blocking_lock(L & | sized(L)) {
    1657        // For synchronization locks to use when acquiring
    1758        void on_notify( L &, struct $thread * );
     
    3172// the info thread is a wrapper around a thread used
    3273// to store extra data for use in the condition variable
    33 forall(dtype L | is_blocking_lock(L)) {
     74forall(L & | is_blocking_lock(L)) {
    3475        struct info_thread;
    3576
     
    4081
    4182//-----------------------------------------------------------------------------
    42 // Blocking Locks
    43 struct blocking_lock {
    44         // Spin lock used for mutual exclusion
    45         __spinlock_t lock;
    46 
    47         // List of blocked threads
    48         Sequence( $thread ) blocked_threads;
    49 
    50         // Count of current blocked threads
    51         size_t wait_count;
    52 
    53         // Flag if the lock allows multiple acquisition
    54         bool multi_acquisition;
    55 
    56         // Flag if lock can be released by non owner
    57         bool strict_owner;
    58 
    59         // Current thread owning the lock
    60         struct $thread * owner;
    61 
    62         // Number of recursion level
    63         size_t recursion_count;
    64 };
    65 
    66 struct single_acquisition_lock {
    67         inline blocking_lock;
    68 };
    69 
    70 struct owner_lock {
    71         inline blocking_lock;
    72 };
    73 
    74 struct multiple_acquisition_lock {
    75         inline blocking_lock;
    76 };
    77 
    78 void  ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner );
    79 void ^?{}( blocking_lock & this );
    80 
    81 void  ?{}( single_acquisition_lock & this );
    82 void ^?{}( single_acquisition_lock & this );
    83 
    84 void  ?{}( owner_lock & this );
    85 void ^?{}( owner_lock & this );
    86 
    87 void  ?{}( multiple_acquisition_lock & this );
    88 void ^?{}( multiple_acquisition_lock & this );
    89 
    90 void lock( blocking_lock & this );
    91 bool try_lock( blocking_lock & this );
    92 void unlock( blocking_lock & this );
    93 void on_notify( blocking_lock & this, struct $thread * t );
    94 void on_wait( blocking_lock & this );
    95 size_t wait_count( blocking_lock & this );
    96 void set_recursion_count( blocking_lock & this, size_t recursion );
    97 size_t get_recursion_count( blocking_lock & this );
    98 
    99 void lock( single_acquisition_lock & this );
    100 void unlock( single_acquisition_lock & this );
    101 void on_notify( single_acquisition_lock & this, struct $thread * t );
    102 void on_wait( single_acquisition_lock & this );
    103 void set_recursion_count( single_acquisition_lock & this, size_t recursion );
    104 size_t get_recursion_count( single_acquisition_lock & this );
    105 
    106 void lock( owner_lock & this );
    107 void unlock( owner_lock & this );
    108 void on_notify( owner_lock & this, struct $thread * t );
    109 void on_wait( owner_lock & this );
    110 void set_recursion_count( owner_lock & this, size_t recursion );
    111 size_t get_recursion_count( owner_lock & this );
    112 
    113 void lock( multiple_acquisition_lock & this );
    114 void unlock( multiple_acquisition_lock & this );
    115 void on_notify( multiple_acquisition_lock & this, struct $thread * t );
    116 void on_wait( multiple_acquisition_lock & this );
    117 void set_recursion_count( multiple_acquisition_lock & this, size_t recursion );
    118 size_t get_recursion_count( multiple_acquisition_lock & this );
    119 
    120 //-----------------------------------------------------------------------------
    12183// Synchronization Locks
    122 forall(dtype L | is_blocking_lock(L)) {
     84forall(L & | is_blocking_lock(L)) {
    12385        struct condition_variable {
    12486                // Spin lock used for mutual exclusion
     
    157119        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time );
    158120}
     121
     122//-----------------------------------------------------------------------------
     123// Semaphore
     124struct semaphore {
     125        __spinlock_t lock;
     126        int count;
     127        __queue_t($thread) waiting;
     128};
     129
     130void  ?{}(semaphore & this, int count = 1);
     131void ^?{}(semaphore & this);
     132bool   P (semaphore & this);
     133bool   V (semaphore & this);
     134bool   V (semaphore & this, unsigned count);
  • libcfa/src/concurrency/monitor.cfa

    rb6a8b31 rd95969a  
    5050static inline [$thread *, int] search_entry_queue( const __waitfor_mask_t &, $monitor * monitors [], __lock_size_t count );
    5151
    52 forall(dtype T | sized( T ))
     52forall(T & | sized( T ))
    5353static inline __lock_size_t insert_unique( T * array [], __lock_size_t & size, T * val );
    5454static inline __lock_size_t count_max    ( const __waitfor_mask_t & mask );
     
    949949}
    950950
    951 forall(dtype T | sized( T ))
     951forall(T & | sized( T ))
    952952static inline __lock_size_t insert_unique( T * array [], __lock_size_t & size, T * val ) {
    953953        if( !val ) return size;
  • libcfa/src/concurrency/monitor.hfa

    rb6a8b31 rd95969a  
    2222#include "stdlib.hfa"
    2323
    24 trait is_monitor(dtype T) {
     24trait is_monitor(T &) {
    2525        $monitor * get_monitor( T & );
    2626        void ^?{}( T & mutex );
     
    5959void ^?{}( monitor_dtor_guard_t & this );
    6060
    61 static inline forall( dtype T | sized(T) | { void ^?{}( T & mutex ); } )
     61static inline forall( T & | sized(T) | { void ^?{}( T & mutex ); } )
    6262void delete( T * th ) {
    6363        ^(*th){};
  • libcfa/src/concurrency/mutex.cfa

    rb6a8b31 rd95969a  
    164164}
    165165
    166 forall(dtype L | is_lock(L))
     166forall(L & | is_lock(L))
    167167void wait(condition_variable & this, L & l) {
    168168        lock( this.lock __cfaabi_dbg_ctx2 );
     
    176176//-----------------------------------------------------------------------------
    177177// Scopes
    178 forall(dtype L | is_lock(L))
     178forall(L & | is_lock(L))
    179179void lock_all  ( L * locks[], size_t count) {
    180180        // Sort locks based on addresses
     
    188188}
    189189
    190 forall(dtype L | is_lock(L))
     190forall(L & | is_lock(L))
    191191void unlock_all( L * locks[], size_t count) {
    192192        // Lock all
  • libcfa/src/concurrency/mutex.hfa

    rb6a8b31 rd95969a  
    4242};
    4343
    44 void ?{}(mutex_lock & this);
    45 void ^?{}(mutex_lock & this);
    46 void lock(mutex_lock & this);
    47 bool try_lock(mutex_lock & this);
    48 void unlock(mutex_lock & this);
     44void ?{}(mutex_lock & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
     45void ^?{}(mutex_lock & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
     46void lock(mutex_lock & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
     47bool try_lock(mutex_lock & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
     48void unlock(mutex_lock & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
    4949
    5050// Exclusive lock - recursive
     
    6464};
    6565
    66 void ?{}(recursive_mutex_lock & this);
    67 void ^?{}(recursive_mutex_lock & this);
    68 void lock(recursive_mutex_lock & this);
    69 bool try_lock(recursive_mutex_lock & this);
    70 void unlock(recursive_mutex_lock & this);
     66void ?{}(recursive_mutex_lock & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
     67void ^?{}(recursive_mutex_lock & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
     68void lock(recursive_mutex_lock & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
     69bool try_lock(recursive_mutex_lock & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
     70void unlock(recursive_mutex_lock & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
    7171
    72 trait is_lock(dtype L | sized(L)) {
     72trait is_lock(L & | sized(L)) {
    7373        void lock  (L &);
    7474        void unlock(L &);
     
    8686};
    8787
    88 void ?{}(condition_variable & this);
    89 void ^?{}(condition_variable & this);
     88void ?{}(condition_variable & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
     89void ^?{}(condition_variable & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
    9090
    91 void notify_one(condition_variable & this);
    92 void notify_all(condition_variable & this);
     91void notify_one(condition_variable & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
     92void notify_all(condition_variable & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
    9393
    94 void wait(condition_variable & this);
     94void wait(condition_variable & this) __attribute__((deprecated("use concurrency/locks.hfa instead")));
    9595
    96 forall(dtype L | is_lock(L))
    97 void wait(condition_variable & this, L & l);
     96forall(L & | is_lock(L))
     97void wait(condition_variable & this, L & l) __attribute__((deprecated("use concurrency/locks.hfa instead")));
    9898
    9999//-----------------------------------------------------------------------------
    100100// Scopes
    101 forall(dtype L | is_lock(L)) {
     101forall(L & | is_lock(L)) {
    102102        #if !defined( __TUPLE_ARRAYS_EXIST__ )
    103103        void lock  ( L * locks [], size_t count);
  • libcfa/src/concurrency/preemption.cfa

    rb6a8b31 rd95969a  
    616616}
    617617
     618// Prevent preemption since we are about to start terminating things
     619void __kernel_abort_lock(void) {
     620        signal_block( SIGUSR1 );
     621}
     622
    618623// Raii ctor/dtor for the preemption_scope
    619624// Used by thread to control when they want to receive preemption signals
  • libcfa/src/concurrency/stats.hfa

    rb6a8b31 rd95969a  
    22
    33#include <stdint.h>
     4
     5enum {
     6        CFA_STATS_READY_Q  = 0x01,
     7        CFA_STATS_IO = 0x02,
     8};
    49
    510#if defined(__CFA_NO_STATISTICS__)
     
    914        static inline void __print_stats( struct __stats_t *, int, const char *, const char *, void * ) {}
    1015#else
    11         enum {
    12                 CFA_STATS_READY_Q  = 0x01,
    13                 #if defined(CFA_HAVE_LINUX_IO_URING_H)
    14                         CFA_STATS_IO = 0x02,
    15                 #endif
    16         };
    1716
    1817        struct __attribute__((aligned(64))) __stats_readQ_t {
  • libcfa/src/concurrency/thread.cfa

    rb6a8b31 rd95969a  
    6262}
    6363
    64 FORALL_DATA_INSTANCE(ThreadCancelled, (dtype thread_t), (thread_t))
     64FORALL_DATA_INSTANCE(ThreadCancelled, (thread_t &), (thread_t))
    6565
    66 forall(dtype T)
     66forall(T &)
    6767void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src) {
    6868        dst->virtual_table = src->virtual_table;
     
    7171}
    7272
    73 forall(dtype T)
     73forall(T &)
    7474const char * msg(ThreadCancelled(T) *) {
    7575        return "ThreadCancelled";
    7676}
    7777
    78 forall(dtype T)
     78forall(T &)
    7979static void default_thread_cancel_handler(ThreadCancelled(T) & ) {
    8080        abort( "Unhandled thread cancellation.\n" );
    8181}
    8282
    83 forall(dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)))
     83forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)))
    8484void ?{}( thread_dtor_guard_t & this,
    85                 T & thrd, void(*defaultResumptionHandler)(ThreadCancelled(T) &)) {
    86         $monitor * m = get_monitor(thrd);
     85                T & thrd, void(*cancelHandler)(ThreadCancelled(T) &)) {
     86        $monitor * m = get_monitor(thrd);
    8787        $thread * desc = get_thread(thrd);
    8888
    8989        // Setup the monitor guard
    9090        void (*dtor)(T& mutex this) = ^?{};
    91         bool join = defaultResumptionHandler != (void(*)(ThreadCancelled(T)&))0;
     91        bool join = cancelHandler != (void(*)(ThreadCancelled(T)&))0;
    9292        (this.mg){&m, (void(*)())dtor, join};
    9393
     
    103103        }
    104104        desc->state = Cancelled;
    105         if (!join) {
    106                 defaultResumptionHandler = default_thread_cancel_handler;
    107         }
     105        void(*defaultResumptionHandler)(ThreadCancelled(T) &) =
     106                join ? cancelHandler : default_thread_cancel_handler;
    108107
    109108        ThreadCancelled(T) except;
     
    125124//-----------------------------------------------------------------------------
    126125// Starting and stopping threads
    127 forall( dtype T | is_thread(T) )
     126forall( T & | is_thread(T) )
    128127void __thrd_start( T & this, void (*main_p)(T &) ) {
    129128        $thread * this_thrd = get_thread(this);
     
    141140//-----------------------------------------------------------------------------
    142141// Support for threads that don't ues the thread keyword
    143 forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T&); } )
     142forall( T & | sized(T) | is_thread(T) | { void ?{}(T&); } )
    144143void ?{}( scoped(T)& this ) with( this ) {
    145144        handle{};
     
    147146}
    148147
    149 forall( dtype T, ttype P | sized(T) | is_thread(T) | { void ?{}(T&, P); } )
     148forall( T &, P... | sized(T) | is_thread(T) | { void ?{}(T&, P); } )
    150149void ?{}( scoped(T)& this, P params ) with( this ) {
    151150        handle{ params };
     
    153152}
    154153
    155 forall( dtype T | sized(T) | is_thread(T) )
     154forall( T & | sized(T) | is_thread(T) )
    156155void ^?{}( scoped(T)& this ) with( this ) {
    157156        ^handle{};
     
    159158
    160159//-----------------------------------------------------------------------------
    161 forall(dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))
     160forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))
    162161T & join( T & this ) {
    163162        thread_dtor_guard_t guard = { this, defaultResumptionHandler };
  • libcfa/src/concurrency/thread.hfa

    rb6a8b31 rd95969a  
    2626//-----------------------------------------------------------------------------
    2727// thread trait
    28 trait is_thread(dtype T) {
     28trait is_thread(T &) {
    2929        void ^?{}(T& mutex this);
    3030        void main(T& this);
     
    3232};
    3333
    34 FORALL_DATA_EXCEPTION(ThreadCancelled, (dtype thread_t), (thread_t)) (
     34FORALL_DATA_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
    3535        thread_t * the_thread;
    3636        exception_t * the_exception;
    3737);
    3838
    39 forall(dtype T)
     39forall(T &)
    4040void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src);
    4141
    42 forall(dtype T)
     42forall(T &)
    4343const char * msg(ThreadCancelled(T) *);
    4444
     
    4747
    4848// Inline getters for threads/coroutines/monitors
    49 forall( dtype T | is_thread(T) )
     49forall( T & | is_thread(T) )
    5050static inline $coroutine* get_coroutine(T & this) __attribute__((const)) { return &get_thread(this)->self_cor; }
    5151
    52 forall( dtype T | is_thread(T) )
     52forall( T & | is_thread(T) )
    5353static inline $monitor  * get_monitor  (T & this) __attribute__((const)) { return &get_thread(this)->self_mon; }
    5454
     
    6060extern struct cluster * mainCluster;
    6161
    62 forall( dtype T | is_thread(T) )
     62forall( T & | is_thread(T) )
    6363void __thrd_start( T & this, void (*)(T &) );
    6464
     
    8282};
    8383
    84 forall( dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )
     84forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )
    8585void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
    8686void ^?{}( thread_dtor_guard_t & this );
     
    8989// thread runner
    9090// Structure that actually start and stop threads
    91 forall( dtype T | sized(T) | is_thread(T) )
     91forall( T & | sized(T) | is_thread(T) )
    9292struct scoped {
    9393        T handle;
    9494};
    9595
    96 forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T&); } )
     96forall( T & | sized(T) | is_thread(T) | { void ?{}(T&); } )
    9797void ?{}( scoped(T)& this );
    9898
    99 forall( dtype T, ttype P | sized(T) | is_thread(T) | { void ?{}(T&, P); } )
     99forall( T &, P... | sized(T) | is_thread(T) | { void ?{}(T&, P); } )
    100100void ?{}( scoped(T)& this, P params );
    101101
    102 forall( dtype T | sized(T) | is_thread(T) )
     102forall( T & | sized(T) | is_thread(T) )
    103103void ^?{}( scoped(T)& this );
    104104
     
    115115void unpark( $thread * this );
    116116
    117 forall( dtype T | is_thread(T) )
     117forall( T & | is_thread(T) )
    118118static inline void unpark( T & this ) { if(!&this) return; unpark( get_thread( this ) );}
    119119
     
    128128//----------
    129129// join
    130 forall( dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) )
     130forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) )
    131131T & join( T & this );
    132132
  • libcfa/src/containers/list.hfa

    rb6a8b31 rd95969a  
    6666#define __DLISTED_MGD_JUSTIMPL(STRUCT)
    6767
    68 forall( dtype tE ) {
     68forall( tE & ) {
    6969        struct $mgd_link {
    7070                tE *elem;
     
    8383                (this.is_terminator){ 1 };
    8484        }
    85         forall ( otype tInit | { void ?{}( $mgd_link(tE) &, tInit); } )
     85        forall ( tInit | { void ?{}( $mgd_link(tE) &, tInit); } )
    8686        static inline void ?=?( $mgd_link(tE) &this, tInit i ) {
    8787                ^?{}( this );
     
    115115  __DLISTED_MGD_COMMON(STRUCT, STRUCT, $links)
    116116
    117 trait $dlistable(dtype Tnode, dtype Telem) {
     117trait $dlistable(Tnode &, Telem &) {
    118118        $mgd_link(Telem) & $prev_link(Tnode &);
    119119        $mgd_link(Telem) & $next_link(Tnode &);
     
    125125};
    126126
    127 forall (dtype Tnode, dtype Telem | $dlistable(Tnode, Telem)) {
     127forall (Tnode &, Telem & | $dlistable(Tnode, Telem)) {
    128128
    129129        // implemented as a sentinel item in an underlying cicrular list
  • libcfa/src/containers/maybe.cfa

    rb6a8b31 rd95969a  
    1818
    1919
    20 forall(otype T)
     20forall(T)
    2121void ?{}(maybe(T) & this) {
    2222        this.has_value = false;
    2323}
    2424
    25 forall(otype T)
     25forall(T)
    2626void ?{}(maybe(T) & this, T value) {
    2727        this.has_value = true;
     
    2929}
    3030
    31 forall(otype T)
     31forall(T)
    3232void ?{}(maybe(T) & this, maybe(T) other) {
    3333        this.has_value = other.has_value;
     
    3737}
    3838
    39 forall(otype T)
     39forall(T)
    4040maybe(T) ?=?(maybe(T) & this, maybe(T) that) {
    4141        if (this.has_value && that.has_value) {
     
    5151}
    5252
    53 forall(otype T)
     53forall(T)
    5454void ^?{}(maybe(T) & this) {
    5555        if (this.has_value) {
     
    5858}
    5959
    60 forall(otype T)
     60forall(T)
    6161bool ?!=?(maybe(T) this, zero_t) {
    6262        return this.has_value;
    6363}
    6464
    65 forall(otype T)
     65forall(T)
    6666maybe(T) maybe_value(T value) {
    6767        return (maybe(T)){value};
    6868}
    6969
    70 forall(otype T)
     70forall(T)
    7171maybe(T) maybe_none() {
    7272        return (maybe(T)){};
    7373}
    7474
    75 forall(otype T)
     75forall(T)
    7676bool has_value(maybe(T) * this) {
    7777        return this->has_value;
    7878}
    7979
    80 forall(otype T)
     80forall(T)
    8181T get(maybe(T) * this) {
    8282        assertf(this->has_value, "attempt to get from maybe without value");
     
    8484}
    8585
    86 forall(otype T)
     86forall(T)
    8787void set(maybe(T) * this, T value) {
    8888        if (this->has_value) {
     
    9494}
    9595
    96 forall(otype T)
     96forall(T)
    9797void set_none(maybe(T) * this) {
    9898        if (this->has_value) {
  • libcfa/src/containers/maybe.hfa

    rb6a8b31 rd95969a  
    1919
    2020// DO NOT USE DIRECTLY!
    21 forall(otype T)
     21forall(T)
    2222struct maybe {
    2323    bool has_value;
     
    2626
    2727
    28 forall(otype T)
     28forall(T)
    2929void ?{}(maybe(T) & this);
    3030
    31 forall(otype T)
     31forall(T)
    3232void ?{}(maybe(T) & this, T value);
    3333
    34 forall(otype T)
     34forall(T)
    3535void ?{}(maybe(T) & this, maybe(T) other);
    3636
    37 forall(otype T)
     37forall(T)
    3838void ^?{}(maybe(T) & this);
    3939
    40 forall(otype T)
     40forall(T)
    4141maybe(T) ?=?(maybe(T) & this, maybe(T) other);
    4242
    43 forall(otype T)
     43forall(T)
    4444bool ?!=?(maybe(T) this, zero_t);
    4545
    4646/* Waiting for bug#11 to be fixed.
    47 forall(otype T)
     47forall(T)
    4848maybe(T) maybe_value(T value);
    4949
    50 forall(otype T)
     50forall(T)
    5151maybe(T) maybe_none();
    5252*/
    5353
    54 forall(otype T)
     54forall(T)
    5555bool has_value(maybe(T) * this);
    5656
    57 forall(otype T)
     57forall(T)
    5858T get(maybe(T) * this);
    5959
    60 forall(otype T)
     60forall(T)
    6161void set(maybe(T) * this, T value);
    6262
    63 forall(otype T)
     63forall(T)
    6464void set_none(maybe(T) * this);
    6565
  • libcfa/src/containers/pair.cfa

    rb6a8b31 rd95969a  
    1313#include <containers/pair.hfa>
    1414
    15 forall(otype R, otype S
     15forall(R, S
    1616        | { int ?==?(R, R); int ?<?(R, R); int ?<?(S, S); })
    1717int ?<?(pair(R, S) p, pair(R, S) q) {
     
    1919}
    2020
    21 forall(otype R, otype S
     21forall(R, S
    2222        | { int ?==?(R, R); int ?<?(R, R); int ?<=?(S, S); })
    2323int ?<=?(pair(R, S) p, pair(R, S) q) {
     
    2525}
    2626
    27 forall(otype R, otype S | { int ?==?(R, R); int ?==?(S, S); })
     27forall(R, S | { int ?==?(R, R); int ?==?(S, S); })
    2828int ?==?(pair(R, S) p, pair(R, S) q) {
    2929        return p.first == q.first && p.second == q.second;
    3030}
    3131
    32 forall(otype R, otype S | { int ?!=?(R, R); int ?!=?(S, S); })
     32forall(R, S | { int ?!=?(R, R); int ?!=?(S, S); })
    3333int ?!=?(pair(R, S) p, pair(R, S) q) {
    3434        return p.first != q.first || p.second != q.second;
    3535}
    3636
    37 forall(otype R, otype S
     37forall(R, S
    3838        | { int ?==?(R, R); int ?>?(R, R); int ?>?(S, S); })
    3939int ?>?(pair(R, S) p, pair(R, S) q) {
     
    4141}
    4242
    43 forall(otype R, otype S
     43forall(R, S
    4444        | { int ?==?(R, R); int ?>?(R, R); int ?>=?(S, S); })
    4545int ?>=?(pair(R, S) p, pair(R, S) q) {
  • libcfa/src/containers/pair.hfa

    rb6a8b31 rd95969a  
    1616#pragma once
    1717
    18 forall(otype R, otype S) struct pair {
     18forall(R, S) struct pair {
    1919        R first;
    2020        S second;
    2121};
    2222
    23 forall(otype R, otype S
     23forall(R, S
    2424        | { int ?==?(R, R); int ?<?(R, R); int ?<?(S, S); })
    2525int ?<?(pair(R, S) p, pair(R, S) q);
    2626
    27 forall(otype R, otype S
     27forall(R, S
    2828        | { int ?==?(R, R); int ?<?(R, R); int ?<=?(S, S); })
    2929int ?<=?(pair(R, S) p, pair(R, S) q);
    3030
    31 forall(otype R, otype S | { int ?==?(R, R); int ?==?(S, S); })
     31forall(R, S | { int ?==?(R, R); int ?==?(S, S); })
    3232int ?==?(pair(R, S) p, pair(R, S) q);
    3333
    34 forall(otype R, otype S | { int ?!=?(R, R); int ?!=?(S, S); })
     34forall(R, S | { int ?!=?(R, R); int ?!=?(S, S); })
    3535int ?!=?(pair(R, S) p, pair(R, S) q);
    3636
    37 forall(otype R, otype S
     37forall(R, S
    3838        | { int ?==?(R, R); int ?>?(R, R); int ?>?(S, S); })
    3939int ?>?(pair(R, S) p, pair(R, S) q);
    4040
    41 forall(otype R, otype S
     41forall(R, S
    4242        | { int ?==?(R, R); int ?>?(R, R); int ?>=?(S, S); })
    4343int ?>=?(pair(R, S) p, pair(R, S) q);
  • libcfa/src/containers/result.cfa

    rb6a8b31 rd95969a  
    1818
    1919
    20 forall(otype T, otype E)
     20forall(T, E)
    2121void ?{}(result(T, E) & this) {
    2222        this.has_value = false;
     
    2424}
    2525
    26 forall(otype T, otype E)
     26forall(T, E)
    2727void ?{}(result(T, E) & this, one_t, T value) {
    2828        this.has_value = true;
     
    3030}
    3131
    32 forall(otype T, otype E)
     32forall(T, E)
    3333void ?{}(result(T, E) & this, zero_t, E error) {
    3434        this.has_value = false;
     
    3636}
    3737
    38 forall(otype T, otype E)
     38forall(T, E)
    3939void ?{}(result(T, E) & this, result(T, E) other) {
    4040        this.has_value = other.has_value;
     
    4646}
    4747
    48 forall(otype T, otype E)
     48forall(T, E)
    4949result(T, E) ?=?(result(T, E) & this, result(T, E) that) {
    5050        if (this.has_value && that.has_value) {
     
    6363}
    6464
    65 forall(otype T, otype E)
     65forall(T, E)
    6666void ^?{}(result(T, E) & this) {
    6767        if (this.has_value) {
     
    7272}
    7373
    74 forall(otype T, otype E)
     74forall(T, E)
    7575bool ?!=?(result(T, E) this, zero_t) {
    7676        return this.has_value;
    7777}
    7878
    79 forall(otype T, otype E)
     79forall(T, E)
    8080result(T, E) result_value(T value) {
    8181        return (result(T, E)){1, value};
    8282}
    8383
    84 forall(otype T, otype E)
     84forall(T, E)
    8585result(T, E) result_error(E error) {
    8686        return (result(T, E)){0, error};
    8787}
    8888
    89 forall(otype T, otype E)
     89forall(T, E)
    9090bool has_value(result(T, E) * this) {
    9191        return this->has_value;
    9292}
    9393
    94 forall(otype T, otype E)
     94forall(T, E)
    9595T get(result(T, E) * this) {
    9696        assertf(this->has_value, "attempt to get from result without value");
     
    9898}
    9999
    100 forall(otype T, otype E)
     100forall(T, E)
    101101E get_error(result(T, E) * this) {
    102102        assertf(!this->has_value, "attempt to get from result without error");
     
    104104}
    105105
    106 forall(otype T, otype E)
     106forall(T, E)
    107107void set(result(T, E) * this, T value) {
    108108        if (this->has_value) {
     
    115115}
    116116
    117 forall(otype T, otype E)
     117forall(T, E)
    118118void set_error(result(T, E) * this, E error) {
    119119        if (this->has_value) {
  • libcfa/src/containers/result.hfa

    rb6a8b31 rd95969a  
    1919
    2020// DO NOT USE DIRECTLY!
    21 forall(otype T, otype E)
     21forall(T, E)
    2222union inner_result{
    2323        T value;
     
    2525};
    2626
    27 forall(otype T, otype E)
     27forall(T, E)
    2828struct result {
    2929        bool has_value;
     
    3232
    3333
    34 forall(otype T, otype E)
     34forall(T, E)
    3535void ?{}(result(T, E) & this);
    3636
    37 forall(otype T, otype E)
     37forall(T, E)
    3838void ?{}(result(T, E) & this, one_t, T value);
    3939
    40 forall(otype T, otype E)
     40forall(T, E)
    4141void ?{}(result(T, E) & this, zero_t, E error);
    4242
    43 forall(otype T, otype E)
     43forall(T, E)
    4444void ?{}(result(T, E) & this, result(T, E) other);
    4545
    46 forall(otype T, otype E)
     46forall(T, E)
    4747void ^?{}(result(T, E) & this);
    4848
    49 forall(otype T, otype E)
     49forall(T, E)
    5050result(T, E) ?=?(result(T, E) & this, result(T, E) other);
    5151
    52 forall(otype T, otype E)
     52forall(T, E)
    5353bool ?!=?(result(T, E) this, zero_t);
    5454
    5555/* Wating for bug#11 to be fixed.
    56 forall(otype T, otype E)
     56forall(T, E)
    5757result(T, E) result_value(T value);
    5858
    59 forall(otype T, otype E)
     59forall(T, E)
    6060result(T, E) result_error(E error);
    6161*/
    6262
    63 forall(otype T, otype E)
     63forall(T, E)
    6464bool has_value(result(T, E) * this);
    6565
    66 forall(otype T, otype E)
     66forall(T, E)
    6767T get(result(T, E) * this);
    6868
    69 forall(otype T, otype E)
     69forall(T, E)
    7070E get_error(result(T, E) * this);
    7171
    72 forall(otype T, otype E)
     72forall(T, E)
    7373void set(result(T, E) * this, T value);
    7474
    75 forall(otype T, otype E)
     75forall(T, E)
    7676void set_error(result(T, E) * this, E error);
    7777
  • libcfa/src/containers/stackLockFree.hfa

    rb6a8b31 rd95969a  
    99// Created On       : Wed May 13 20:58:58 2020
    1010// Last Modified By : Peter A. Buhr
    11 // Last Modified On : Sun Jun 14 13:25:09 2020
    12 // Update Count     : 64
     11// Last Modified On : Wed Jan 20 20:40:03 2021
     12// Update Count     : 67
    1313//
    1414
     
    1717#include <stdint.h>
    1818
    19 forall( dtype T )
     19forall( T & )
    2020union Link {
    2121        struct {                                                                                        // 32/64-bit x 2
     
    3131}; // Link
    3232
    33 forall( otype T | sized(T) | { Link(T) * ?`next( T * ); } ) {
     33forall( T | sized(T) | { Link(T) * ?`next( T * ); } ) {
    3434        struct StackLF {
    3535                Link(T) stack;
     
    4242
    4343                void push( StackLF(T) & this, T & n ) with(this) {
    44                         *( &n )`next = stack;                                   // atomic assignment unnecessary, or use CAA
     44                        *( &n )`next = stack;                                           // atomic assignment unnecessary, or use CAA
    4545                        for () {                                                                        // busy wait
    4646                          if ( __atomic_compare_exchange_n( &stack.atom, &( &n )`next->atom, (Link(T))@{ {&n, ( &n )`next->count + 1} }.atom, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) break; // attempt to update top node
     
    6565                                }
    6666                                if( next == 0p ) return false;
    67                                 link = (next)`next;
     67                                link = ( next )`next;
    6868                        }
    6969                }
  • libcfa/src/containers/vector.cfa

    rb6a8b31 rd95969a  
    1818#include <stdlib.hfa>
    1919
    20 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     20forall(T, allocator_t | allocator_c(T, allocator_t))
    2121void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other);
    2222
    2323//------------------------------------------------------------------------------
    2424//Initialization
    25 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     25forall(T, allocator_t | allocator_c(T, allocator_t))
    2626void ?{}(vector(T, allocator_t)& this)
    2727{
     
    3030}
    3131
    32 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     32forall(T, allocator_t | allocator_c(T, allocator_t))
    3333void ?{}(vector(T, allocator_t)& this, vector(T, allocator_t) rhs)
    3434{
     
    3737}
    3838
    39 // forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     39// forall(T, allocator_t | allocator_c(T, allocator_t))
    4040// vector(T, allocator_t) ?=?(vector(T, allocator_t)* this, vector(T, allocator_t) rhs)
    4141// {
     
    4545// }
    4646
    47 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     47forall(T, allocator_t | allocator_c(T, allocator_t))
    4848void ^?{}(vector(T, allocator_t)& this)
    4949{
     
    5454//------------------------------------------------------------------------------
    5555//Modifiers
    56 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     56forall(T, allocator_t | allocator_c(T, allocator_t))
    5757void push_back(vector(T, allocator_t)* this, T value)
    5858{
     
    6262}
    6363
    64 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     64forall(T, allocator_t | allocator_c(T, allocator_t))
    6565void pop_back(vector(T, allocator_t)* this)
    6666{
     
    6969}
    7070
    71 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     71forall(T, allocator_t | allocator_c(T, allocator_t))
    7272void clear(vector(T, allocator_t)* this)
    7373{
     
    8282//Internal Helpers
    8383
    84 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     84forall(T, allocator_t | allocator_c(T, allocator_t))
    8585void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other)
    8686{
     
    9393//------------------------------------------------------------------------------
    9494//Allocator
    95 forall(otype T)
     95forall(T)
    9696void ?{}(heap_allocator(T)& this)
    9797{
     
    100100}
    101101
    102 forall(otype T)
     102forall(T)
    103103void ?{}(heap_allocator(T)& this, heap_allocator(T) rhs)
    104104{
     
    107107}
    108108
    109 forall(otype T)
     109forall(T)
    110110heap_allocator(T) ?=?(heap_allocator(T)& this, heap_allocator(T) rhs)
    111111{
     
    115115}
    116116
    117 forall(otype T)
     117forall(T)
    118118void ^?{}(heap_allocator(T)& this)
    119119{
     
    121121}
    122122
    123 forall(otype T)
     123forall(T)
    124124inline void realloc_storage(heap_allocator(T)* this, size_t size)
    125125{
  • libcfa/src/containers/vector.hfa

    rb6a8b31 rd95969a  
    2020//------------------------------------------------------------------------------
    2121//Allocator
    22 forall(otype T)
     22forall(T)
    2323struct heap_allocator
    2424{
     
    2727};
    2828
    29 forall(otype T)
     29forall(T)
    3030void ?{}(heap_allocator(T)& this);
    3131
    32 forall(otype T)
     32forall(T)
    3333void ?{}(heap_allocator(T)& this, heap_allocator(T) rhs);
    3434
    35 forall(otype T)
     35forall(T)
    3636heap_allocator(T) ?=?(heap_allocator(T)& this, heap_allocator(T) rhs);
    3737
    38 forall(otype T)
     38forall(T)
    3939void ^?{}(heap_allocator(T)& this);
    4040
    41 forall(otype T)
     41forall(T)
    4242void realloc_storage(heap_allocator(T)* this, size_t size);
    4343
    44 forall(otype T)
     44forall(T)
    4545static inline T* data(heap_allocator(T)* this)
    4646{
     
    5050//------------------------------------------------------------------------------
    5151//Declaration
    52 trait allocator_c(otype T, otype allocator_t)
     52trait allocator_c(T, allocator_t)
    5353{
    5454        void realloc_storage(allocator_t*, size_t);
     
    5656};
    5757
    58 forall(otype T, otype allocator_t = heap_allocator(T) | allocator_c(T, allocator_t))
     58forall(T, allocator_t = heap_allocator(T) | allocator_c(T, allocator_t))
    5959struct vector;
    6060
    6161//------------------------------------------------------------------------------
    6262//Initialization
    63 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     63forall(T, allocator_t | allocator_c(T, allocator_t))
    6464void ?{}(vector(T, allocator_t)& this);
    6565
    66 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     66forall(T, allocator_t | allocator_c(T, allocator_t))
    6767void ?{}(vector(T, allocator_t)& this, vector(T, allocator_t) rhs);
    6868
    69 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     69forall(T, allocator_t | allocator_c(T, allocator_t))
    7070vector(T, allocator_t) ?=?(vector(T, allocator_t)& this, vector(T, allocator_t) rhs);
    7171
    72 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     72forall(T, allocator_t | allocator_c(T, allocator_t))
    7373void ^?{}(vector(T, allocator_t)& this);
    7474
    75 forall(otype T, otype allocator_t = heap_allocator(T) | allocator_c(T, allocator_t))
     75forall(T, allocator_t = heap_allocator(T) | allocator_c(T, allocator_t))
    7676struct vector
    7777{
     
    8282//------------------------------------------------------------------------------
    8383//Capacity
    84 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     84forall(T, allocator_t | allocator_c(T, allocator_t))
    8585static inline bool empty(vector(T, allocator_t)* this)
    8686{
     
    8888}
    8989
    90 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     90forall(T, allocator_t | allocator_c(T, allocator_t))
    9191static inline size_t size(vector(T, allocator_t)* this)
    9292{
     
    9494}
    9595
    96 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     96forall(T, allocator_t | allocator_c(T, allocator_t))
    9797static inline void reserve(vector(T, allocator_t)* this, size_t size)
    9898{
     
    102102//------------------------------------------------------------------------------
    103103//Element access
    104 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     104forall(T, allocator_t | allocator_c(T, allocator_t))
    105105static inline T at(vector(T, allocator_t)* this, size_t index)
    106106{
     
    108108}
    109109
    110 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     110forall(T, allocator_t | allocator_c(T, allocator_t))
    111111static inline T ?[?](vector(T, allocator_t)* this, size_t index)
    112112{
     
    114114}
    115115
    116 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     116forall(T, allocator_t | allocator_c(T, allocator_t))
    117117static inline T front(vector(T, allocator_t)* this)
    118118{
     
    120120}
    121121
    122 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     122forall(T, allocator_t | allocator_c(T, allocator_t))
    123123static inline T back(vector(T, allocator_t)* this)
    124124{
     
    128128//------------------------------------------------------------------------------
    129129//Modifiers
    130 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     130forall(T, allocator_t | allocator_c(T, allocator_t))
    131131void push_back(vector(T, allocator_t)* this, T value);
    132132
    133 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     133forall(T, allocator_t | allocator_c(T, allocator_t))
    134134void pop_back(vector(T, allocator_t)* this);
    135135
    136 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     136forall(T, allocator_t | allocator_c(T, allocator_t))
    137137void clear(vector(T, allocator_t)* this);
    138138
    139139//------------------------------------------------------------------------------
    140140//Iterators
    141 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     141forall(T, allocator_t | allocator_c(T, allocator_t))
    142142static inline T* begin(vector(T, allocator_t)* this)
    143143{
     
    145145}
    146146
    147 // forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     147// forall(T, allocator_t | allocator_c(T, allocator_t))
    148148// static inline const T* cbegin(const vector(T, allocator_t)* this)
    149149// {
     
    151151// }
    152152
    153 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     153forall(T, allocator_t | allocator_c(T, allocator_t))
    154154static inline T* end(vector(T, allocator_t)* this)
    155155{
     
    157157}
    158158
    159 // forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     159// forall(T, allocator_t | allocator_c(T, allocator_t))
    160160// static inline const T* cend(const vector(T, allocator_t)* this)
    161161// {
  • libcfa/src/exception.h

    rb6a8b31 rd95969a  
    101101// implemented in the .c file either so they all have to be inline.
    102102
    103 trait is_exception(dtype exceptT, dtype virtualT) {
     103trait is_exception(exceptT &, virtualT &) {
    104104        /* The first field must be a pointer to a virtual table.
    105105         * That virtual table must be a decendent of the base exception virtual table.
     
    109109};
    110110
    111 trait is_termination_exception(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT)) {
     111trait is_termination_exception(exceptT &, virtualT & | is_exception(exceptT, virtualT)) {
    112112        void defaultTerminationHandler(exceptT &);
    113113};
    114114
    115 trait is_resumption_exception(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT)) {
     115trait is_resumption_exception(exceptT &, virtualT & | is_exception(exceptT, virtualT)) {
    116116        void defaultResumptionHandler(exceptT &);
    117117};
    118118
    119 forall(dtype exceptT, dtype virtualT | is_termination_exception(exceptT, virtualT))
     119forall(exceptT &, virtualT & | is_termination_exception(exceptT, virtualT))
    120120static inline void $throw(exceptT & except) {
    121121        __cfaehm_throw_terminate(
     
    125125}
    126126
    127 forall(dtype exceptT, dtype virtualT | is_resumption_exception(exceptT, virtualT))
     127forall(exceptT &, virtualT & | is_resumption_exception(exceptT, virtualT))
    128128static inline void $throwResume(exceptT & except) {
    129129        __cfaehm_throw_resume(
     
    133133}
    134134
    135 forall(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT))
     135forall(exceptT &, virtualT & | is_exception(exceptT, virtualT))
    136136static inline void cancel_stack(exceptT & except) __attribute__((noreturn)) {
    137137        __cfaehm_cancel_stack( (exception_t *)&except );
    138138}
    139139
    140 forall(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT))
     140forall(exceptT &, virtualT & | is_exception(exceptT, virtualT))
    141141static inline void defaultTerminationHandler(exceptT & except) {
    142142        return cancel_stack( except );
    143143}
    144144
    145 forall(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT))
     145forall(exceptT &, virtualT & | is_exception(exceptT, virtualT))
    146146static inline void defaultResumptionHandler(exceptT & except) {
    147147        throw except;
  • libcfa/src/executor.cfa

    rb6a8b31 rd95969a  
    77#include <containers/list.hfa>
    88
    9 forall( dtype T | $dlistable(T, T) ) {
     9forall( T & | $dlistable(T, T) ) {
    1010        monitor Buffer {                                                                        // unbounded buffer
    1111                dlist( T, T ) queue;                                                    // unbounded list of work requests
  • libcfa/src/gmp.hfa

    rb6a8b31 rd95969a  
    255255
    256256        // I/O
    257         forall( dtype istype | istream( istype ) )
     257        forall( istype & | istream( istype ) )
    258258                istype & ?|?( istype & is, Int & mp ) {
    259259                gmp_scanf( "%Zd", &mp );
     
    261261        } // ?|?
    262262
    263         forall( dtype ostype | ostream( ostype ) ) {
     263        forall( ostype & | ostream( ostype ) ) {
    264264                ostype & ?|?( ostype & os, Int mp ) {
    265265                        if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
  • libcfa/src/interpose.cfa

    rb6a8b31 rd95969a  
    125125
    126126                // Failure handler
    127                 __cfaabi_sigaction( SIGSEGV, sigHandler_segv, SA_SIGINFO | SA_ONSTACK );
    128                 __cfaabi_sigaction( SIGBUS , sigHandler_segv, SA_SIGINFO | SA_ONSTACK );
    129                 __cfaabi_sigaction( SIGILL , sigHandler_ill , SA_SIGINFO | SA_ONSTACK );
    130                 __cfaabi_sigaction( SIGFPE , sigHandler_fpe , SA_SIGINFO | SA_ONSTACK );
    131                 __cfaabi_sigaction( SIGTERM, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // one shot handler, return to default
    132                 __cfaabi_sigaction( SIGINT , sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND );
    133                 __cfaabi_sigaction( SIGABRT, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND );
    134                 __cfaabi_sigaction( SIGHUP , sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // terminal hangup
     127                 // internal errors
     128                __cfaabi_sigaction( SIGSEGV, sigHandler_segv, SA_SIGINFO | SA_ONSTACK ); // Invalid memory reference (default: Core)
     129                __cfaabi_sigaction( SIGBUS , sigHandler_segv, SA_SIGINFO | SA_ONSTACK ); // Bus error, bad memory access (default: Core)
     130                __cfaabi_sigaction( SIGILL , sigHandler_ill , SA_SIGINFO | SA_ONSTACK ); // Illegal Instruction (default: Core)
     131                __cfaabi_sigaction( SIGFPE , sigHandler_fpe , SA_SIGINFO | SA_ONSTACK ); // Floating-point exception (default: Core)
     132
     133                // handlers to outside errors
     134                // reset in-case they insist and send it over and over
     135                __cfaabi_sigaction( SIGTERM, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // Termination signal (default: Term)
     136                __cfaabi_sigaction( SIGINT , sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // Interrupt from keyboard (default: Term)
     137                __cfaabi_sigaction( SIGHUP , sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // Hangup detected on controlling terminal or death of controlling process (default: Term)
     138                __cfaabi_sigaction( SIGQUIT, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // Quit from keyboard (default: Core)
     139                __cfaabi_sigaction( SIGABRT, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // Abort signal from abort(3) (default: Core)
    135140        }
    136141}
     
    163168}
    164169
    165 void * kernel_abort( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 0p; }
    166 void kernel_abort_msg( void * data, char buffer[], int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
    167 // See concurrency/kernel.cfa for strong definition used in multi-processor mode.
    168 int kernel_abort_lastframe( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 4; }
     170// See concurrency/kernel.cfa and concurrency/preemption.cfa for strong definition used in multi-processor mode.
     171void __kernel_abort_lock( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
     172void __kernel_abort_msg( char buffer[], int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
     173int __kernel_abort_lastframe( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 4; }
    169174
    170175enum { abort_text_size = 1024 };
     
    173178static void __cfaabi_backtrace( int start ) {
    174179        enum { Frames = 50, };                                                          // maximum number of stack frames
    175         int last = kernel_abort_lastframe();                            // skip last N stack frames
     180        int last = __kernel_abort_lastframe();                          // skip last N stack frames
    176181
    177182        void * array[Frames];
     
    220225}
    221226
    222 static volatile int __abort_stage = 0;
     227static volatile bool __abort_first = 0;
    223228
    224229// Cannot forward va_list.
    225230void __abort( bool signalAbort, const char fmt[], va_list args ) {
    226         int stage = __atomic_add_fetch( &__abort_stage, 1, __ATOMIC_SEQ_CST );
    227 
    228         // First stage: stop the cforall kernel and print
    229         if(stage == 1) {
    230                 // increment stage
    231                 stage = __atomic_add_fetch( &__abort_stage, 1, __ATOMIC_SEQ_CST );
    232 
    233                 // must be done here to lock down kernel
    234                 void * kernel_data = kernel_abort();
    235                 int len;
    236 
    237                 signal( SIGABRT, SIG_DFL );                                                     // prevent final "real" abort from recursing to handler
    238 
    239                 len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid)
    240                 __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
    241 
    242                 assert( fmt );
    243                 len = vsnprintf( abort_text, abort_text_size, fmt, args );
    244                 __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
    245 
    246                 // add optional newline if missing at the end of the format text
    247                 if ( fmt[strlen( fmt ) - 1] != '\n' ) {
    248                         __cfaabi_bits_write( STDERR_FILENO, "\n", 1 );
    249                 } // if
    250                 kernel_abort_msg( kernel_data, abort_text, abort_text_size );
    251         }
    252 
    253         // Second stage: print the backtrace
    254         if(stage == 2) {
    255                 // increment stage
    256                 stage = __atomic_add_fetch( &__abort_stage, 1, __ATOMIC_SEQ_CST );
    257 
    258                 // print stack trace in handler
    259                 __cfaabi_backtrace( signalAbort ? 4 : 2 );
    260         }
    261 
    262         do {
    263                 // Finally call abort
     231        // Multiple threads can come here from multiple paths
     232        // To make sure this is safe any concurrent/subsequent call to abort is redirected to libc-abort
     233        bool first = ! __atomic_test_and_set( &__abort_first, __ATOMIC_SEQ_CST);
     234
     235        // Prevent preemption from kicking-in and messing with the abort
     236        __kernel_abort_lock();
     237
     238        // first to abort ?
     239        if ( !first ) {
     240                // We aren't the first to abort just let C handle it
     241                signal( SIGABRT, SIG_DFL );     // restore default in case we came here through the function.
    264242                __cabi_libc.abort();
    265 
    266                 // Loop so that we never return
    267         } while(true);
     243        }
     244
     245        int len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid)
     246        __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
     247
     248        // print the cause of the error
     249        assert( fmt );
     250        len = vsnprintf( abort_text, abort_text_size, fmt, args );
     251        __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
     252
     253        // add optional newline if missing at the end of the format text
     254        if ( fmt[strlen( fmt ) - 1] != '\n' ) {
     255                __cfaabi_bits_write( STDERR_FILENO, "\n", 1 );
     256        } // if
     257
     258        // Give the kernel the chance to add some data in here
     259        __kernel_abort_msg( abort_text, abort_text_size );
     260
     261        // print stack trace in handler
     262        __cfaabi_backtrace( signalAbort ? 4 : 2 );
     263
     264        // Finally call abort
     265        __cabi_libc.abort();
     266
    268267}
    269268
  • libcfa/src/iostream.cfa

    rb6a8b31 rd95969a  
    3636
    3737
    38 forall( dtype ostype | ostream( ostype ) ) {
     38forall( ostype & | ostream( ostype ) ) {
    3939        ostype & ?|?( ostype & os, bool b ) {
    4040                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     
    402402
    403403// tuples
    404 forall( dtype ostype, otype T, ttype Params | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) {
     404forall( ostype &, T, Params... | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) {
    405405        ostype & ?|?( ostype & os, T arg, Params rest ) {
    406406                (ostype &)(os | arg);                                                   // print first argument
     
    421421
    422422// writes the range [begin, end) to the given stream
    423 forall( dtype ostype, otype elt_type | writeable( elt_type, ostype ), otype iterator_type | iterator( iterator_type, elt_type ) ) {
     423forall( ostype &, elt_type | writeable( elt_type, ostype ), iterator_type | iterator( iterator_type, elt_type ) ) {
    424424        void write( iterator_type begin, iterator_type end, ostype & os ) {
    425425                void print( elt_type i ) { os | i; }
     
    442442// Default prefix for non-decimal prints is 0b, 0, 0x.
    443443#define IntegralFMTImpl( T, IFMTNP, IFMTP ) \
    444 forall( dtype ostype | ostream( ostype ) ) { \
     444forall( ostype & | ostream( ostype ) ) { \
    445445        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    446446                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
     
    535535// Default prefix for non-decimal prints is 0b, 0, 0x.
    536536#define IntegralFMTImpl128( T, SIGNED, CODE, IFMTNP, IFMTP ) \
    537 forall( dtype ostype | ostream( ostype ) ) \
     537forall( ostype & | ostream( ostype ) ) \
    538538static void base10_128( ostype & os, _Ostream_Manip(T) f ) { \
    539539        if ( f.val > UINT64_MAX ) { \
     
    552552        } /* if */ \
    553553} /* base10_128 */ \
    554 forall( dtype ostype | ostream( ostype ) ) { \
     554forall( ostype & | ostream( ostype ) ) { \
    555555        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    556556                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
     
    654654#if defined( __SIZEOF_INT128__ )
    655655// Default prefix for non-decimal prints is 0b, 0, 0x.
    656 forall( dtype ostype | ostream( ostype ) )
     656forall( ostype & | ostream( ostype ) )
    657657static inline void base_128( ostype & os, unsigned int128 val, unsigned int128 power, _Ostream_Manip(uint64_t) & f, unsigned int maxdig, unsigned int bits, unsigned int cnt = 0 ) {
    658658        int wd = 1;                                                                                     // f.wd is never 0 because 0 implies left-pad
     
    719719
    720720#define IntegralFMTImpl128( T ) \
    721 forall( dtype ostype | ostream( ostype ) ) { \
     721forall( ostype & | ostream( ostype ) ) { \
    722722        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    723723                _Ostream_Manip(uint64_t) fmt; \
     
    767767
    768768#define FloatingPointFMTImpl( T, DFMTNP, DFMTP ) \
    769 forall( dtype ostype | ostream( ostype ) ) { \
     769forall( ostype & | ostream( ostype ) ) { \
    770770        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    771771                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
     
    801801// *********************************** character ***********************************
    802802
    803 forall( dtype ostype | ostream( ostype ) ) {
     803forall( ostype & | ostream( ostype ) ) {
    804804        ostype & ?|?( ostype & os, _Ostream_Manip(char) f ) {
    805805                if ( f.base != 'c' ) {                                                  // bespoke binary/octal/hex format
     
    834834// *********************************** C string ***********************************
    835835
    836 forall( dtype ostype | ostream( ostype ) ) {
     836forall( ostype & | ostream( ostype ) ) {
    837837        ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f ) {
    838838                if ( ! f.val ) return os;                                               // null pointer ?
     
    882882
    883883
    884 forall( dtype istype | istream( istype ) ) {
     884forall( istype & | istream( istype ) ) {
    885885        istype & ?|?( istype & is, bool & b ) {
    886886                char val[6];
     
    10481048// *********************************** manipulators ***********************************
    10491049
    1050 forall( dtype istype | istream( istype ) )
     1050forall( istype & | istream( istype ) )
    10511051istype & ?|?( istype & is, _Istream_Cstr f ) {
    10521052        // skip xxx
     
    10831083} // ?|?
    10841084
    1085 forall( dtype istype | istream( istype ) )
     1085forall( istype & | istream( istype ) )
    10861086istype & ?|?( istype & is, _Istream_Char f ) {
    10871087        fmt( is, "%*c" );                                                                       // argument variable unused
     
    10901090
    10911091#define InputFMTImpl( T, CODE ) \
    1092 forall( dtype istype | istream( istype ) ) \
     1092forall( istype & | istream( istype ) ) \
    10931093istype & ?|?( istype & is, _Istream_Manip(T) f ) { \
    10941094        enum { size = 16 }; \
     
    11191119InputFMTImpl( long double, "Lf" )
    11201120
    1121 forall( dtype istype | istream( istype ) )
     1121forall( istype & | istream( istype ) )
    11221122istype & ?|?( istype & is, _Istream_Manip(float _Complex) fc ) {
    11231123        float re, im;
     
    11301130} // ?|?
    11311131
    1132 forall( dtype istype | istream( istype ) )
     1132forall( istype & | istream( istype ) )
    11331133istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) {
    11341134        double re, im;
     
    11411141} // ?|?
    11421142
    1143 forall( dtype istype | istream( istype ) )
     1143forall( istype & | istream( istype ) )
    11441144istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) {
    11451145        long double re, im;
  • libcfa/src/iostream.hfa

    rb6a8b31 rd95969a  
    2222
    2323
    24 trait ostream( dtype ostype ) {
     24trait ostream( ostype & ) {
    2525        // private
    2626        bool $sepPrt( ostype & );                                                       // get separator state (on/off)
     
    5656}; // ostream
    5757
    58 // trait writeable( otype T ) {
    59 //      forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype &, T );
     58// trait writeable( T ) {
     59//      forall( ostype & | ostream( ostype ) ) ostype & ?|?( ostype &, T );
    6060// }; // writeable
    6161
    62 trait writeable( otype T, dtype ostype | ostream( ostype ) ) {
     62trait writeable( T, ostype & | ostream( ostype ) ) {
    6363        ostype & ?|?( ostype &, T );
    6464}; // writeable
     
    6666// implement writable for intrinsic types
    6767
    68 forall( dtype ostype | ostream( ostype ) ) {
     68forall( ostype & | ostream( ostype ) ) {
    6969        ostype & ?|?( ostype &, bool );
    7070        void ?|?( ostype &, bool );
     
    140140
    141141// tuples
    142 forall( dtype ostype, otype T, ttype Params | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) {
     142forall( ostype &, T, Params... | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) {
    143143        ostype & ?|?( ostype & os, T arg, Params rest );
    144144        void ?|?( ostype & os, T arg, Params rest );
     
    146146
    147147// writes the range [begin, end) to the given stream
    148 forall( dtype ostype, otype elt_type | writeable( elt_type, ostype ), otype iterator_type | iterator( iterator_type, elt_type ) ) {
     148forall( ostype &, elt_type | writeable( elt_type, ostype ), iterator_type | iterator( iterator_type, elt_type ) ) {
    149149        void write( iterator_type begin, iterator_type end, ostype & os );
    150150        void write_reverse( iterator_type begin, iterator_type end, ostype & os );
     
    153153// *********************************** manipulators ***********************************
    154154
    155 forall( otype T )
     155forall( T )
    156156struct _Ostream_Manip {
    157157        T val;                                                                                          // polymorphic base-type
     
    193193        _Ostream_Manip(T) & sign( _Ostream_Manip(T) & fmt ) { fmt.flags.sign = true; return fmt; } \
    194194} /* distribution */ \
    195 forall( dtype ostype | ostream( ostype ) ) { \
     195forall( ostype & | ostream( ostype ) ) { \
    196196        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
    197197        void ?|?( ostype & os, _Ostream_Manip(T) f ); \
     
    234234        _Ostream_Manip(T) & nodp( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
    235235} /* distribution */ \
    236 forall( dtype ostype | ostream( ostype ) ) { \
     236forall( ostype & | ostream( ostype ) ) { \
    237237        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
    238238        void ?|?( ostype & os, _Ostream_Manip(T) f ); \
     
    254254        _Ostream_Manip(char) & nobase( _Ostream_Manip(char) & fmt ) { fmt.flags.nobsdp = true; return fmt; }
    255255} // distribution
    256 forall( dtype ostype | ostream( ostype ) ) {
     256forall( ostype & | ostream( ostype ) ) {
    257257        ostype & ?|?( ostype & os, _Ostream_Manip(char) f );
    258258        void ?|?( ostype & os, _Ostream_Manip(char) f );
     
    272272        _Ostream_Manip(const char *) & nobase( _Ostream_Manip(const char *) & fmt ) { fmt.flags.nobsdp = true; return fmt; }
    273273} // distribution
    274 forall( dtype ostype | ostream( ostype ) ) {
     274forall( ostype & | ostream( ostype ) ) {
    275275        ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f );
    276276        void ?|?( ostype & os, _Ostream_Manip(const char *) f );
     
    281281
    282282
    283 trait istream( dtype istype ) {
     283trait istream( istype & ) {
    284284        void nlOn( istype & );                                                          // read newline
    285285        void nlOff( istype & );                                                         // scan newline
     
    294294}; // istream
    295295
    296 trait readable( otype T ) {
    297         forall( dtype istype | istream( istype ) ) istype & ?|?( istype &, T );
     296trait readable( T ) {
     297        forall( istype & | istream( istype ) ) istype & ?|?( istype &, T );
    298298}; // readable
    299299
    300 forall( dtype istype | istream( istype ) ) {
     300forall( istype & | istream( istype ) ) {
    301301        istype & ?|?( istype &, bool & );
    302302
     
    363363        _Istream_Cstr & wdi( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; }
    364364} // distribution
    365 forall( dtype istype | istream( istype ) ) istype & ?|?( istype & is, _Istream_Cstr f );
     365forall( istype & | istream( istype ) ) istype & ?|?( istype & is, _Istream_Cstr f );
    366366
    367367struct _Istream_Char {
     
    373373        _Istream_Char & ignore( _Istream_Char & fmt ) { fmt.ignore = true; return fmt; }
    374374} // distribution
    375 forall( dtype istype | istream( istype ) ) istype & ?|?( istype & is, _Istream_Char f );
    376 
    377 forall( dtype T | sized( T ) )
     375forall( istype & | istream( istype ) ) istype & ?|?( istype & is, _Istream_Char f );
     376
     377forall( T & | sized( T ) )
    378378struct _Istream_Manip {
    379379        T & val;                                                                                        // polymorphic base-type
     
    389389        _Istream_Manip(T) & wdi( unsigned int w, _Istream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
    390390} /* distribution */ \
    391 forall( dtype istype | istream( istype ) ) { \
     391forall( istype & | istream( istype ) ) { \
    392392        istype & ?|?( istype & is, _Istream_Manip(T) f ); \
    393393} // ?|?
     
    418418#include <time_t.hfa>                                                                   // Duration (constructors) / Time (constructors)
    419419
    420 forall( dtype ostype | ostream( ostype ) ) {
     420forall( ostype & | ostream( ostype ) ) {
    421421        ostype & ?|?( ostype & os, Duration dur );
    422422        void ?|?( ostype & os, Duration dur );
  • libcfa/src/iterator.cfa

    rb6a8b31 rd95969a  
    1616#include "iterator.hfa"
    1717
    18 forall( otype iterator_type, otype elt_type | iterator( iterator_type, elt_type ) )
     18forall( iterator_type, elt_type | iterator( iterator_type, elt_type ) )
    1919void for_each( iterator_type begin, iterator_type end, void (* func)( elt_type ) ) {
    2020        for ( iterator_type i = begin; i != end; ++i ) {
     
    2323} // for_each
    2424
    25 forall( otype iterator_type, otype elt_type | iterator( iterator_type, elt_type ) )
     25forall( iterator_type, elt_type | iterator( iterator_type, elt_type ) )
    2626void for_each_reverse( iterator_type begin, iterator_type end, void (* func)( elt_type ) ) {
    2727        for ( iterator_type i = end; i != begin; ) {
  • libcfa/src/iterator.hfa

    rb6a8b31 rd95969a  
    1717
    1818// An iterator can be used to traverse a data structure.
    19 trait iterator( otype iterator_type, otype elt_type ) {
     19trait iterator( iterator_type, elt_type ) {
    2020        // point to the next element
    2121//      iterator_type ?++( iterator_type & );
     
    3131};
    3232
    33 trait iterator_for( otype iterator_type, otype collection_type, otype elt_type | iterator( iterator_type, elt_type ) ) {
     33trait iterator_for( iterator_type, collection_type, elt_type | iterator( iterator_type, elt_type ) ) {
    3434//      [ iterator_type begin, iterator_type end ] get_iterators( collection_type );
    3535        iterator_type begin( collection_type );
     
    3737};
    3838
    39 forall( otype iterator_type, otype elt_type | iterator( iterator_type, elt_type ) )
     39forall( iterator_type, elt_type | iterator( iterator_type, elt_type ) )
    4040void for_each( iterator_type begin, iterator_type end, void (* func)( elt_type ) );
    4141
    42 forall( otype iterator_type, otype elt_type | iterator( iterator_type, elt_type ) )
     42forall( iterator_type, elt_type | iterator( iterator_type, elt_type ) )
    4343void for_each_reverse( iterator_type begin, iterator_type end, void (* func)( elt_type ) );
    4444
  • libcfa/src/math.hfa

    rb6a8b31 rd95969a  
    286286        unsigned long long int floor( unsigned long long int n, unsigned long long int align ) { return n / align * align; }
    287287
    288         // forall( otype T | { T ?/?( T, T ); T ?*?( T, T ); } )
     288        // forall( T | { T ?/?( T, T ); T ?*?( T, T ); } )
    289289        // T floor( T n, T align ) { return n / align * align; }
    290290
     
    300300        unsigned long long int ceiling_div( unsigned long long int n, unsigned long long int align ) { return (n + (align - 1)) / align; }
    301301
    302         // forall( otype T | { T ?+?( T, T ); T ?-?( T, T ); T ?%?( T, T ); } )
     302        // forall( T | { T ?+?( T, T ); T ?-?( T, T ); T ?%?( T, T ); } )
    303303        // T ceiling_div( T n, T align ) { verify( is_pow2( align ) );return (n + (align - 1)) / align; }
    304304       
     
    315315        unsigned long long int ceiling( unsigned long long int n, unsigned long long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
    316316
    317         // forall( otype T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T ); T ?/?( T, T ); } )
     317        // forall( T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T ); T ?/?( T, T ); } )
    318318        // T ceiling( T n, T align ) { return return floor( n + (n % align != 0 ? align - 1 : 0), align ); *}
    319319
     
    414414
    415415static inline {
    416         forall( otype T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T );T ?*?( T, T ); } )
     416        forall( T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T );T ?*?( T, T ); } )
    417417        T lerp( T x, T y, T a ) { return x * ((T){1} - a) + y * a; }
    418418
    419         forall( otype T | { void ?{}( T &, zero_t ); void ?{}( T &, one_t ); int ?<?( T, T ); } )
     419        forall( T | { void ?{}( T &, zero_t ); void ?{}( T &, one_t ); int ?<?( T, T ); } )
    420420        T step( T edge, T x ) { return x < edge ? (T){0} : (T){1}; }
    421421
    422         forall( otype T | { void ?{}( T &, int ); T clamp( T, T, T ); T ?-?( T, T ); T ?*?( T, T ); T ?/?( T, T ); } )
     422        forall( T | { void ?{}( T &, int ); T clamp( T, T, T ); T ?-?( T, T ); T ?*?( T, T ); T ?/?( T, T ); } )
    423423        T smoothstep( T edge0, T edge1, T x ) { T t = clamp( (x - edge0) / (edge1 - edge0), (T){0}, (T){1} ); return t * t * ((T){3} - (T){2} * t); }
    424424} // distribution
  • libcfa/src/memory.cfa

    rb6a8b31 rd95969a  
    1818
    1919// Internal data object.
    20 forall(dtype T | sized(T), ttype Args | { void ?{}(T &, Args); })
     20forall(T & | sized(T), Args... | { void ?{}(T &, Args); })
    2121void ?{}(counter_data(T) & this, Args args) {
    2222        (this.counter){1};
     
    2424}
    2525
    26 forall(dtype T | sized(T) | { void ^?{}(T &); })
     26forall(T & | sized(T) | { void ^?{}(T &); })
    2727void ^?{}(counter_data(T) & this) {
    2828        assert(0 == this.counter);
     
    3131
    3232// This is one of many pointers keeping this alive.
    33 forall(dtype T | sized(T))
     33forall(T & | sized(T))
    3434void ?{}(counter_ptr(T) & this) {
    3535        this.data = 0p;
    3636}
    3737
    38 forall(dtype T | sized(T))
     38forall(T & | sized(T))
    3939void ?{}(counter_ptr(T) & this, zero_t) {
    4040        this.data = 0p;
    4141}
    4242
    43 forall(dtype T | sized(T) | { void ^?{}(T &); })
     43forall(T & | sized(T) | { void ^?{}(T &); })
    4444static void internal_decrement(counter_ptr(T) & this) {
    4545        if (this.data && 0 == --this.data->counter) {
     
    4848}
    4949
    50 forall(dtype T | sized(T))
     50forall(T & | sized(T))
    5151static void internal_copy(counter_ptr(T) & this, counter_ptr(T) & that) {
    5252        this.data = that.data;
     
    5656}
    5757
    58 forall(dtype T | sized(T) | { void ^?{}(T &); })
     58forall(T & | sized(T) | { void ^?{}(T &); })
    5959void ?{}(counter_ptr(T) & this, counter_ptr(T) that) {
    6060        // `that` is a copy but it should have neither a constructor
     
    6464}
    6565
    66 forall(dtype T | sized(T), ttype Args | { void ?{}(T&, Args); })
     66forall(T & | sized(T), Args... | { void ?{}(T&, Args); })
    6767void ?{}(counter_ptr(T) & this, Args args) {
    6868        this.data = (counter_data(T)*)new(args);
    6969}
    7070
    71 forall(dtype T | sized(T) | { void ^?{}(T &); })
     71forall(T & | sized(T) | { void ^?{}(T &); })
    7272void ^?{}(counter_ptr(T) & this) {
    7373        internal_decrement(this);
    7474}
    7575
    76 forall(dtype T | sized(T))
     76forall(T & | sized(T))
    7777T & *?(counter_ptr(T) & this) {
    7878        return *((this.data) ? &this.data->object : 0p);
    7979}
    8080
    81 forall(dtype T | sized(T) | { void ^?{}(T &); })
     81forall(T & | sized(T) | { void ^?{}(T &); })
    8282void ?=?(counter_ptr(T) & this, counter_ptr(T) that) {
    8383        if (this.data != that.data) {
     
    8787}
    8888
    89 forall(dtype T | sized(T) | { void ^?{}(T &); })
     89forall(T & | sized(T) | { void ^?{}(T &); })
    9090void ?=?(counter_ptr(T) & this, zero_t) {
    9191        internal_decrement(this);
     
    9393}
    9494
    95 forall(dtype T | sized(T))
     95forall(T & | sized(T))
    9696int ?==?(counter_ptr(T) const & this, counter_ptr(T) const & that) {
    9797        return this.data == that.data;
    9898}
    9999
    100 forall(dtype T | sized(T))
     100forall(T & | sized(T))
    101101int ?!=?(counter_ptr(T) const & this, counter_ptr(T) const & that) {
    102102        return !?==?(this, that);
    103103}
    104104
    105 forall(dtype T | sized(T))
     105forall(T & | sized(T))
    106106int ?==?(counter_ptr(T) const & this, zero_t) {
    107107        return this.data == 0;
    108108}
    109109
    110 forall(dtype T | sized(T))
     110forall(T & | sized(T))
    111111int ?!=?(counter_ptr(T) const & this, zero_t) {
    112112        return !?==?(this, (zero_t)0);
     
    114114
    115115// This is the only pointer that keeps this alive.
    116 forall(dtype T)
     116forall(T &)
    117117void ?{}(unique_ptr(T) & this) {
    118118        this.data = 0p;
    119119}
    120120
    121 forall(dtype T)
     121forall(T &)
    122122void ?{}(unique_ptr(T) & this, zero_t) {
    123123        this.data = 0p;
    124124}
    125125
    126 forall(dtype T | sized(T), ttype Args | { void ?{}(T &, Args); })
     126forall(T & | sized(T), Args... | { void ?{}(T &, Args); })
    127127void ?{}(unique_ptr(T) & this, Args args) {
    128128        this.data = (T *)new(args);
    129129}
    130130
    131 forall(dtype T | { void ^?{}(T &); })
     131forall(T & | { void ^?{}(T &); })
    132132void ^?{}(unique_ptr(T) & this) {
    133133        delete(this.data);
    134134}
    135135
    136 forall(dtype T)
     136forall(T &)
    137137T & *?(unique_ptr(T) & this) {
    138138        return *this.data;
    139139}
    140140
    141 forall(dtype T | { void ^?{}(T &); })
     141forall(T & | { void ^?{}(T &); })
    142142void ?=?(unique_ptr(T) & this, zero_t) {
    143143        delete(this.data);
     
    145145}
    146146
    147 forall(dtype T | { void ^?{}(T &); })
     147forall(T & | { void ^?{}(T &); })
    148148void move(unique_ptr(T) & this, unique_ptr(T) & that) {
    149149        delete(this.data);
     
    152152}
    153153
    154 forall(dtype T)
     154forall(T &)
    155155int ?==?(unique_ptr(T) const & this, unique_ptr(T) const & that) {
    156156        return this.data == that.data;
    157157}
    158158
    159 forall(dtype T)
     159forall(T &)
    160160int ?!=?(unique_ptr(T) const & this, unique_ptr(T) const & that) {
    161161        return !?==?(this, that);
    162162}
    163163
    164 forall(dtype T)
     164forall(T &)
    165165int ?==?(unique_ptr(T) const & this, zero_t) {
    166166        return this.data == 0;
    167167}
    168168
    169 forall(dtype T)
     169forall(T &)
    170170int ?!=?(unique_ptr(T) const & this, zero_t) {
    171171        return !?==?(this, (zero_t)0);
  • libcfa/src/memory.hfa

    rb6a8b31 rd95969a  
    1717
    1818// Internal data object.
    19 forall(dtype T | sized(T)) {
     19forall(T & | sized(T)) {
    2020        struct counter_data {
    2121                unsigned int counter;
     
    2323        };
    2424
    25         forall(ttype Args | { void ?{}(T &, Args); })
     25        forall(Args... | { void ?{}(T &, Args); })
    2626        void ?{}(counter_data(T) & this, Args args);
    2727
     
    3131
    3232// This is one of many pointers keeping this alive.
    33 forall(dtype T | sized(T)) {
     33forall(T & | sized(T)) {
    3434        struct counter_ptr {
    3535                counter_data(T) * data;
     
    4040        forall( | { void ^?{}(T &); })
    4141        void ?{}(counter_ptr(T) & this, counter_ptr(T) that);
    42         forall(ttype Args | { void ?{}(T&, Args); })
     42        forall(Args... | { void ?{}(T&, Args); })
    4343        void ?{}(counter_ptr(T) & this, Args args);
    4444
     
    6060
    6161// This is the only pointer that keeps this alive.
    62 forall(dtype T) {
     62forall(T &) {
    6363        struct unique_ptr {
    6464                T * data;
     
    6868        void ?{}(unique_ptr(T) & this, zero_t);
    6969        void ?{}(unique_ptr(T) & this, unique_ptr(T) that) = void;
    70         forall( | sized(T), ttype Args | { void ?{}(T &, Args); })
     70        forall( | sized(T), Args... | { void ?{}(T &, Args); })
    7171        void ?{}(unique_ptr(T) & this, Args args);
    7272
  • libcfa/src/parseargs.cfa

    rb6a8b31 rd95969a  
    3030
    3131static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * usage, FILE * out)  __attribute__ ((noreturn));
    32 
     32//-----------------------------------------------------------------------------
     33// checking
     34static void check_args(cfa_option options[], size_t opt_count) {
     35        for(i; opt_count) {
     36                for(j; opt_count) {
     37                        if(i == j) continue;
     38
     39                        if( options[i].short_name != '\0'
     40                        && options[i].short_name == options[j].short_name)
     41                                abort("Parse Args error: two options have short name '%c' (%zu & %zu)", options[i].short_name, i, j);
     42
     43                        if(0 == strcmp(options[i].long_name, options[j].long_name)) abort("Parse Args error: two options have long name '%s' (%zu & %zu)", options[i].long_name, i, j);
     44                }
     45        }
     46}
     47
     48
     49//-----------------------------------------------------------------------------
     50// Parsing args
    3351void parse_args( cfa_option options[], size_t opt_count, const char * usage, char ** & left ) {
    3452        if( 0p != &cfa_args_argc ) {
     
    4159}
    4260
    43 //-----------------------------------------------------------------------------
    44 // getopt_long wrapping
    4561void parse_args(
    4662        int argc,
     
    5167        char ** & left
    5268) {
     69        check_args(options, opt_count);
     70
     71        int maxv = 'h';
     72        char optstring[opt_count * 3] = { '\0' };
     73        {
     74                int idx = 0;
     75                for(i; opt_count) {
     76                        if (options[i].short_name) {
     77                                maxv = max(options[i].short_name, maxv);
     78                                optstring[idx] = options[i].short_name;
     79                                idx++;
     80                                if(    ((intptr_t)options[i].parse) != ((intptr_t)parse_settrue)
     81                                && ((intptr_t)options[i].parse) != ((intptr_t)parse_setfalse) ) {
     82                                        optstring[idx] = ':';
     83                                        idx++;
     84                                }
     85                        }
     86                }
     87                optstring[idx+0] = 'h';
     88                optstring[idx+1] = '\0';
     89        }
     90
    5391        struct option optarr[opt_count + 2];
    5492        {
     
    5694                for(i; opt_count) {
    5795                        if(options[i].long_name) {
     96                                options[i].val = (options[i].short_name != '\0') ? ((int)options[i].short_name) : ++maxv;
    5897                                optarr[idx].name = options[i].long_name;
    5998                                optarr[idx].flag = 0p;
    60                                 optarr[idx].val  = options[i].short_name;
     99                                optarr[idx].val  = options[i].val;
    61100                                if(    ((intptr_t)options[i].parse) == ((intptr_t)parse_settrue)
    62101                                    || ((intptr_t)options[i].parse) == ((intptr_t)parse_setfalse) ) {
     
    70109                optarr[idx+0].[name, has_arg, flag, val] = ["help", no_argument, 0, 'h'];
    71110                optarr[idx+1].[name, has_arg, flag, val] = [0, no_argument, 0, 0];
    72         }
    73 
    74         char optstring[opt_count * 3] = { '\0' };
    75         {
    76                 int idx = 0;
    77                 for(i; opt_count) {
    78                         optstring[idx] = options[i].short_name;
    79                         idx++;
    80                         if(    ((intptr_t)options[i].parse) != ((intptr_t)parse_settrue)
    81                             && ((intptr_t)options[i].parse) != ((intptr_t)parse_setfalse) ) {
    82                                 optstring[idx] = ':';
    83                                 idx++;
    84                         }
    85                 }
    86                 optstring[idx+0] = 'h';
    87                 optstring[idx+1] = '\0';
    88111        }
    89112
     
    103126                        default:
    104127                                for(i; opt_count) {
    105                                         if(opt == options[i].short_name) {
     128                                        if(opt == options[i].val) {
    106129                                                const char * arg = optarg ? optarg : "";
    107130                                                if( arg[0] == '=' ) { arg++; }
     
    125148        if(hwidth <= 0) hwidth = max;
    126149
    127         fprintf(out, "  -%c, --%-*s   %.*s\n", sn, width, ln, hwidth, help);
     150        char sname[4] = { ' ', ' ', ' ', '\0' };
     151        if(sn != '\0') {
     152                sname[0] = '-';
     153                sname[1] = sn;
     154                sname[2] = ',';
     155        }
     156
     157        fprintf(out, "  %s --%-*s   %.*s\n", sname, width, ln, hwidth, help);
    128158        for() {
    129159                help += min(strlen(help), hwidth);
  • libcfa/src/parseargs.hfa

    rb6a8b31 rd95969a  
    22
    33struct cfa_option {
     4      int val; // reserved
    45      char short_name;
    56      const char * long_name;
     
    1314static inline void ?{}( cfa_option & this ) {}
    1415
    15 forall(dtype T | { bool parse(const char *, T & ); })
     16forall(T & | { bool parse(const char *, T & ); })
    1617static inline void ?{}( cfa_option & this, char short_name, const char * long_name, const char * help, T & variable ) {
     18      this.val        = 0;
    1719      this.short_name = short_name;
    1820      this.long_name  = long_name;
     
    2224}
    2325
    24 forall(dtype T)
     26forall(T &)
    2527static inline void ?{}( cfa_option & this, char short_name, const char * long_name, const char * help, T & variable, bool (*parse)(const char *, T & )) {
     28      this.val        = 0;
    2629      this.short_name = short_name;
    2730      this.long_name  = long_name;
  • libcfa/src/rational.cfa

    rb6a8b31 rd95969a  
    1818#include "stdlib.hfa"
    1919
    20 forall( otype RationalImpl | arithmetic( RationalImpl ) ) {
     20forall( RationalImpl | arithmetic( RationalImpl ) ) {
    2121        // helper routines
    2222
     
    159159        // I/O
    160160
    161         forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } )
     161        forall( istype & | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } )
    162162        istype & ?|?( istype & is, Rational(RationalImpl) & r ) {
    163163                is | r.numerator | r.denominator;
     
    168168        } // ?|?
    169169
    170         forall( dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, RationalImpl ); } ) {
     170        forall( ostype & | ostream( ostype ) | { ostype & ?|?( ostype &, RationalImpl ); } ) {
    171171                ostype & ?|?( ostype & os, Rational(RationalImpl) r ) {
    172172                        return os | r.numerator | '/' | r.denominator;
     
    179179} // distribution
    180180
    181 forall( otype RationalImpl | arithmetic( RationalImpl ) | { RationalImpl ?\?( RationalImpl, unsigned long ); } )
     181forall( RationalImpl | arithmetic( RationalImpl ) | { RationalImpl ?\?( RationalImpl, unsigned long ); } )
    182182Rational(RationalImpl) ?\?( Rational(RationalImpl) x, long int y ) {
    183183        if ( y < 0 ) {
     
    190190// conversion
    191191
    192 forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); } )
     192forall( RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); } )
    193193double widen( Rational(RationalImpl) r ) {
    194194        return convert( r.numerator ) / convert( r.denominator );
    195195} // widen
    196196
    197 forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); RationalImpl convert( double ); } )
     197forall( RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); RationalImpl convert( double ); } )
    198198Rational(RationalImpl) narrow( double f, RationalImpl md ) {
    199199        // http://www.ics.uci.edu/~eppstein/numth/frap.c
  • libcfa/src/rational.hfa

    rb6a8b31 rd95969a  
    2020#include "iostream.hfa"
    2121
    22 trait scalar( otype T ) {
     22trait scalar( T ) {
    2323};
    2424
    25 trait arithmetic( otype T | scalar( T ) ) {
     25trait arithmetic( T | scalar( T ) ) {
    2626        int !?( T );
    2727        int ?==?( T, T );
     
    4646// implementation
    4747
    48 forall( otype RationalImpl | arithmetic( RationalImpl ) ) {
     48forall( RationalImpl | arithmetic( RationalImpl ) ) {
    4949        struct Rational {
    5050                RationalImpl numerator, denominator;                    // invariant: denominator > 0
     
    8989
    9090        // I/O
    91         forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } )
     91        forall( istype & | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } )
    9292        istype & ?|?( istype &, Rational(RationalImpl) & );
    9393
    94         forall( dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, RationalImpl ); } ) {
     94        forall( ostype & | ostream( ostype ) | { ostype & ?|?( ostype &, RationalImpl ); } ) {
    9595                ostype & ?|?( ostype &, Rational(RationalImpl) );
    9696                void ?|?( ostype &, Rational(RationalImpl) );
     
    9898} // distribution
    9999
    100 forall( otype RationalImpl | arithmetic( RationalImpl ) |{RationalImpl ?\?( RationalImpl, unsigned long );} )
     100forall( RationalImpl | arithmetic( RationalImpl ) |{RationalImpl ?\?( RationalImpl, unsigned long );} )
    101101Rational(RationalImpl) ?\?( Rational(RationalImpl) x, long int y );
    102102
    103103// conversion
    104 forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); } )
     104forall( RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); } )
    105105double widen( Rational(RationalImpl) r );
    106 forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl );  RationalImpl convert( double );} )
     106forall( RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl );  RationalImpl convert( double );} )
    107107Rational(RationalImpl) narrow( double f, RationalImpl md );
    108108
  • libcfa/src/stdlib.cfa

    rb6a8b31 rd95969a  
    2828// Cforall allocation/deallocation and constructor/destructor, array types
    2929
    30 forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } )
     30forall( T & | sized(T), TT... | { void ?{}( T &, TT ); } )
    3131T * anew( size_t dim, TT p ) {
    3232        T * arr = alloc( dim );
     
    3737} // anew
    3838
    39 forall( dtype T | sized(T) | { void ^?{}( T & ); } )
     39forall( T & | sized(T) | { void ^?{}( T & ); } )
    4040void adelete( T arr[] ) {
    4141        if ( arr ) {                                                                            // ignore null
     
    4848} // adelete
    4949
    50 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype TT | { void adelete( TT ); } )
     50forall( T & | sized(T) | { void ^?{}( T & ); }, TT... | { void adelete( TT ); } )
    5151void adelete( T arr[], TT rest ) {
    5252        if ( arr ) {                                                                            // ignore null
     
    9797//---------------------------------------
    9898
    99 forall( otype E | { int ?<?( E, E ); } ) {
     99forall( E | { int ?<?( E, E ); } ) {
    100100        E * bsearch( E key, const E * vals, size_t dim ) {
    101101                int cmp( const void * t1, const void * t2 ) {
     
    156156
    157157
    158 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) {
     158forall( K, E | { int ?<?( K, K ); K getKey( const E & ); } ) {
    159159        E * bsearch( K key, const E * vals, size_t dim ) {
    160160                int cmp( const void * t1, const void * t2 ) {
  • libcfa/src/stdlib.hfa

    rb6a8b31 rd95969a  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Dec 12 13:52:34 2020
    13 // Update Count     : 536
     12// Last Modified On : Thu Jan 21 22:02:13 2021
     13// Update Count     : 574
    1414//
    1515
     
    4848        else return (T *)alignment( _Alignof(T), dim, sizeof(T) )
    4949
    50 static inline forall( dtype T | sized(T) ) {
     50static inline forall( T & | sized(T) ) {
    5151        // CFA safe equivalents, i.e., implicit size specification
    5252
     
    108108
    109109        1. Replace the current forall-block that contains defintions of S_fill and S_realloc with following:
    110                 forall( dtype T | sized(T) ) {
     110                forall( T & | sized(T) ) {
    111111                        union  U_fill           { char c; T * a; T t; };
    112112                        struct S_fill           { char tag; U_fill(T) fill; };
     
    151151typedef struct S_resize                 { inline void *;  }     T_resize;
    152152
    153 forall( dtype T ) {
     153forall( T & ) {
    154154        struct S_fill           { char tag; char c; size_t size; T * at; char t[50]; };
    155155        struct S_realloc        { inline T *; };
     
    159159static inline T_resize  ?`resize  ( void * a )  { return (T_resize){a}; }
    160160
    161 static inline forall( dtype T | sized(T) ) {
     161static inline forall( T & | sized(T) ) {
    162162        S_fill(T) ?`fill ( T t ) {
    163163                S_fill(T) ret = { 't' };
    164164                size_t size = sizeof(T);
    165                 if(size > sizeof(ret.t)) { printf("ERROR: const object of size greater than 50 bytes given for dynamic memory fill\n"); exit(1); }
     165                if ( size > sizeof(ret.t) ) {
     166                        abort( "ERROR: const object of size greater than 50 bytes given for dynamic memory fill\n" );
     167                } // if
    166168                memcpy( &ret.t, &t, size );
    167169                return ret;
     
    173175        S_realloc(T)    ?`realloc ( T * a )                             { return (S_realloc(T)){a}; }
    174176
    175         T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) {
     177        T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {
    176178                T * ptr = NULL;
    177179                size_t size = sizeof(T);
     
    181183                        ptr = (T*) (void *) resize( (void *)Resize, Align, Dim * size );
    182184                } else if ( Realloc ) {
    183                         if (Fill.tag != '0') copy_end = min(malloc_size( Realloc ), Dim * size);
    184                         ptr = (T*) (void *) realloc( (void *)Realloc, Align, Dim * size );
     185                        if ( Fill.tag != '0' ) copy_end = min(malloc_size( Realloc ), Dim * size );
     186                        ptr = (T *) (void *) realloc( (void *)Realloc, Align, Dim * size );
    185187                } else {
    186                         ptr = (T*) (void *) memalign( Align, Dim * size );
    187                 }
    188 
    189                 if(Fill.tag == 'c') {
     188                        ptr = (T *) (void *) memalign( Align, Dim * size );
     189                }
     190
     191                if ( Fill.tag == 'c' ) {
    190192                        memset( (char *)ptr + copy_end, (int)Fill.c, Dim * size - copy_end );
    191                 } else if(Fill.tag == 't') {
     193                } else if ( Fill.tag == 't' ) {
    192194                        for ( int i = copy_end; i < Dim * size; i += size ) {
     195                                #pragma GCC diagnostic push
     196                                #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
     197                                assert( size <= sizeof(Fill.t) );
    193198                                memcpy( (char *)ptr + i, &Fill.t, size );
     199                                #pragma GCC diagnostic pop
    194200                        }
    195                 } else if(Fill.tag == 'a') {
     201                } else if ( Fill.tag == 'a' ) {
    196202                        memcpy( (char *)ptr + copy_end, Fill.at, min(Dim * size - copy_end, Fill.size) );
    197                 } else if(Fill.tag == 'T') {
    198                         for ( int i = copy_end; i < Dim * size; i += size ) {
    199                                 memcpy( (char *)ptr + i, Fill.at, size );
    200                         }
     203                } else if ( Fill.tag == 'T' ) {
     204                        memcpy( (char *)ptr + copy_end, Fill.at, Dim * size );
    201205                }
    202206
     
    204208        } // $alloc_internal
    205209
    206         forall( ttype TT | { T * $alloc_internal( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {
     210        forall( TT... | { T * $alloc_internal( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {
    207211
    208212                T * $alloc_internal( void *       , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) {
     
    233237} // distribution T
    234238
    235 static inline forall( dtype T | sized(T) ) {
     239static inline forall( T & | sized(T) ) {
    236240        // CFA safe initialization/copy, i.e., implicit size specification, non-array types
    237241        T * memset( T * dest, char fill ) {
     
    254258
    255259// CFA deallocation for multiple objects
    256 static inline forall( dtype T )                                                 // FIX ME, problems with 0p in list
     260static inline forall( T & )                                                     // FIX ME, problems with 0p in list
    257261void free( T * ptr ) {
    258262        free( (void *)ptr );                                                            // C free
    259263} // free
    260 static inline forall( dtype T, ttype TT | { void free( TT ); } )
     264static inline forall( T &, TT... | { void free( TT ); } )
    261265void free( T * ptr, TT rest ) {
    262266        free( ptr );
     
    265269
    266270// CFA allocation/deallocation and constructor/destructor, non-array types
    267 static inline forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } )
     271static inline forall( T & | sized(T), TT... | { void ?{}( T &, TT ); } )
    268272T * new( TT p ) {
    269         return &(*(T *)malloc()){ p };                                                  // run constructor
     273        return &(*(T *)malloc()){ p };                                          // run constructor
    270274} // new
    271275
    272 static inline forall( dtype T | { void ^?{}( T & ); } )
     276static inline forall( T & | { void ^?{}( T & ); } )
    273277void delete( T * ptr ) {
    274278        // special case for 0-sized object => always call destructor
     
    278282        free( ptr );                                                                            // always call free
    279283} // delete
    280 static inline forall( dtype T, ttype TT | { void ^?{}( T & ); void delete( TT ); } )
     284static inline forall( T &, TT... | { void ^?{}( T & ); void delete( TT ); } )
    281285void delete( T * ptr, TT rest ) {
    282286        delete( ptr );
     
    285289
    286290// CFA allocation/deallocation and constructor/destructor, array types
    287 forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } ) T * anew( size_t dim, TT p );
    288 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] );
    289 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype TT | { void adelete( TT ); } ) void adelete( T arr[], TT rest );
     291forall( T & | sized(T), TT... | { void ?{}( T &, TT ); } ) T * anew( size_t dim, TT p );
     292forall( T & | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] );
     293forall( T & | sized(T) | { void ^?{}( T & ); }, TT... | { void adelete( TT ); } ) void adelete( T arr[], TT rest );
    290294
    291295//---------------------------------------
     
    327331//---------------------------------------
    328332
    329 forall( otype E | { int ?<?( E, E ); } ) {
     333forall( E | { int ?<?( E, E ); } ) {
    330334        E * bsearch( E key, const E * vals, size_t dim );
    331335        size_t bsearch( E key, const E * vals, size_t dim );
     
    336340} // distribution
    337341
    338 forall( otype K, otype E | { int ?<?( K, K ); K getKey( const E & ); } ) {
     342forall( K, E | { int ?<?( K, K ); K getKey( const E & ); } ) {
    339343        E * bsearch( K key, const E * vals, size_t dim );
    340344        size_t bsearch( K key, const E * vals, size_t dim );
     
    345349} // distribution
    346350
    347 forall( otype E | { int ?<?( E, E ); } ) {
     351forall( E | { int ?<?( E, E ); } ) {
    348352        void qsort( E * vals, size_t dim );
    349353} // distribution
  • libcfa/src/time.cfa

    rb6a8b31 rd95969a  
    3131
    3232
    33 forall( dtype ostype | ostream( ostype ) ) {
     33forall( ostype & | ostream( ostype ) ) {
    3434        ostype & ?|?( ostype & os, Duration dur ) with( dur ) {
    3535                (ostype &)(os | tn / TIMEGRAN);                                 // print seconds
     
    136136} // strftime
    137137
    138 forall( dtype ostype | ostream( ostype ) ) {
     138forall( ostype & | ostream( ostype ) ) {
    139139        ostype & ?|?( ostype & os, Time time ) with( time ) {
    140140                char buf[32];                                                                   // at least 26
  • libcfa/src/vec/vec.hfa

    rb6a8b31 rd95969a  
    1818#include <math.hfa>
    1919
    20 trait fromint(otype T) {
     20trait fromint(T) {
    2121    void ?{}(T&, int);
    2222};
    23 trait zeroinit(otype T) {
     23trait zeroinit(T) {
    2424    void ?{}(T&, zero_t);
    2525};
    26 trait zero_assign(otype T) {
     26trait zero_assign(T) {
    2727    T ?=?(T&, zero_t);
    2828};
    29 trait subtract(otype T) {
     29trait subtract(T) {
    3030    T ?-?(T, T);
    3131};
    32 trait negate(otype T) {
     32trait negate(T) {
    3333    T -?(T);
    3434};
    35 trait add(otype T) {
     35trait add(T) {
    3636    T ?+?(T, T);
    3737};
    38 trait multiply(otype T) {
     38trait multiply(T) {
    3939    T ?*?(T, T);
    4040};
    41 trait divide(otype T) {
     41trait divide(T) {
    4242    T ?/?(T, T);
    4343};
    44 trait lessthan(otype T) {
     44trait lessthan(T) {
    4545    int ?<?(T, T);
    4646};
    47 trait equality(otype T) {
     47trait equality(T) {
    4848    int ?==?(T, T);
    4949};
    50 trait sqrt(otype T) {
     50trait sqrt(T) {
    5151    T sqrt(T);
    5252};
     
    6868}
    6969
    70 trait dottable(otype V, otype T) {
     70trait dottable(V, T) {
    7171    T dot(V, V);
    7272};
     
    7474static inline {
    7575
    76 forall(otype T | sqrt(T), otype V | dottable(V, T))
     76forall(T | sqrt(T), V | dottable(V, T))
    7777T length(V v) {
    7878   return sqrt(dot(v, v));
    7979}
    8080
    81 forall(otype T, otype V | dottable(V, T))
     81forall(T, V | dottable(V, T))
    8282T length_squared(V v) {
    8383   return dot(v, v);
    8484}
    8585
    86 forall(otype T, otype V | { T length(V); } | subtract(V))
     86forall(T, V | { T length(V); } | subtract(V))
    8787T distance(V v1, V v2) {
    8888    return length(v1 - v2);
    8989}
    9090
    91 forall(otype T, otype V | { T length(V); V ?/?(V, T); })
     91forall(T, V | { T length(V); V ?/?(V, T); })
    9292V normalize(V v) {
    9393    return v / length(v);
     
    9595
    9696// Project vector u onto vector v
    97 forall(otype T, otype V | dottable(V, T) | { V normalize(V); V ?*?(V, T); })
     97forall(T, V | dottable(V, T) | { V normalize(V); V ?*?(V, T); })
    9898V project(V u, V v) {
    9999    V v_norm = normalize(v);
     
    102102
    103103// Reflect incident vector v with respect to surface with normal n
    104 forall(otype T | fromint(T), otype V | { V project(V, V); V ?*?(T, V); V ?-?(V,V); })
     104forall(T | fromint(T), V | { V project(V, V); V ?*?(T, V); V ?-?(V,V); })
    105105V reflect(V v, V n) {
    106106    return v - (T){2} * project(v, n);
     
    111111// entering material (i.e., from air to water, eta = 1/1.33)
    112112// v and n must already be normalized
    113 forall(otype T | fromint(T) | subtract(T) | multiply(T) | add(T) | lessthan(T) | sqrt(T),
    114        otype V | dottable(V, T) | { V ?*?(T, V); V ?-?(V,V); void ?{}(V&, zero_t); })
     113forall(T | fromint(T) | subtract(T) | multiply(T) | add(T) | lessthan(T) | sqrt(T),
     114       V | dottable(V, T) | { V ?*?(T, V); V ?-?(V,V); void ?{}(V&, zero_t); })
    115115V refract(V v, V n, T eta) {
    116116    T dotValue = dot(n, v);
     
    128128// i is the incident vector
    129129// ng is the geometric normal of the surface
    130 forall(otype T | lessthan(T) | zeroinit(T), otype V | dottable(V, T) | negate(V))
     130forall(T | lessthan(T) | zeroinit(T), V | dottable(V, T) | negate(V))
    131131V faceforward(V n, V i, V ng) {
    132132    return dot(ng, i) < (T){0} ? n : -n;
  • libcfa/src/vec/vec2.hfa

    rb6a8b31 rd95969a  
    1919#include "vec.hfa"
    2020
    21 forall (otype T) {
     21forall (T) {
    2222    struct vec2 {
    2323        T x, y;
     
    2525}
    2626
    27 forall (otype T) {
     27forall (T) {
    2828    static inline {
    2929
     
    279279}
    280280
    281 forall(dtype ostype, otype T | writeable(T, ostype)) {
     281forall(ostype &, T | writeable(T, ostype)) {
    282282    ostype & ?|?(ostype & os, vec2(T) v) with (v) {
    283283        return os | '<' | x | ',' | y | '>';
  • libcfa/src/vec/vec3.hfa

    rb6a8b31 rd95969a  
    1919#include "vec.hfa"
    2020
    21 forall (otype T) {
     21forall (T) {
    2222    struct vec3 {
    2323        T x, y, z;
     
    2525}
    2626
    27 forall (otype T) {
     27forall (T) {
    2828    static inline {
    2929
     
    288288}
    289289
    290 forall(dtype ostype, otype T | writeable(T, ostype)) {
     290forall(ostype &, T | writeable(T, ostype)) {
    291291    ostype & ?|?(ostype & os, vec3(T) v) with (v) {
    292292        return os | '<' | x | ',' | y | ',' | z | '>';
  • libcfa/src/vec/vec4.hfa

    rb6a8b31 rd95969a  
    1919#include "vec.hfa"
    2020
    21 forall (otype T) {
     21forall (T) {
    2222    struct vec4 {
    2323        T x, y, z, w;
     
    2525}
    2626
    27 forall (otype T) {
     27forall (T) {
    2828    static inline {
    2929
     
    283283}
    284284
    285 forall(dtype ostype, otype T | writeable(T, ostype)) {
     285forall(ostype &, T | writeable(T, ostype)) {
    286286    ostype & ?|?(ostype & os, vec4(T) v) with (v) {
    287287        return os | '<' | x | ',' | y | ',' | z | ',' | w | '>';
  • src/Parser/parser.yy

    rb6a8b31 rd95969a  
    24412441type_parameter:                                                                                 // CFA
    24422442        type_class identifier_or_type_name
    2443                 { typedefTable.addToScope( *$2, TYPEDEFname, "9" ); }
     2443                {   typedefTable.addToScope( *$2, TYPEDEFname, "9" );
     2444                        if ( $1 == TypeDecl::Otype ) { SemanticError( yylloc, "otype keyword is deprecated" ); }
     2445                        if ( $1 == TypeDecl::Dtype ) { SemanticError( yylloc, "dtype keyword is deprecated" ); }
     2446                        if ( $1 == TypeDecl::Ttype ) { SemanticError( yylloc, "ttype keyword is deprecated" ); }
     2447                }
    24442448          type_initializer_opt assertion_list_opt
    24452449                { $$ = DeclarationNode::newTypeParam( $1, $2 )->addTypeInitializer( $4 )->addAssertions( $5 ); }
  • src/ResolvExpr/PolyCost.cc

    rb6a8b31 rd95969a  
    3535                PassVisitor<PolyCost> coster( env, indexer );
    3636                type->accept( coster );
    37                 return coster.pass.result;
     37                return (coster.pass.result > 0) ? 1 : 0;
    3838        }
    3939
     
    8787        ast::Pass<PolyCost_new> costing( symtab, env );
    8888        type->accept( costing );
    89         return costing.core.result;
     89        return (costing.core.result > 0) ? 1 : 0;
    9090}
    9191
  • src/ResolvExpr/SpecCost.cc

    rb6a8b31 rd95969a  
    4343                // mark specialization of base type
    4444                void postvisit(ReferenceType*) { if ( count >= 0 ) ++count; }
     45
     46                void postvisit(StructInstType*) { if ( count >= 0 ) ++count; }
     47                void postvisit(UnionInstType*) { if ( count >= 0 ) ++count; }
    4548
    4649        private:
     
    8285                void previsit(StructInstType* sty) {
    8386                        count = minover( sty->parameters );
    84                         visit_children = false;
    8587                }
    8688
     
    8890                void previsit(UnionInstType* uty) {
    8991                        count = minover( uty->parameters );
    90                         visit_children = false;
    9192                }
    9293
     
    174175                void postvisit( const ast::ArrayType * ) { if ( count >= 0 ) ++count; }
    175176                void postvisit( const ast::ReferenceType * ) { if ( count >= 0 ) ++count; }
     177
     178                void postvisit( const ast::StructInstType * ) { if ( count >= 0 ) ++count; }
     179                void postvisit( const ast::UnionInstType * ) { if ( count >= 0 ) ++count; }
    176180
    177181                // Use the minimal specialization value over returns and params.
     
    189193                void previsit( const ast::StructInstType * sty ) {
    190194                        count = minimumPresent( sty->params, expr_result );
    191                         visit_children = false;
    192195                }
    193196
     
    195198                void previsit( const ast::UnionInstType * uty ) {
    196199                        count = minimumPresent( uty->params, expr_result );
    197                         visit_children = false;
    198200                }
    199201
  • tests/alloc2.cfa

    rb6a8b31 rd95969a  
    1616        bool passed = (malloc_size(ip) == size) && (malloc_usable_size(ip) >= size) && (malloc_alignment(ip) == align) && ((uintptr_t)ip % align  == 0);
    1717        if (!passed) {
    18                 printf("failed test %3d: %4lu %4lu but got %4lu ( %3lu ) %4lu\n", tests_total, size, align, malloc_size(ip), malloc_usable_size(ip), malloc_alignment(ip));
     18                printf("failed test %3d: %4zu %4zu but got %4zu ( %3zu ) %4zu\n", tests_total, size, align, malloc_size(ip), malloc_usable_size(ip), malloc_alignment(ip));
    1919                tests_failed += 1;
    2020        }
  • tests/avltree/avl-private.cfa

    rb6a8b31 rd95969a  
    1111// an AVL tree's height is easy to compute
    1212// just follow path with the larger balance
    13 forall(otype K | Comparable(K), otype V)
     13forall(K | Comparable(K), V)
    1414int height(tree(K, V) * t){
    1515  int helper(tree(K, V) * t, int ht){
     
    2727}
    2828
    29 forall(otype K | Comparable(K), otype V)
     29forall(K | Comparable(K), V)
    3030int calcBalance(tree(K, V) * t){
    3131  int l = height(t->left);
     
    3636
    3737// re-establish the link between parent and child
    38 forall(otype K | Comparable(K), otype V)
     38forall(K | Comparable(K), V)
    3939void relinkToParent(tree(K, V) * t){
    4040  tree(K, V) * parent = t->parent; // FIX ME!!
     
    4949
    5050// rotate left from t
    51 forall(otype K | Comparable(K), otype V)
     51forall(K | Comparable(K), V)
    5252tree(K, V) * rotateLeft(tree(K, V) * t){
    5353  tree(K, V) * newRoot = t->right;
     
    6868
    6969// rotate right from t
    70 forall(otype K | Comparable(K), otype V)
     70forall(K | Comparable(K), V)
    7171tree(K, V) * rotateRight(tree(K, V) * t){
    7272  tree(K, V) * newRoot = t->left;
     
    8787
    8888// balances a node that has balance factor -2 or 2
    89 forall(otype K | Comparable(K), otype V)
     89forall(K | Comparable(K), V)
    9090tree(K, V) * fix(tree(K, V) * t){
    9191  // ensure that t's balance factor is one of
     
    113113
    114114// attempt to fix the tree, if necessary
    115 forall(otype K | Comparable(K), otype V)
     115forall(K | Comparable(K), V)
    116116tree(K, V) * tryFix(tree(K, V) * t){
    117117  int b = calcBalance(t);
     
    126126
    127127// sets parent field of c to be p
    128 forall(otype K | Comparable(K), otype V)
     128forall(K | Comparable(K), V)
    129129void setParent(tree(K, V) * c, tree(K, V) * p){
    130130  if (! empty(c)){
  • tests/avltree/avl-private.h

    rb6a8b31 rd95969a  
    55
    66// attempt to fix the tree, if necessary
    7 forall(otype K | Comparable(K), otype V)
     7forall(K | Comparable(K), V)
    88tree(K, V) * tryFix(tree(K, V) * t);
    99
    1010// sets parent field of c to be p
    11 forall(otype K | Comparable(K), otype V)
     11forall(K | Comparable(K), V)
    1212void setParent(tree(K, V) * c, tree(K, V) * p);
    1313
    14 forall(otype K | Comparable(K), otype V)
     14forall(K | Comparable(K), V)
    1515int height(tree(K, V) * t);
  • tests/avltree/avl.h

    rb6a8b31 rd95969a  
    99// #include <lib.h>
    1010
    11 trait Comparable(otype T) {
     11trait Comparable(T) {
    1212  int ?<?(T, T);
    1313};
    1414
    15 forall(otype T | Comparable(T))
     15forall(T | Comparable(T))
    1616int ?==?(T t1, T t2);
    1717
    18 forall(otype T | Comparable(T))
     18forall(T | Comparable(T))
    1919int ?>?(T t1, T t2);
    2020
     
    4141
    4242// temporary: need forward decl to get around typedef problem
    43 forall(otype K | Comparable(K), otype V)
     43forall(K | Comparable(K), V)
    4444struct tree;
    4545
    46 forall(otype K | Comparable(K), otype V)
     46forall(K | Comparable(K), V)
    4747struct tree {
    4848  K key;
     
    5454};
    5555
    56 forall(otype K | Comparable(K), otype V)
     56forall(K | Comparable(K), V)
    5757void ?{}(tree(K, V) &t, K key, V value);
    5858
    59 forall(otype K, otype V)
     59forall(K | Comparable(K), V)
    6060void ^?{}(tree(K, V) & t);
    6161
    62 forall(otype K | Comparable(K), otype V)
     62forall(K | Comparable(K), V)
    6363tree(K, V) * create(K key, V value);
    6464
    65 forall(otype K | Comparable(K), otype V)
     65forall(K | Comparable(K), V)
    6666V * find(tree(K, V) * t, K key);
    6767
    68 forall(otype K | Comparable(K), otype V)
     68forall(K | Comparable(K), V)
    6969int empty(tree(K, V) * t);
    7070
    7171// returns the root of the tree
    72 forall(otype K | Comparable(K), otype V)
     72forall(K | Comparable(K), V)
    7373int insert(tree(K, V) ** t, K key, V value);
    7474
    75 forall(otype K | Comparable(K), otype V)
     75forall(K | Comparable(K), V)
    7676int remove(tree(K, V) ** t, K key);
    7777
    78 forall(otype K | Comparable(K), otype V)
     78forall(K | Comparable(K), V)
    7979void copy(tree(K, V) * src, tree(K, V) ** ret);
    8080
    81 forall(otype K | Comparable(K), otype V)
     81forall(K | Comparable(K), V)
    8282void for_each(tree(K, V) * t, void (*func)(V));
    8383
  • tests/avltree/avl0.cfa

    rb6a8b31 rd95969a  
    11#include "avl.h"
    22
    3 forall(otype T | Comparable(T))
     3forall(T | Comparable(T))
    44int ?==?(T t1, T t2) {
    55  return !(t1 < t2) && !(t2 < t1);
    66}
    77
    8 forall(otype T | Comparable(T))
     8forall(T | Comparable(T))
    99int ?>?(T t1, T t2) {
    1010  return t2 < t1;
  • tests/avltree/avl1.cfa

    rb6a8b31 rd95969a  
    33#include <stdlib.hfa>
    44
    5 forall(otype K | Comparable(K), otype V)
     5forall(K | Comparable(K), V)
    66void ?{}(tree(K, V) &t, K key, V value){
    77  (t.key) { key };
     
    1313}
    1414
    15 forall(otype K, otype V)
     15forall(K| Comparable(K), V)
    1616void ^?{}(tree(K, V) & t){
    1717  delete(t.left);
     
    2121}
    2222
    23 forall(otype K | Comparable(K), otype V)
     23forall(K | Comparable(K), V)
    2424tree(K, V) * create(K key, V value) {
    2525  // infinite loop trying to resolve ... t = malloc();
  • tests/avltree/avl2.cfa

    rb6a8b31 rd95969a  
    22#include "avl-private.h"
    33
    4 forall(otype K | Comparable(K), otype V)
     4forall(K | Comparable(K), V)
    55V * find(tree(K, V) * t, K key){
    66  if (empty(t)){
     
    1818}
    1919
    20 forall(otype K | Comparable(K), otype V)
     20forall(K | Comparable(K), V)
    2121int empty(tree(K, V) * t){
    2222  return t == NULL;
     
    2424
    2525// returns the root of the tree
    26 forall(otype K | Comparable(K), otype V)
     26forall(K | Comparable(K), V)
    2727int insert(tree(K, V) ** t, K key, V value) {
    2828  // handles a non-empty tree
  • tests/avltree/avl3.cfa

    rb6a8b31 rd95969a  
    44
    55// swaps the data within two tree nodes
    6 forall(otype K | Comparable(K), otype V)
     6forall(K | Comparable(K), V)
    77void node_swap(tree(K, V) * t, tree(K, V) * t2){
    88        swap( t->key,  t2->key);
     
    1111
    1212// go left as deep as possible from within the right subtree
    13 forall(otype K | Comparable(K), otype V)
     13forall(K | Comparable(K), V)
    1414tree(K, V) * find_successor(tree(K, V) * t){
    1515        tree(K, V) * find_successor_helper(tree(K, V) * t){
     
    2525
    2626// cleanup - don't want to deep delete, so set children to NULL first.
    27 forall(otype K | Comparable(K), otype V)
     27forall(K | Comparable(K), V)
    2828void deleteSingleNode(tree(K, V) * t) {
    2929        t->left = NULL;
     
    3333
    3434// does the actual remove operation once we've found the node in question
    35 forall(otype K | Comparable(K), otype V)
     35forall(K | Comparable(K), V)
    3636tree(K, V) * remove_node(tree(K, V) * t){
    3737        // is the node a leaf?
     
    8585
    8686// finds the node that needs to be removed
    87 forall(otype K | Comparable(K), otype V)
     87forall(K | Comparable(K), V)
    8888tree(K, V) * remove_helper(tree(K, V) * t, K key, int * worked){
    8989        if (empty(t)){
     
    106106}
    107107
    108 forall(otype K | Comparable(K), otype V)
     108forall(K | Comparable(K), V)
    109109int remove(tree(K, V) ** t, K key){
    110110        int worked = 0;
  • tests/avltree/avl4.cfa

    rb6a8b31 rd95969a  
    44// Perform a shallow copy of src, return the
    55// new tree in ret
    6 forall(otype K | Comparable(K), otype V)
     6forall(K | Comparable(K), V)
    77int copy(tree(K, V) * src, tree(K, V) ** ret){
    88  tree(K, V) * helper(tree(K, V) * t, int * worked){
     
    3535
    3636// Apply func to every value element in t, using an in order traversal
    37 forall(otype K | Comparable(K), otype V)
     37forall(K | Comparable(K), V)
    3838void for_each(tree(K, V) * t, int (*func)(V)) {
    3939  if (t == NULL) {
  • tests/bugs/10.cfa

    rb6a8b31 rd95969a  
    22// https://cforall.uwaterloo.ca/trac/ticket/10
    33
    4 forall(otype T)
     4forall(T)
    55struct result {
    66      union {
  • tests/bugs/104.cfa

    rb6a8b31 rd95969a  
    44[ float, float ] modf_( float x );
    55
    6 forall(otype T | { [T, T] modf_(T); })
     6forall(T | { [T, T] modf_(T); })
    77void modf(T);
    88
  • tests/bugs/194.cfa

    rb6a8b31 rd95969a  
    22// https://cforall.uwaterloo.ca/trac/ticket/194
    33
    4 forall( dtype T | sized(T) ) T * foo( void ) {
     4forall( T & | sized(T) ) T * foo( void ) {
    55      printf( "foo1\n" );
    66        return (T *)0;
    77}
    8 forall( dtype T | sized(T) ) T & foo( void ) {
     8forall( T & | sized(T) ) T & foo( void ) {
    99        printf( "foo2\n" );
    1010        return (T &)*(T *)0;
  • tests/bugs/196.cfa

    rb6a8b31 rd95969a  
    22// https://cforall.uwaterloo.ca/trac/ticket/196
    33
    4 forall(dtype T)
     4forall(T &)
    55struct link;
    66
    7 forall(dtype T)
     7forall(T &)
    88struct link {
    99        link(T) * next;
     
    1212// -----
    1313
    14 forall(dtype T)
     14forall(T &)
    1515struct foo;
    1616
    17 forall(dtype U)
     17forall(U &)
    1818struct bar {
    1919        foo(U) * data;
    2020};
    2121
    22 forall(dtype T)
     22forall(T &)
    2323struct foo {};
    2424
  • tests/bugs/203-2.cfa

    rb6a8b31 rd95969a  
    11// Trac ticket: https://cforall.uwaterloo.ca/trac/ticket/203
    22
    3 forall(dtype A)
     3forall(A &)
    44struct empty {
    55        // Nothing.
    66};
    77
    8 forall(dtype C)
     8forall(C &)
    99struct wrap_e {
    1010        empty(C) field;
  • tests/bugs/203-7.cfa

    rb6a8b31 rd95969a  
    11// Trac ticket: https://cforall.uwaterloo.ca/trac/ticket/203
    22
    3 forall(dtype A)
     3forall(A &)
    44struct empty {
    55        // Nothing.
    66};
    77
    8 forall(dtype C)
     8forall(C &)
    99struct wrap_e {
    1010        empty(C) field;
  • tests/bugs/203-9.cfa

    rb6a8b31 rd95969a  
    11// Trac ticket: https://cforall.uwaterloo.ca/trac/ticket/203
    22
    3 forall(dtype A)
     3forall(A &)
    44struct empty {
    55        // Nothing.
    66};
    77
    8 forall(dtype C)
     8forall(C &)
    99struct wrap_e {
    1010        empty(C) field;
  • tests/bugs/7.cfa

    rb6a8b31 rd95969a  
    88
    99// (Bug 1 unresolved as of this test.)
    10 forall(otype T)
     10forall(T)
    1111struct stack_node;
    1212
    13 forall(otype T)
     13forall(T)
    1414struct stack_node {
    1515    stack_node(T) * next;
     
    1717};
    1818
    19 forall(otype T)
     19forall(T)
    2020struct stack {
    2121    stack_node(T) * head;
    2222};
    2323
    24 trait stack_errors(otype T) {
     24trait stack_errors(T) {
    2525    T emptyStackHandler (stack(T) * this);
    2626};
    2727
    28 forall(otype T | stack_errors(T))
     28forall(T | stack_errors(T))
    2929T pop (stack(T) * this) {
    3030    return (T){};
  • tests/castError.cfa

    rb6a8b31 rd95969a  
    1414//
    1515
    16 forall(otype T) struct S { T p; };
     16forall(T) struct S { T p; };
    1717int f;
    1818S(int) sint;
  • tests/concurrent/examples/boundedBufferEXT.cfa

    rb6a8b31 rd95969a  
    2424enum { BufferSize = 50 };
    2525
    26 forall( otype T ) {
     26forall( T ) {
    2727        monitor Buffer {
    2828                int front, back, count;
  • tests/concurrent/examples/boundedBufferINT.cfa

    rb6a8b31 rd95969a  
    2424enum { BufferSize = 50 };
    2525
    26 forall( otype T ) {
     26forall( T ) {
    2727        monitor Buffer {
    2828                condition full, empty;
  • tests/concurrent/examples/quickSort.generic.cfa

    rb6a8b31 rd95969a  
    2121#include <string.h>                                                                             // strcmp
    2222
    23 forall( otype T | { int ?<?( T, T ); } ) {
     23forall( T | { int ?<?( T, T ); } ) {
    2424        thread Quicksort {
    2525                T * values;                                                                             // communication variables
  • tests/concurrent/multi-monitor.cfa

    rb6a8b31 rd95969a  
    3838}
    3939
    40 forall(dtype T | sized(T) | { void ^?{}(T & mutex); })
     40forall(T & | sized(T) | { void ^?{}(T & mutex); })
    4141void delete_mutex(T * x) {
    4242        ^(*x){};
  • tests/concurrent/thread.cfa

    rb6a8b31 rd95969a  
    11#include <fstream.hfa>
    22#include <kernel.hfa>
     3#include <locks.hfa>
    34#include <stdlib.hfa>
    45#include <thread.hfa>
  • tests/errors/completeType.cfa

    rb6a8b31 rd95969a  
    11void foo(int *) {}
    22void bar(void *) {}
    3 forall(otype T) void baz(T *);
    4 forall(dtype T) void qux(T *);
    5 forall(dtype T | sized(T)) void quux(T *);
     3forall(T) void baz(T *);
     4forall(T &) void qux(T *);
     5forall(T & | sized(T)) void quux(T *);
    66
    77struct A;       // incomplete
     
    3939
    4040
    41 forall(otype T)
     41forall(T)
    4242void baz(T * x) {
    4343        // okay
     
    4949}
    5050
    51 forall(dtype T)
     51forall(T &)
    5252void qux(T * y) {
    5353        // okay
     
    6161}
    6262
    63 forall(dtype T | sized(T))
     63forall(T & | sized(T))
    6464void quux(T * z) {
    6565        // okay
  • tests/exceptions/defaults.cfa

    rb6a8b31 rd95969a  
    5555
    5656void unhandled_test(void) {
    57         forall(dtype T, dtype V | is_exception(T, V))
     57        forall(T &, V & | is_exception(T, V))
    5858        void defaultTerminationHandler(T &) {
    5959                throw (unhandled_exception){};
  • tests/exceptions/polymorphic.cfa

    rb6a8b31 rd95969a  
    33#include <exception.hfa>
    44
    5 FORALL_TRIVIAL_EXCEPTION(proxy, (otype T), (T));
    6 FORALL_TRIVIAL_INSTANCE(proxy, (otype U), (U))
     5FORALL_TRIVIAL_EXCEPTION(proxy, (T), (T));
     6FORALL_TRIVIAL_INSTANCE(proxy, (U), (U))
    77
    88const char * msg(proxy(int) * this) { return "proxy(int)"; }
     
    3333}
    3434
    35 FORALL_DATA_EXCEPTION(cell, (otype T), (T))(
     35FORALL_DATA_EXCEPTION(cell, (T), (T))(
    3636        T data;
    3737);
    3838
    39 FORALL_DATA_INSTANCE(cell, (otype T), (T))
     39FORALL_DATA_INSTANCE(cell, (T), (T))
    4040
    4141const char * msg(cell(int) * this) { return "cell(int)"; }
  • tests/exceptions/virtual-poly.cfa

    rb6a8b31 rd95969a  
    1616};
    1717
    18 forall(otype T)
     18forall(T)
    1919struct mono_child_vtable {
    2020        mono_base_vtable const * const parent;
    2121};
    2222
    23 forall(otype T)
     23forall(T)
    2424struct mono_child {
    2525        mono_child_vtable(T) const * virtual_table;
     
    3737}
    3838
    39 forall(otype U)
     39forall(U)
    4040struct poly_base_vtable {
    4141        poly_base_vtable(U) const * const parent;
    4242};
    4343
    44 forall(otype U)
     44forall(U)
    4545struct poly_base {
    4646        poly_base_vtable(U) const * virtual_table;
    4747};
    4848
    49 forall(otype V)
     49forall(V)
    5050struct poly_child_vtable {
    5151        poly_base_vtable(V) const * const parent;
    5252};
    5353
    54 forall(otype V)
     54forall(V)
    5555struct poly_child {
    5656        poly_child_vtable(V) const * virtual_table;
  • tests/forall.cfa

    rb6a8b31 rd95969a  
    1515
    1616void g1() {
    17         forall( otype T ) T f( T ) {};
     17        forall( T ) T f( T ) {};
    1818        void f( int ) {};
    1919        void h( void (*p)(void) ) {};
     
    3232
    3333void g2() {
    34         forall( otype T ) void f( T, T ) {}
    35         forall( otype T, otype U ) void f( T, U ) {}
     34        forall( T ) void f( T, T ) {}
     35        forall( T, U ) void f( T, U ) {}
    3636
    3737        int x;
     
    4545}
    4646
    47 typedef forall ( otype T ) int (* f)( int );
    48 
    49 forall( otype T )
     47typedef forall ( T ) int (* f)( int );
     48
     49forall( T )
    5050void swap( T left, T right ) {
    5151        T temp = left;
     
    5454}
    5555
    56 trait sumable( otype T ) {
     56trait sumable( T ) {
    5757        void ?{}( T &, zero_t );                                                        // 0 literal constructor
    5858        T ?+?( T, T );                                                                          // assortment of additions
     
    6262}; // sumable
    6363
    64 forall( otype T | sumable( T ) )                                                // use trait
     64forall( T | sumable( T ) )                                              // use trait
    6565T sum( size_t size, T a[] ) {
    6666        T total = 0;                                                                            // initialize by 0 constructor
     
    7070} // sum
    7171
    72 forall( otype T | { T ?+?( T, T ); T ?++( T & ); [T] ?+=?( T &,T ); } )
     72forall( T | { T ?+?( T, T ); T ?++( T & ); [T] ?+=?( T &,T ); } )
    7373T twice( T t ) {
    7474        return t + t;
    7575}
    7676
    77 forall( otype T | { int ?<?(T, T); } )
     77forall( T | { int ?<?(T, T); } )
    7878T min( T t1, T t2 ) {
    7979        return t1 < t2 ? t1 : t2;
     
    9191
    9292// Multiple forall
    93 forall( otype T ) forall( otype S ) struct { int i; };
    94 forall( otype T ) struct { int i; } forall( otype S );
    95 struct { int i; } forall( otype T ) forall( otype S );
    96 forall( otype W ) struct { int i; } forall( otype T ) forall( otype S );
     93forall( T ) forall( S ) struct { int i; };
     94forall( T ) struct { int i; } forall( S );
     95struct { int i; } forall( T ) forall( S );
     96forall( W ) struct { int i; } forall( T ) forall( S );
    9797
    9898// Distribution
    9999struct P { int i; };
    100 forall( otype T ) struct Q { T i; };
    101 forall( otype T ) struct { int i; };
     100forall( T ) struct Q { T i; };
     101forall( T ) struct { int i; };
    102102struct KK { int i; };
    103103inline static {
    104104        void RT1() {}
    105105}
    106 forall( otype T ) {
     106forall( T ) {
    107107        T RT2( T ) {
    108108                typedef int TD1;
    109109                struct S1 { T t; };
    110110        }
    111         forall( otype X ) {
     111        forall( X ) {
    112112                typedef int TD2;
    113113                struct S2 {};
     
    117117        }
    118118        extern "C" {
    119                 forall( otype W ) {
     119                forall( W ) {
    120120                        W RT3( W ) {}
    121121                        struct S3 {};
     
    123123        }
    124124        void RT4() {
    125                 forall( otype W ) struct S4 {};
     125                forall( W ) struct S4 {};
    126126                typedef int TD3;
    127127        }
     
    147147
    148148static inline {
    149         forall( otype T ) {
     149        forall( T ) {
    150150                int RT6( T p );
    151151        }
    152         forall( otype T, otype U ) {
     152        forall( T, U ) {
    153153                int RT7( T, U );
    154154        }
    155155}
    156 static forall( otype T ) {
     156static forall( T ) {
    157157        int RT8( T );
    158158}
    159 forall( otype T ) inline static {
     159forall( T ) inline static {
    160160        int RT9( T ) { T t; return 3; }
    161161}
    162162
    163 forall( otype T | { T ?+?( T, T ); } ) {
    164         forall( otype S | { T ?+?( T, S ); } ) {
    165                 forall( otype W ) T bar( T t, S s ) { return t + s; }
    166                 forall( otype W | { W ?+?( T, W ); } ) W baz( T t, S s, W w ) { return t + s + w; }
     163forall( T | { T ?+?( T, T ); } ) {
     164        forall( S | { T ?+?( T, S ); } ) {
     165                forall( W ) T bar( T t, S s ) { return t + s; }
     166                forall( W | { W ?+?( T, W ); } ) W baz( T t, S s, W w ) { return t + s + w; }
    167167                struct W { T t; } (int,int) ww;
    168168                struct P pp;
     
    170170}
    171171
    172 forall( otype T | { T ?+?( T, T ); } ) forall( otype S | { T ?+?( T, S ); } )
     172forall( T | { T ?+?( T, T ); } ) forall( S | { T ?+?( T, S ); } )
    173173struct XW { T t; };
    174174XW(int,int) xww;
    175175
    176 forall( otype T ) struct S { T t; } (int) x, y, z;
    177 forall( otype T ) struct { T t; } (int) a, b, c;
    178 
    179 forall( otype T ) static forall( otype S ) {
    180     forall( otype X ) struct U {
     176forall( T ) struct S { T t; } (int) x, y, z;
     177forall( T ) struct { T t; } (int) a, b, c;
     178
     179forall( T ) static forall( S ) {
     180    forall( X ) struct U {
    181181                T x;
    182182    };
    183183}
    184184
    185 forall( otype T ) {
     185forall( T ) {
    186186        extern "C" {
    187187                struct SS { T t; };
  • tests/function-operator.cfa

    rb6a8b31 rd95969a  
    2222
    2323// STL-like Algorithms
    24 trait Assignable(dtype T, dtype U) { T ?=?(T &, U); };
    25 trait Copyable(dtype T) { void ?{}(T &, T); };
    26 trait Destructable(dtype T) { void ^?{}(T &); };
     24trait Assignable(T &, U &) { T ?=?(T &, U); };
     25trait Copyable(T &) { void ?{}(T &, T); };
     26trait Destructable(T &) { void ^?{}(T &); };
    2727
    28 trait Iterator(dtype iter | sized(iter) | Copyable(iter) | Destructable(iter), otype T) {
     28trait Iterator(iter & | sized(iter) | Copyable(iter) | Destructable(iter), T) {
    2929        T & *?(iter);
    3030        iter ++?(iter &);
     
    3232};
    3333
    34 forall(otype Tin, dtype Input | Iterator(Input, Tin), otype Tout, dtype Output | Iterator(Output, Tout) | Assignable(Tout, Tin))
     34forall(Tin, Input & | Iterator(Input, Tin), Tout, Output & | Iterator(Output, Tout) | Assignable(Tout, Tin))
    3535Output copy(Input first, Input last, Output result) {
    3636        while (first != last) {
     
    4242
    4343// test ?()(T *, ...) -- ?() with function call-by-pointer
    44 forall(otype Tin, dtype Input | Iterator(Input, Tin), otype Tout, dtype Output | Iterator(Output, Tout), otype FuncRet, dtype Func | { FuncRet ?()(Func *, Tin); } | Assignable(Tout, FuncRet))
     44forall(Tin, Input & | Iterator(Input, Tin), Tout, Output & | Iterator(Output, Tout), FuncRet, Func & | { FuncRet ?()(Func *, Tin); } | Assignable(Tout, FuncRet))
    4545Output transform (Input first, Input last, Output result, Func * op) {
    4646        while (first != last) {
     
    5252
    5353// test ?()(T, ...) -- ?() with function call-by-value
    54 forall(dtype Iter, otype T | Iterator(Iter, T), otype Pred | { int ?()(Pred, T); })
     54forall(Iter &, T | Iterator(Iter, T), Pred | { int ?()(Pred, T); })
    5555Iter find_if (Iter first, Iter last, Pred pred) {
    5656        while (first != last) {
     
    6262
    6363// test ?()(T, ...) -- ?() with function call-by-reference
    64 forall(otype Generator, otype GenRet | { GenRet ?()(Generator &); }, dtype Iter, otype T | Iterator(Iter, T) | Assignable(T, GenRet))
     64forall(Generator, GenRet | { GenRet ?()(Generator &); }, Iter &, T | Iterator(Iter, T) | Assignable(T, GenRet))
    6565void generate(Iter first, Iter last, Generator & gen) {
    6666        int i = 0;
     
    108108}
    109109
    110 forall(otype T | { int ?==?(T, T); })
     110forall(T | { int ?==?(T, T); })
    111111struct Equals {
    112112        T val;
    113113};
    114114
    115 forall(otype T | { int ?==?(T, T); })
     115forall(T | { int ?==?(T, T); })
    116116int ?()(Equals(T) eq, T x) {
    117117        return eq.val == x;
    118118}
    119119
    120 forall(otype T | { T ?*?(T, T); })
     120forall(T | { T ?*?(T, T); })
    121121struct Multiply {
    122122        T val;
    123123};
    124124
    125 forall(otype T | { T ?*?(T, T); })
     125forall(T | { T ?*?(T, T); })
    126126T ?()(Multiply(T) * mult, T x) {
    127127        return mult->val * x;
     
    130130// TODO: generalize to ttype return; doesn't work yet
    131131// like std::function
    132 forall(otype Return, ttype Args)
     132forall(Return, Args...)
    133133struct function {
    134134        Return (*f)(Args);
  • tests/genericUnion.cfa

    rb6a8b31 rd95969a  
    1616#include <limits.hfa>
    1717
    18 forall(otype T)
     18forall(T)
    1919union ByteView {
    2020        T val;
     
    2222};
    2323
    24 forall(otype T)
     24forall(T)
    2525void print(ByteView(T) x) {
    2626        for (int i = 0; i < sizeof(int); i++) {                         // want to change to sizeof(T)
     
    2929}
    3030
    31 forall(otype T)
     31forall(T)
    3232void f(ByteView(T) x, T val) {
    3333        print(x);
  • tests/global-monomorph.cfa

    rb6a8b31 rd95969a  
    11// Create monomorphic instances of polymorphic types at global scope.
    22
    3 forall(dtype T)
     3forall(T &)
    44void poly0(T &) {}
    55
    6 forall(dtype T | sized(T))
     6forall(T & | sized(T))
    77void poly1(T &) {}
    88
    9 forall(otype T)
     9forall(T)
    1010void poly2(T &) {}
    1111
  • tests/identity.cfa

    rb6a8b31 rd95969a  
    1616#include <fstream.hfa>
    1717
    18 forall( otype T )
     18forall( T )
    1919T identity( T t ) {
    2020        return t;
  • tests/init1.cfa

    rb6a8b31 rd95969a  
    120120}
    121121
    122 forall (dtype T, dtype S)
     122forall (T &, S &)
    123123T & anycvt( S & s ) {
    124124    return s;               // mismatched referenced type
    125125}
    126126
    127 forall (dtype T, dtype S)
     127forall (T &, S &)
    128128T * anycvt( S * s ) {
    129129    return s;               // mismatched referenced type
  • tests/nested-types.cfa

    rb6a8b31 rd95969a  
    1616typedef int N;
    1717struct A {
    18         forall(otype T)
     18        forall(T)
    1919        struct N {
    2020                T x;
  • tests/poly-d-cycle.cfa

    rb6a8b31 rd95969a  
    11// Check that a cycle of polymorphic dtype structures can be instancated.
    22
    3 forall(dtype T)
     3forall(T &)
    44struct func_table;
    55
    6 forall(dtype U)
     6forall(U &)
    77struct object {
    88        func_table(U) * virtual_table;
    99};
    1010
    11 forall(dtype T)
     11forall(T &)
    1212struct func_table {
    1313        void (*object_func)(object(T) *);
  • tests/poly-o-cycle.cfa

    rb6a8b31 rd95969a  
    11// Check that a cycle of polymorphic otype structures can be instancated.
    22
    3 forall(otype T)
     3forall(T)
    44struct func_table;
    55
    6 forall(otype U)
     6forall(U)
    77struct object {
    88        func_table(U) * virtual_table;
    99};
    1010
    11 forall(otype T)
     11forall(T)
    1212struct func_table {
    1313        void (*object_func)(object(T) *);
  • tests/polymorphism.cfa

    rb6a8b31 rd95969a  
    1818#include <fstream.hfa>
    1919
    20 forall(otype T)
     20forall(T)
    2121T f(T x, T y) {
    2222        x = y;
     
    2424}
    2525
    26 forall(otype T) T ident(T x) {
     26forall(T) T ident(T x) {
    2727        return x;
    2828}
    2929
    30 forall( otype T, otype U )
     30forall( T, U )
    3131size_t struct_size( T i, U j ) {
    3232        struct S { T i; U j; };
     
    3434}
    3535
    36 forall( otype T, otype U )
     36forall( T, U )
    3737size_t union_size( T i, U j ) {
    3838        union B { T i; U j; };
     
    4141
    4242// perform some simple operations on aggregates of T and U
    43 forall( otype T | { void print(T); int ?==?(T, T); }, otype U | { void print(U); U ?=?(U&, zero_t); } )
     43forall( T | { void print(T); int ?==?(T, T); }, U | { void print(U); U ?=?(U&, zero_t); } )
    4444U foo(T i, U j) {
    4545        struct S { T i; U j; };
  • tests/raii/ctor-autogen.cfa

    rb6a8b31 rd95969a  
    3333
    3434// dtype-static generic type is otype
    35 forall(dtype T)
     35forall(T &)
    3636struct DtypeStaticStruct {
    3737  T * data;
     
    3939};
    4040
    41 forall(dtype T)
     41forall(T &)
    4242union DtypeStaticUnion {
    4343  T * data;
     
    4646
    4747// dynamic generic type is otype
    48 forall(otype T)
     48forall(T)
    4949struct DynamicStruct {
    5050        T x;
    5151};
    5252
    53 forall(otype T)
     53forall(T)
    5454union DynamicUnion {
    5555        T x;
     
    8080
    8181
    82 forall(otype T)
     82forall(T)
    8383T identity(T x) { return x; }
    8484
  • tests/simpleGenericTriple.cfa

    rb6a8b31 rd95969a  
    1414//
    1515
    16 forall(otype T)
     16forall(T)
    1717struct T3 {
    1818        T f0, f1, f2;
    1919};
    2020
    21 forall(otype T | { T ?+?(T, T); })
     21forall(T | { T ?+?(T, T); })
    2222T3(T) ?+?(T3(T) x, T3(T) y) {
    2323        T3(T) z = { x.f0+y.f0, x.f1+y.f1, x.f2+y.f2 };
  • tests/sum.cfa

    rb6a8b31 rd95969a  
    1818#include <stdlib.hfa>
    1919
    20 trait sumable( otype T ) {
     20trait sumable( T ) {
    2121        void ?{}( T &, zero_t );                                                        // 0 literal constructor
    2222        T ?+?( T, T );                                                                          // assortment of additions
     
    2626}; // sumable
    2727
    28 forall( otype T | sumable( T ) )                                                // use trait
     28forall( T | sumable( T ) )                                              // use trait
    2929T sum( size_t size, T a[] ) {
    3030        T total = 0;                                                                            // initialize by 0 constructor
     
    107107                 | sum( size, (S *)a ) | ", check" | (S)s;
    108108
    109         forall( otype Impl | sumable( Impl ) )
     109        forall( Impl | sumable( Impl ) )
    110110        struct GS {
    111111                Impl * x, * y;
     
    194194                 sum( size, (S *)a ).[i, j], s.[i, j] );
    195195
    196         forall( otype Impl | sumable( Impl ) )
     196        forall( Impl | sumable( Impl ) )
    197197        struct GS {
    198198                Impl * x, * y;
  • tests/tuple/tuplePolymorphism.cfa

    rb6a8b31 rd95969a  
    2929// ensure that f is a viable candidate for g, even though its parameter structure does not exactly match
    3030[A] f([A, B] x, B y) { printf("%g %c %g %lld %c %lld %lld %c %lld\n", x.0.[x,y,z], x.1.[x,y,z], y.[x,y,z]); return x.0; }
    31 forall(otype T, otype U | { T f(T, U, U); })
     31forall(T, U | { T f(T, U, U); })
    3232void g(T x, U y) { f(x, y, y); }
    3333
    3434// add two triples
    35 forall(otype T | { T ?+?(T, T); })
     35forall(T | { T ?+?(T, T); })
    3636[T, T, T] ?+?([T, T, T] x, [T, T, T] y) {
    3737        return [x.0+y.0, x.1+y.1, x.2+y.2];
     
    6464}
    6565
    66 forall(otype T)
     66forall(T)
    6767[T, T] foo([T, T] y) {
    6868        [T, T] x;
  • tests/tuple/tupleVariadic.cfa

    rb6a8b31 rd95969a  
    1919        printf("called func(void)\n");
    2020}
    21 forall(otype T, ttype Params | { void process(T); void func(Params); })
     21forall(T, Params... | { void process(T); void func(Params); })
    2222void func(T arg1, Params p) {
    2323        process(arg1);
     
    9292}
    9393
    94 forall(otype T)
     94forall(T)
    9595T * copy(T x) {
    9696        // test calling new inside a polymorphic function
     
    9898}
    9999
    100 forall(ttype T | { void foo(T); }) void bar(T x) {}
     100forall(T... | { void foo(T); }) void bar(T x) {}
    101101void foo(int) {}
    102102
  • tests/zombies/ArrayN.c

    rb6a8b31 rd95969a  
    66// }
    77
    8 forall(otype index_t)
     8forall(index_t)
    99index_t offset_to_index(unsigned offset, index_t size) {
    1010    return [offset / size.0, offset % size.1];
  • tests/zombies/Members.c

    rb6a8b31 rd95969a  
    22int ?=?( int*, int );
    33float ?=?( float*, float );
    4 forall( dtype DT ) DT * ?=?( DT**, DT* );
    5 forall(otype T) lvalue T *?( T* );
     4forall( DT & ) DT * ?=?( DT**, DT* );
     5forall(T) lvalue T *?( T* );
    66char *__builtin_memcpy();
    77
  • tests/zombies/Rank2.c

    rb6a8b31 rd95969a  
    11int ?=?( int &, int );
    2 forall(dtype DT) DT * ?=?( DT *&, DT * );
     2forall(DT &) DT * ?=?( DT *&, DT * );
    33
    44void a() {
    5         forall( otype T ) void f( T );
    6         void g( forall( otype U ) void p( U ) );
     5        forall( T ) void f( T );
     6        void g( forall( U ) void p( U ) );
    77        g( f );
    88}
     
    1010void g() {
    1111        void h( int *null );
    12         forall( otype T ) T id( T );
     12        forall( T ) T id( T );
    1313//      forall( dtype T ) T *0;
    1414//      int 0;
  • tests/zombies/abstype.c

    rb6a8b31 rd95969a  
    2121}
    2222
    23 forall( otype T ) T *?( T * );
     23forall( T ) T *?( T * );
    2424int ?++( int * );
    2525int ?=?( int *, int );
    26 forall( dtype DT ) DT * ?=?( DT **, DT * );
     26forall( DT & ) DT * ?=?( DT **, DT * );
    2727
    2828otype U = int *;
  • tests/zombies/context.cfa

    rb6a8b31 rd95969a  
    11// trait declaration
    22
    3 trait has_q( otype T ) {
     3trait has_q( T ) {
    44        T q( T );
    55};
    66
    7 forall( otype z | has_q( z ) ) void f() {
    8         trait has_r( otype T, otype U ) {
     7forall( z | has_q( z ) ) void f() {
     8        trait has_r( T, U ) {
    99                T r( T, T (T,U) );
    1010        };
  • tests/zombies/gc_no_raii/bug-repro/blockers/explicit_cast.c

    rb6a8b31 rd95969a  
    99};
    1010
    11 forall(otype T)
     11forall(T)
    1212struct gcpointer
    1313{
     
    1515};
    1616
    17 forall(otype T)
     17forall(T)
    1818static inline gcpointer(T) gcmalloc()
    1919{
  • tests/zombies/gc_no_raii/bug-repro/blockers/recursive_realloc.c

    rb6a8b31 rd95969a  
    33#include <stdlib.hfa>
    44
    5 trait allocator_c(otype T, otype allocator_t)
     5trait allocator_c(T, allocator_t)
    66{
    77        void realloc(allocator_t* const, size_t);
    88};
    99
    10 forall(otype T)
     10forall(T)
    1111struct heap_allocator
    1212{
     
    1515};
    1616
    17 forall(otype T)
     17forall(T)
    1818inline void realloc(heap_allocator(T) *const this, size_t size)
    1919{
  • tests/zombies/gc_no_raii/bug-repro/deref.c

    rb6a8b31 rd95969a  
    1     forall(otype T)
     1    forall(T)
    22    struct wrap
    33    {
     
    55    };
    66
    7     forall(otype T)
     7    forall(T)
    88    T *? (wrap(T) rhs)
    99    {
  • tests/zombies/gc_no_raii/bug-repro/field.c

    rb6a8b31 rd95969a  
    88//------------------------------------------------------------------------------
    99//Declaration
    10 trait allocator_c(otype T, otype allocator_t)
     10trait allocator_c(T, allocator_t)
    1111{
    1212        void ctor(allocator_t* const);
     
    1616};
    1717
    18 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     18forall(T, allocator_t | allocator_c(T, allocator_t))
    1919struct vector
    2020{
  • tests/zombies/gc_no_raii/bug-repro/malloc.c

    rb6a8b31 rd95969a  
    1 forall(otype T)
     1forall(T)
    22struct wrapper
    33{
     
    55};
    66
    7 forall(otype T)
     7forall(T)
    88void ctor(wrapper(T)* this)
    99{
     
    1111}
    1212
    13 forall(otype T)
     13forall(T)
    1414wrapper(T) gcmalloc()
    1515{
     
    1919}
    2020
    21 forall(otype T)
     21forall(T)
    2222wrapper(T)* ?=? (wrapper(T)* lhs, wrapper(T)* rhs)
    2323{
  • tests/zombies/gc_no_raii/bug-repro/oddtype.c

    rb6a8b31 rd95969a  
    1 forall(dtype T)
     1forall(T &)
    22struct wrap {
    33        int i;
    44};
    55
    6 forall(otype T) void ?{}(wrap(T)* this) {}
    7 forall(otype T) void ?=?(wrap(T)* this) {}
    8 forall(otype T) void ^?{}(wrap(T)* this) {}
     6forall(T) void ?{}(wrap(T)* this) {}
     7forall(T) void ?=?(wrap(T)* this) {}
     8forall(T) void ^?{}(wrap(T)* this) {}
    99
    1010struct List_t {
  • tests/zombies/gc_no_raii/bug-repro/push_back.h

    rb6a8b31 rd95969a  
    11//------------------------------------------------------------------------------
    22//Declaration
    3 trait allocator_c(otype T, otype allocator_t) {
     3trait allocator_c(T, allocator_t) {
    44        void ctor(allocator_t* const);
    55        void dtor(allocator_t* const);
     
    88};
    99
    10 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     10forall(T, allocator_t | allocator_c(T, allocator_t))
    1111struct vector
    1212{
     
    1717//------------------------------------------------------------------------------
    1818//Initialization
    19 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     19forall(T, allocator_t | allocator_c(T, allocator_t))
    2020void vector_ctor(vector(T, allocator_t) *const this);
    2121
    22 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     22forall(T, allocator_t | allocator_c(T, allocator_t))
    2323void dtor(vector(T, allocator_t) *const this);
    2424
    2525//------------------------------------------------------------------------------
    2626//Allocator
    27 forall(otype T)
     27forall(T)
    2828struct heap_allocator
    2929{
     
    3232};
    3333
    34 forall(otype T)
     34forall(T)
    3535void ctor(heap_allocator(T) *const this);
    3636
    37 forall(otype T)
     37forall(T)
    3838void dtor(heap_allocator(T) *const this);
    3939
    40 forall(otype T)
     40forall(T)
    4141void realloc(heap_allocator(T) *const this, size_t size);
    4242
    43 forall(otype T)
     43forall(T)
    4444inline T* data(heap_allocator(T) *const this)
    4545{
     
    4949//------------------------------------------------------------------------------
    5050//Capacity
    51 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     51forall(T, allocator_t | allocator_c(T, allocator_t))
    5252inline bool empty(vector(T, allocator_t) *const this)
    5353{
     
    5555}
    5656
    57 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     57forall(T, allocator_t | allocator_c(T, allocator_t))
    5858inline bool size(vector(T, allocator_t) *const this)
    5959{
     
    6161}
    6262
    63 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     63forall(T, allocator_t | allocator_c(T, allocator_t))
    6464inline void reserve(vector(T, allocator_t) *const this, size_t size)
    6565{
     
    6969//------------------------------------------------------------------------------
    7070//Modifiers
    71 forall(otype T, otype allocator_t | allocator_c(T, allocator_t))
     71forall(T, allocator_t | allocator_c(T, allocator_t))
    7272void push_back(vector(T, allocator_t) *const this, T value);
  • tests/zombies/gc_no_raii/bug-repro/realloc.c

    rb6a8b31 rd95969a  
    11void* realloc(void*, unsigned long int);
    22
    3 forall(otype T)
     3forall(T)
    44struct wrap
    55{
     
    77};
    88
    9 forall(otype T)
     9forall(T)
    1010static inline void realloc(wrap(T) *const this, unsigned long int size)
    1111{
  • tests/zombies/gc_no_raii/bug-repro/return.c

    rb6a8b31 rd95969a  
    1 forall(otype T)
     1forall(T)
    22struct wrapper
    33{
     
    55};
    66
    7 forall(otype T)
     7forall(T)
    88wrapper(T) create()
    99{
     
    1212}
    1313
    14 forall(otype T)
     14forall(T)
    1515wrapper(T)* ?=?(wrapper(T)* lhs, wrapper(T)* rhs)
    1616{
  • tests/zombies/gc_no_raii/bug-repro/return_template.c

    rb6a8b31 rd95969a  
    1 forall(otype T)
     1forall(T)
    22struct wrap
    33{
     
    55};
    66
    7 forall(otype T) void ?{}(wrap(T)* this);
    8 forall(otype T) void ?{}(wrap(T)* this, wrap(T)* rhs);
    9 forall(otype T) void ^?{}(wrap(T)* this);
    10 forall(otype T) void ?=?(wrap(T)* this, wrap(T)* rhs);
     7forall(T) void ?{}(wrap(T)* this);
     8forall(T) void ?{}(wrap(T)* this, wrap(T)* rhs);
     9forall(T) void ^?{}(wrap(T)* this);
     10forall(T) void ?=?(wrap(T)* this, wrap(T)* rhs);
    1111
    12 forall(otype T)
     12forall(T)
    1313wrap(T) test()
    1414{
  • tests/zombies/gc_no_raii/bug-repro/slow_malloc.c

    rb6a8b31 rd95969a  
    11#include <stdlib.hfa>
    22
    3 forall(otype T)
     3forall(T)
    44struct heap_allocator
    55{
  • tests/zombies/gc_no_raii/bug-repro/zero.c

    rb6a8b31 rd95969a  
    1 forall(otype T)
     1forall(T)
    22struct wrap
    33{
     
    55};
    66
    7 forall(otype T)
     7forall(T)
    88int ?==? (wrap(T) lhs, wrap(T) rhs)
    99{
     
    1414struct wrap(int) 0;
    1515/*/
    16 forall(otype T)
     16forall(T)
    1717struct wrap(T) 0;
    1818//*/
  • tests/zombies/gc_no_raii/src/gc.h

    rb6a8b31 rd95969a  
    1313// }
    1414
    15 forall(otype T)
     15forall(T)
    1616static inline void gcmalloc(gcpointer(T)* ptr)
    1717{
  • tests/zombies/gc_no_raii/src/gcpointers.c

    rb6a8b31 rd95969a  
    113113#endif
    114114
    115 forall(otype T) void ?{}(gcpointer(T)* this) {
     115forall(T) void ?{}(gcpointer(T)* this) {
    116116        (&this->internal) {};
    117117}
    118118
    119 forall(otype T) void ?{}(gcpointer(T)* this, void* address) {
     119forall(T) void ?{}(gcpointer(T)* this, void* address) {
    120120        (&this->internal) { address };
    121121}
    122122
    123 forall(otype T) void ?{}(gcpointer(T)* this, gcpointer(T) other) {
     123forall(T) void ?{}(gcpointer(T)* this, gcpointer(T) other) {
    124124        (&this->internal) { other.internal };
    125125}
    126126
    127 forall(otype T) void ^?{}(gcpointer(T)* this) {
     127forall(T) void ^?{}(gcpointer(T)* this) {
    128128        ^?{}(&this->internal);
    129129}
    130130
    131 forall(otype T) gcpointer(T) ?=?(gcpointer(T)* this, gcpointer(T) rhs) {
     131forall(T) gcpointer(T) ?=?(gcpointer(T)* this, gcpointer(T) rhs) {
    132132        this->internal = rhs.internal;
    133133        return *this;
     
    136136// forall(otype T) T *?(gcpointer(T) this);
    137137
    138 forall(otype T) T* get(gcpointer(T)* this) {
     138forall(T) T* get(gcpointer(T)* this) {
    139139        return (T*)this->internal.ptr;
    140140}
    141141//
    142142// //Logical operators
    143 forall(otype T) int ?!=?(gcpointer(T) this, int zero) {
     143forall(T) int ?!=?(gcpointer(T) this, int zero) {
    144144        return this.internal.ptr != 0;
    145145}
  • tests/zombies/gc_no_raii/src/gcpointers.h

    rb6a8b31 rd95969a  
    44#include <stdint.h>
    55
    6 forall(dtype T)
     6forall(T &)
    77struct gcpointer;
    88
     
    2929#endif
    3030
    31 forall(dtype T)
     31forall(T &)
    3232struct gcpointer
    3333{
     
    3636
    3737//
    38 forall(otype T) void ?{}(gcpointer(T)* this);
    39 forall(otype T) void ?{}(gcpointer(T)* this, void* address);
    40 forall(otype T) void ?{}(gcpointer(T)* this, gcpointer(T) other);
    41 forall(otype T) void ^?{}(gcpointer(T)* this);
    42 forall(otype T) gcpointer(T) ?=?(gcpointer(T)* this, gcpointer(T) rhs);
     38forall(T) void ?{}(gcpointer(T)* this);
     39forall(T) void ?{}(gcpointer(T)* this, void* address);
     40forall(T) void ?{}(gcpointer(T)* this, gcpointer(T) other);
     41forall(T) void ^?{}(gcpointer(T)* this);
     42forall(T) gcpointer(T) ?=?(gcpointer(T)* this, gcpointer(T) rhs);
    4343
    4444
    4545// forall(otype T) T *?(gcpointer(T) this);
    46 forall(otype T) T* get(gcpointer(T)* this);
     46forall(T) T* get(gcpointer(T)* this);
    4747
    4848//Logical operators
    49 forall(otype T) int ?!=?(gcpointer(T) this, int zero);
    50 forall(otype T) int ?!=?(gcpointer(T) this, gcpointer(T) rhs);
    51 forall(otype T) int ?==?(gcpointer(T) this, gcpointer(T) rhs);
     49forall(T) int ?!=?(gcpointer(T) this, int zero);
     50forall(T) int ?!=?(gcpointer(T) this, gcpointer(T) rhs);
     51forall(T) int ?==?(gcpointer(T) this, gcpointer(T) rhs);
  • tests/zombies/gc_no_raii/src/tools.h

    rb6a8b31 rd95969a  
    1212// }
    1313
    14 trait has_equal(otype T)
     14trait has_equal(T)
    1515{
    1616        signed int ?==?(T a, T b);
    1717};
    1818
    19 trait InputIterator_t(otype T, otype InputIterator)
     19trait InputIterator_t(T, InputIterator)
    2020{
    2121        signed int ?==?(InputIterator a, InputIterator b);
     
    2626};
    2727
    28 forall(otype T | has_equal(T), otype InputIterator | InputIterator_t(T, InputIterator))
     28forall(T | has_equal(T), InputIterator | InputIterator_t(T, InputIterator))
    2929static inline InputIterator find( InputIterator first, const InputIterator* const last, T val)
    3030{
  • tests/zombies/hashtable.cfa

    rb6a8b31 rd95969a  
    1414
    1515
    16 trait has_hash( otype K ) {
     16trait has_hash( K ) {
    1717    size_t hash(K);
    1818    int ?==?( K, K );
    1919};
    2020
    21 trait hkey( otype K, dtype tN | has_hash(K) ) {
     21trait hkey( K, tN & | has_hash(K) ) {
    2222    K key(tN &);
    2323};
    2424
    25 forall( otype K, dtype tN, dtype tE | $dlistable(tN, tE) | hkey(K, tN) ) {
     25forall( K, tN &, tE & | $dlistable(tN, tE) | hkey(K, tN) ) {
    2626
    2727    struct hashtable {
     
    3939}
    4040
    41 forall( otype K, dtype tN, dtype tE | $dlistable(tN, tE) | hkey(K, tN) | { void defaultResumptionHandler(ht_fill_limit_crossed &); } ) {
     41forall( K, tN &, tE & | $dlistable(tN, tE) | hkey(K, tN) | { void defaultResumptionHandler(ht_fill_limit_crossed &); } ) {
    4242
    4343    void ?{}( hashtable(K, tN, tE) & this, size_t n_buckets, dlist(tN, tE) *buckets ) {
     
    5757}
    5858
    59 forall( otype K, dtype tN, dtype tE | $dlistable(tN, tE) | hkey(K, tN) ) {
     59forall( K, tN &, tE & | $dlistable(tN, tE) | hkey(K, tN) ) {
    6060
    6161    float fill_frac( hashtable(K, tN, tE) & this ) with(this) {
     
    124124
    125125
    126 trait heaped(dtype T) {
     126trait heaped(T &) {
    127127    T * alloc( size_t );
    128128    void free( void * );
     
    133133}
    134134
    135 forall( otype K, dtype tN, dtype tE | $dlistable(tN, tE) | hkey(K, tN) | heaped( dlist(tN, tE) ) ) {
     135forall( K, tN &, tE & | $dlistable(tN, tE) | hkey(K, tN) | heaped( dlist(tN, tE) ) ) {
    136136
    137137    struct hashtable_dynamic {
  • tests/zombies/hashtable2.cfa

    rb6a8b31 rd95969a  
    6969
    7070
    71 trait pretendsToMatter( dtype TTT ) {
     71trait pretendsToMatter( TTT & ) {
    7272    void actsmart(TTT &);
    7373};
    7474
    75 forall( dtype TTTx )
     75forall( TTTx & )
    7676void actsmart(TTTx &) {}
    7777
     
    8686//   2. shows up in -CFA output as hashtable_rbs(), which is bad C; expecting hashtable_rbs*
    8787
    88 forall( otype Tt_unused | pretendsToMatter(Tt_unused) ) {
     88forall( Tt_unused | pretendsToMatter(Tt_unused) ) {
    8989
    9090    // hashtable of request by source
     
    104104}
    105105
    106 forall( otype Tt_unused | pretendsToMatter(Tt_unused) | { void defaultResumptionHandler(ht_fill_limit_crossed &); } ) {
     106forall( Tt_unused | pretendsToMatter(Tt_unused) | { void defaultResumptionHandler(ht_fill_limit_crossed &); } ) {
    107107
    108108    void ?{}( hashtable_rbs(Tt_unused) & this, size_t n_buckets, dlist(request_in_ht_by_src, request) *buckets,
     
    135135void defaultResumptionHandler( ht_auto_resize_pending & ex );
    136136
    137 forall( otype Tt_unused | pretendsToMatter(Tt_unused) ) {
     137forall( Tt_unused | pretendsToMatter(Tt_unused) ) {
    138138
    139139    float fill_frac( hashtable_rbs(Tt_unused) & this ) with(this) {
     
    221221
    222222
    223 trait heaped(dtype T) {
     223trait heaped(T &) {
    224224    T * alloc( size_t );
    225225    void free( void * );
     
    228228void __dynamic_defaultResumptionHandler(ht_fill_limit_crossed &);
    229229
    230 forall( otype Tt_unused ) {
     230forall( Tt_unused ) {
    231231
    232232    struct hashtable_rbs_dynamic {
     
    263263
    264264
    265 forall( otype Tt_unused | heaped( dlist(request_in_ht_by_src, request) ) ) {
     265forall( Tt_unused | heaped( dlist(request_in_ht_by_src, request) ) ) {
    266266
    267267    void ?{}( hashtable_rbs_dynamic(Tt_unused).resize_policy & this, size_t nbuckets_floor ) {
     
    325325}
    326326
    327 forall( otype Tt_unused ) {
     327forall( Tt_unused ) {
    328328    void rehashToLarger_STEP( hashtable_rbs_dynamic(Tt_unused) & this, size_t new_n_buckets ) with (this) {
    329329        rehashToLarger( this, new_n_buckets );
  • tests/zombies/huge.c

    rb6a8b31 rd95969a  
    1414//
    1515
    16 int huge( int n, forall( otype T ) T (*f)( T ) ) {
     16int huge( int n, forall( T ) T (*f)( T ) ) {
    1717        if ( n <= 0 )
    1818                return f( 0 );
  • tests/zombies/it_out.c

    rb6a8b31 rd95969a  
    1616typedef unsigned long streamsize_type;
    1717
    18 trait ostream( dtype os_type ) {
     18trait ostream( os_type & ) {
    1919        os_type *write( os_type *, const char *, streamsize_type );
    2020        int fail( os_type * );
    2121};
    2222
    23 trait writeable( otype T ) {
    24         forall( dtype os_type | ostream( os_type ) ) os_type * ?<<?( os_type *, T );
     23trait writeable( T ) {
     24        forall( os_type & | ostream( os_type ) ) os_type * ?<<?( os_type *, T );
    2525};
    2626
    27 forall( dtype os_type | ostream( os_type ) ) os_type * ?<<?( os_type *, char );
    28 forall( dtype os_type | ostream( os_type ) ) os_type * ?<<?( os_type *, int );
    29 forall( dtype os_type | ostream( os_type ) ) os_type * ?<<?( os_type *, const char * );
     27forall( os_type & | ostream( os_type ) ) os_type * ?<<?( os_type *, char );
     28forall( os_type & | ostream( os_type ) ) os_type * ?<<?( os_type *, int );
     29forall( os_type & | ostream( os_type ) ) os_type * ?<<?( os_type *, const char * );
    3030
    31 trait istream( dtype is_type ) {
     31trait istream( is_type & ) {
    3232        is_type *read( is_type *, char *, streamsize_type );
    3333        is_type *unread( is_type *, char );
     
    3636};
    3737
    38 trait readable( otype T ) {
    39         forall( dtype is_type | istream( is_type ) ) is_type * ?<<?( is_type *, T );
     38trait readable( T ) {
     39        forall( is_type & | istream( is_type ) ) is_type * ?<<?( is_type *, T );
    4040};
    4141
    42 forall( dtype is_type | istream( is_type ) ) is_type * ?>>?( is_type *, char* );
    43 forall( dtype is_type | istream( is_type ) ) is_type * ?>>?( is_type *, int* );
     42forall( is_type & | istream( is_type ) ) is_type * ?>>?( is_type *, char* );
     43forall( is_type & | istream( is_type ) ) is_type * ?>>?( is_type *, int* );
    4444
    45 trait iterator( otype iterator_type, otype elt_type ) {
     45trait iterator( iterator_type, elt_type ) {
    4646        iterator_type ?++( iterator_type* );
    4747        iterator_type ++?( iterator_type* );
     
    5252};
    5353
    54 forall( otype elt_type | writeable( elt_type ),
    55                 otype iterator_type | iterator( iterator_type, elt_type ),
    56                 dtype os_type | ostream( os_type ) )
     54forall( elt_type | writeable( elt_type ),
     55                iterator_type | iterator( iterator_type, elt_type ),
     56                os_type & | ostream( os_type ) )
    5757void write_all( iterator_type begin, iterator_type end, os_type *os );
    5858
    59 forall( otype elt_type | writeable( elt_type ),
    60                 otype iterator_type | iterator( iterator_type, elt_type ),
    61                 dtype os_type | ostream( os_type ) )
     59forall( elt_type | writeable( elt_type ),
     60                iterator_type | iterator( iterator_type, elt_type ),
     61                os_type & | ostream( os_type ) )
    6262void write_all( elt_type begin, iterator_type end, os_type *os ) {
    6363        os << begin;
  • tests/zombies/new.c

    rb6a8b31 rd95969a  
    1414//
    1515
    16 forall( otype T )
     16forall( T )
    1717void f( T *t ) {
    1818        t--;
  • tests/zombies/occursError.cfa

    rb6a8b31 rd95969a  
    1 forall( otype T ) void f( void (*)( T, T * ) );
    2 forall( otype U ) void g( U,  U * );
    3 forall( otype U ) void h( U *, U );
     1forall( T ) void f( void (*)( T, T * ) );
     2forall( U ) void g( U,  U * );
     3forall( U ) void h( U *, U );
    44
    55void test() {
  • tests/zombies/prolog.c

    rb6a8b31 rd95969a  
    2525void is_integer( int x ) {}
    2626
    27 trait ArithmeticType( otype T ) {
     27trait ArithmeticType( T ) {
    2828        void is_arithmetic( T );
    2929};
    3030
    31 trait IntegralType( otype T | ArithmeticType( T ) ) {
     31trait IntegralType( T | ArithmeticType( T ) ) {
    3232        void is_integer( T );
    3333};
    3434
    35 forall( otype T | IntegralType( T ) | { void printResult( T ); } )
     35forall( T | IntegralType( T ) | { void printResult( T ); } )
    3636void hornclause( T param ) {
    3737        printResult( param );
  • tests/zombies/quad.c

    rb6a8b31 rd95969a  
    1616#include <fstream.hfa>
    1717
    18 forall( otype T | { T ?*?( T, T ); } )
     18forall( T | { T ?*?( T, T ); } )
    1919T square( T t ) {
    2020        return t * t;
    2121}
    2222
    23 forall( otype U | { U square( U ); } )
     23forall( U | { U square( U ); } )
    2424U quad( U u ) {
    2525        return square( square( u ) );
  • tests/zombies/scope.cfa

    rb6a8b31 rd95969a  
    2020y p;
    2121
    22 trait has_u( otype z ) {
     22trait has_u( z ) {
    2323        z u(z);
    2424};
    2525
    26 forall( otype t | has_u( t ) )
     26forall( t | has_u( t ) )
    2727y q( t the_t ) {
    2828        t y = u( the_t );
  • tests/zombies/simplePoly.c

    rb6a8b31 rd95969a  
    1414//
    1515
    16 forall( otype T, otype U | { T f( T, U ); } )
     16forall( T, U | { T f( T, U ); } )
    1717T q( T t, U u ) {
    1818        return f( t, u );
  • tests/zombies/simpler.c

    rb6a8b31 rd95969a  
    1414//
    1515
    16 forall( otype T ) T id( T, T );
     16forall( T ) T id( T, T );
    1717
    1818int main() {
  • tests/zombies/specialize.c

    rb6a8b31 rd95969a  
    3939}
    4040
    41 forall( otype T ) T f( T t )
     41forall( T ) T f( T t )
    4242{
    4343        printf( "in f; sizeof T is %d\n", sizeof( T ) );
  • tests/zombies/square.c

    rb6a8b31 rd95969a  
    1616#include <fstream.hfa>
    1717
    18 forall( otype T | { T ?*?( T, T ); } )
     18forall( T | { T ?*?( T, T ); } )
    1919T square( T t ) {
    2020        return t * t;
  • tests/zombies/structMember.cfa

    rb6a8b31 rd95969a  
    6666        S.T;
    6767        .S.T;
    68         forall( otype S, otype T ) struct W {
     68        forall( S, T ) struct W {
    6969                struct X {};
    7070        };
  • tests/zombies/subrange.cfa

    rb6a8b31 rd95969a  
    11// A small context defining the notion of an ordered otype.  (The standard
    22// library should probably contain a context for this purpose.)
    3 trait ordered(otype T) {
     3trait ordered(T) {
    44    int ?<?(T, T), ?<=?(T, T);
    55};
     
    77// A subrange otype resembling an Ada subotype with a base otype and a range
    88// constraint.
    9 otype subrange(otype base_t | ordered(base_t), base_t low = 0, base_t high = 8) = base_t;
     9otype subrange(base_t | ordered(base_t), base_t low = 0, base_t high = 8) = base_t;
    1010
    1111// Note that subrange() can be applied to floating-point and pointer otypes, not
     
    2828
    2929// Convenient access to subrange bounds, for instance for iteration:
    30 forall (otype T, T low, T high)
     30forall (T, T low, T high)
    3131T lbound( subrange(T, low, high) v) {
    3232    return low;
    3333}
    3434
    35 forall (otype T, T low, T high)
     35forall (T, T low, T high)
    3636T hbound( subrange(T, low, high) v) {
    3737    return high;
     
    4444// of exception handling here.  Inlining allows the compiler to eliminate
    4545// bounds checks.
    46 forall (otype T | ordered(T), T low, T high)
     46forall (T | ordered(T), T low, T high)
    4747inline subrange(T, low, high) ?=?(subrange(T, low, high)* target, T source) {
    4848    if (low <= source && source <= high) *((T*)target) = source;
     
    5454// compares range bounds so that the compiler can optimize checks away when the
    5555// ranges are known to overlap.
    56 forall (otype T | ordered(T), T t_low, T t_high, T s_low, T s_high)
     56forall (T | ordered(T), T t_low, T t_high, T s_low, T s_high)
    5757inline subrange(T, t_low, t_high) ?=?(subrange(T, t_low, t_high)* target,
    5858                                      subrange(T, s_low, s_high) source) {
  • tests/zombies/twice.c

    rb6a8b31 rd95969a  
    1616#include <fstream.hfa>
    1717
    18 forall( otype T | { T ?+?( T, T ); } )
     18forall( T | { T ?+?( T, T ); } )
    1919T twice( const T t ) {
    2020        return t + t;
  • tests/zombies/typeGenerator.cfa

    rb6a8b31 rd95969a  
    1 context addable( otype T ) {
     1context addable( T ) {
    22        T ?+?( T,T );
    33        T ?=?( T*, T);
    44};
    55
    6 otype List1( otype T | addable( T ) ) = struct { T data; List1( T ) *next; } *;
     6otype List1( T | addable( T ) ) = struct { T data; List1( T ) *next; } *;
    77typedef List1( int ) ListOfIntegers;
    88//List1( int ) li;
     
    1111[int] h( * List1( int ) p );                                                    // new declaration syntax
    1212
    13 struct( otype T ) S2 { T i; };                                                  // actual definition
     13struct( T ) S2 { T i; };                                                        // actual definition
    1414struct( int ) S3 v1, *p;                                                                // expansion and instantiation
    15 struct( otype T )( int ) S24 { T i; } v2;                               // actual definition, expansion and instantiation
    16 struct( otype T )( int ) { T i; } v2;                                   // anonymous actual definition, expansion and instantiation
     15struct( T )( int ) S24 { T i; } v2;                             // actual definition, expansion and instantiation
     16struct( T )( int ) { T i; } v2;                                 // anonymous actual definition, expansion and instantiation
    1717
    18 struct( otype T | addable( T ) ) node { T data; struct( T ) node *next; };
    19 otype List( otype T ) = struct( T ) node *;
     18struct( T | addable( T ) ) node { T data; struct( T ) node *next; };
     19otype List( T ) = struct( T ) node *;
    2020List( int ) my_list;
    2121
  • tests/zombies/withStatement.cfa

    rb6a8b31 rd95969a  
    5454}
    5555
    56 forall( otype T )
     56forall( T )
    5757struct Box {
    5858        T x;
    5959};
    6060
    61 forall( otype T )
     61forall( T )
    6262void ?{}( Box(T) & this ) with( this ) { // with clause in polymorphic function
    6363        x{};
     
    6666void print( int i ) { sout | i; }
    6767
    68 forall( otype T | { void print( T ); })
     68forall( T | { void print( T ); })
    6969void foo( T t ) {
    7070        Box( T ) b = { t };
  • tests/zombies/wrapper/src/pointer.h

    rb6a8b31 rd95969a  
    88// type safe malloc / free
    99
    10 forall(otype T)
     10forall(T)
    1111T* new()
    1212{
     
    1616}
    1717
    18 forall(otype T)
     18forall(T)
    1919void delete(T* p)
    2020{
Note: See TracChangeset for help on using the changeset viewer.