Changes in / [2b4daf2:42f6e07]


Ignore:
Files:
11 added
57 deleted
87 edited

Legend:

Unmodified
Added
Removed
  • Jenkins/FullBuild

    r2b4daf2 r42f6e07  
    3232
    3333                        stage('Package') {
    34                                 trigger_dist( commitId, currentBuild.number.toString() )
     34                                build job: 'Cforall_Distribute_Ref', parameters: [string(name: 'GitRef', value: commitId), string(name: 'Build', value: currentBuild.number.toString())]
    3535                        }
    3636                }
     
    103103}
    104104
    105 def trigger_dist(String commitId, String buildNum) {
    106         def result = build job: 'Cforall_Distribute_Ref',       \
    107                 parameters: [                                           \
    108                         string(name: 'GitRef', value: commitId),        \
    109                         string(name: 'Build' , value: buildNum) \
    110                 ],                                                              \
    111                 propagate: false
    112 
    113         echo(result.result)
    114 
    115         if(result.result != 'SUCCESS') {
    116                 sh("wget -q -O - https://cforall.uwaterloo.ca/jenkins/job/Cforall_Distribute_Ref/${result.number}/consoleText")
    117                 error(result.result)
    118         }
    119 }
    120 
    121105//===========================================================================================================
    122106//Routine responsible of sending the email notification once the build is completed
  • Jenkins/tools.groovy

    r2b4daf2 r42f6e07  
    66import org.jenkinsci.plugins.pipeline.modeldefinition.Utils
    77
     8// Global for the stage name
     9StageName = ''
     10
    811// wrapper around stage declaretion to be more verbose
    912// and allow showing as skipped in the UI
    1013def BuildStage(String name, boolean run, Closure block ) {
    11         echo " -------- ${name} -------- "
     14        StageName = name
     15        echo " -------- ${StageName} -------- "
    1216        if(run) {
    1317                stage(name, block)
  • Jenkinsfile

    r2b4daf2 r42f6e07  
    5454        //attach the build log to the email
    5555        catch (Exception caughtError) {
    56                 // Store the result of the build log
    57                 currentBuild.result = "FAILURE"
    58 
    59                 // An error has occured, the build log is relevent
     56                //rethrow error later
     57                err = caughtError
     58
     59                echo err.toString()
     60
     61                //An error has occured, the build log is relevent
    6062                log_needed = true
    6163
    62                 // rethrow error later
    63                 err = caughtError
    64 
    65                 // print the error so it shows in the log
    66                 echo err.toString()
     64                //Store the result of the build log
     65                currentBuild.result = "${tools.StageName} FAILURE".trim()
    6766        }
    6867
  • benchmark/Makefile.am

    r2b4daf2 r42f6e07  
    522522size-cfa$(EXEEXT):
    523523        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/size/size.cfa
    524 
    525 ## =========================================================================================================
    526 
    527 %-tokio$(EXEEXT): $(srcdir)/readyQ/%.rs $(srcdir)/bench.rs
    528         cd $(builddir) && cargo build --release
    529         cp $(builddir)/target/release/$(basename $@) $@
  • benchmark/creation/node_cor.js

    r2b4daf2 r42f6e07  
    66function * coroutine() { yield }
    77
    8 for ( var i = 0; i < times; i += 1 ) { // warm JIT
     8for ( var i = 0; i < times; i += 1 ) { // warm jit
    99        cor = coroutine()
    1010}
  • benchmark/ctxswitch/node_cor.js

    r2b4daf2 r42f6e07  
    1111cor = coroutine()
    1212
    13 for ( var i = 0; i < times; i += 1 ) { // warm JIT
     13for ( var i = 0; i < times; i += 1 ) { // warm git
    1414        cor.next();
    1515}
  • benchmark/readyQ/bench.go

    r2b4daf2 r42f6e07  
    55        "flag"
    66        "fmt"
    7         "log"
    87        "os"
    98        "runtime"
    10         "runtime/pprof"
    119        "sync/atomic"
    1210        "time"
     
    4543}
    4644
    47 func bench_init() func() {
     45func bench_init() {
    4846        nprocsOpt := flag.Int("p", 1, "The number of processors")
    4947        nthreadsOpt := flag.Int("t", 1, "The number of threads")
    5048        durationOpt := flag.Float64("d", 0, "Duration of the experiment in seconds")
    5149        stopOpt := flag.Uint64("i", 0, "Duration of the experiment in iterations")
    52         cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
    5350
    5451        flag.Parse()
     
    7572
    7673        runtime.GOMAXPROCS(nprocs)
    77 
    78         if (*cpuprofile) != "" {
    79                 f, err := os.Create(*cpuprofile)
    80                 if err != nil {
    81                     log.Fatal(err)
    82                 }
    83                 pprof.StartCPUProfile(f)
    84         }
    85 
    86         return func() {
    87                 if (*cpuprofile) != "" {
    88                         pprof.StopCPUProfile()
    89                 }
    90         }
    9174}
  • benchmark/readyQ/cycle.cpp

    r2b4daf2 r42f6e07  
    7171                { 'r', "ringsize", "Number of threads in a cycle", ring_size }
    7272        };
    73         BENCH_OPT_PARSE("libfibre cycle benchmark");
     73        BENCH_OPT_PARSE("cforall cycle benchmark");
    7474
    7575        {
  • benchmark/readyQ/cycle.rs

    r2b4daf2 r42f6e07  
     1#[cfg(any(
     2        feature = "sync time rt-threaded",
     3  ))]
     4
     5extern crate tokio;
     6
     7use std::io::{self, Write};
    18use std::sync::Arc;
    2 use std::sync::atomic::Ordering;
    3 use std::time::Instant;
     9use std::sync::atomic::{AtomicU64, AtomicBool,Ordering};
     10use std::time::{Instant,Duration};
    411
    512use tokio::runtime::Builder;
    613use tokio::sync;
    7 
     14use tokio::time;
     15
     16extern crate isatty;
     17use isatty::stdout_isatty;
     18
     19extern crate num_format;
     20use num_format::{Locale, ToFormattedString};
     21
     22extern crate clap;
    823use clap::{Arg, App};
    9 use num_format::{Locale, ToFormattedString};
    10 
    11 #[path = "../bench.rs"]
    12 mod bench;
    13 
    14 // ==================================================
     24
     25use std::cell::UnsafeCell;
     26use std::mem::MaybeUninit;
     27use std::ops;
     28
     29pub struct InitializeCell<T> {
     30    inner: UnsafeCell<MaybeUninit<T>>,
     31}
     32
     33unsafe impl<T> Sync for InitializeCell<T> {}
     34
     35impl<T> InitializeCell<T> {
     36    pub const unsafe fn new_uninitialized() -> InitializeCell<T> {
     37          InitializeCell {
     38                inner: UnsafeCell::new(MaybeUninit::uninit()),
     39          }
     40    }
     41    pub const fn new(init: T) -> InitializeCell<T> {
     42          InitializeCell {
     43                inner: UnsafeCell::new(MaybeUninit::new(init)),
     44          }
     45    }
     46    pub unsafe fn init(&self, init: T) {
     47          (*self.inner.get()) = MaybeUninit::new(init);
     48    }
     49}
     50
     51impl<T> ops::Deref for InitializeCell<T> {
     52    type Target = T;
     53    fn deref(&self) -> &T {
     54          unsafe {
     55                &*(*self.inner.get()).as_ptr()
     56          }
     57    }
     58}
     59
     60static CLOCK_MODE: InitializeCell<bool> = unsafe { InitializeCell::new_uninitialized() };
     61static STOP_COUNT: InitializeCell<u64>  = unsafe { InitializeCell::new_uninitialized() };
     62static DURATION: InitializeCell<f64>    = unsafe { InitializeCell::new_uninitialized() };
     63static STOP         : AtomicBool = AtomicBool::new(false);
     64static THREADS_LEFT : AtomicU64  = AtomicU64 ::new(10);
     65
    1566struct Partner {
    1667        sem: sync::Semaphore,
     
    1869}
    1970
    20 async fn partner_main(idx: usize, others: Arc<Vec<Arc<Partner>>>, exp: Arc<bench::BenchData> ) -> u64 {
     71async fn partner_main(result: sync::oneshot::Sender<u64>, idx: usize, others: Arc<Vec<Arc<Partner>>> ) {
    2172        let this = &others[idx];
    2273        let mut count:u64 = 0;
     
    2677                count += 1;
    2778
    28                 if  exp.clock_mode && exp.stop.load(Ordering::Relaxed) { break; }
    29                 if !exp.clock_mode && count >= exp.stop_count { break; }
    30         }
    31 
    32         exp.threads_left.fetch_sub(1, Ordering::SeqCst);
    33         count
    34 }
    35 
    36 // ==================================================
     79                if  *CLOCK_MODE && STOP.load(Ordering::Relaxed) { break; }
     80                if !*CLOCK_MODE && count >= *STOP_COUNT { break; }
     81        }
     82
     83        THREADS_LEFT.fetch_sub(1, Ordering::SeqCst);
     84        result.send( count ).unwrap();
     85}
     86
     87fn prep(nthreads: usize, tthreads: usize) -> Vec<Arc<Partner>> {
     88        let mut thddata = Vec::with_capacity(tthreads);
     89        for i in 0..tthreads {
     90                let pi = (i + nthreads) % tthreads;
     91                thddata.push(Arc::new(Partner{
     92                        sem: sync::Semaphore::new(0),
     93                        next: pi,
     94                }));
     95        }
     96        return thddata;
     97}
     98
     99async fn wait(start: &Instant, is_tty: bool) {
     100        loop {
     101                time::sleep(Duration::from_micros(100000)).await;
     102                let delta = start.elapsed();
     103                if is_tty {
     104                        print!(" {:.1}\r", delta.as_secs_f32());
     105                        io::stdout().flush().unwrap();
     106                }
     107                if *CLOCK_MODE && delta >= Duration::from_secs_f64(*DURATION)  {
     108                        break;
     109                }
     110                else if !*CLOCK_MODE && THREADS_LEFT.load(Ordering::Relaxed) == 0 {
     111                        break;
     112                }
     113        }
     114}
     115
    37116fn main() {
    38117        let options = App::new("Cycle Tokio")
    39                 .args(&bench::args())
     118                .arg(Arg::with_name("duration")  .short("d").long("duration")  .takes_value(true).default_value("5").help("Duration of the experiments in seconds"))
     119                .arg(Arg::with_name("iterations").short("i").long("iterations").takes_value(true).conflicts_with("duration").help("Number of iterations of the experiments"))
     120                .arg(Arg::with_name("nthreads")  .short("t").long("nthreads")  .takes_value(true).default_value("1").help("Number of threads to use"))
     121                .arg(Arg::with_name("nprocs")    .short("p").long("nprocs")    .takes_value(true).default_value("1").help("Number of processors to use"))
    40122                .arg(Arg::with_name("ringsize")  .short("r").long("ringsize")  .takes_value(true).default_value("1").help("Number of threads in a cycle"))
    41123                .get_matches();
     
    45127        let nprocs    = options.value_of("nprocs").unwrap().parse::<usize>().unwrap();
    46128
    47         let tthreads = nthreads * ring_size;
    48         let exp = Arc::new(bench::BenchData::new(options, tthreads));
     129        if options.is_present("iterations") {
     130                unsafe{
     131                        CLOCK_MODE.init( false );
     132                        STOP_COUNT.init( options.value_of("iterations").unwrap().parse::<u64>().unwrap() );
     133                }
     134        }
     135        else {
     136                unsafe{
     137                        CLOCK_MODE.init(true);
     138                        DURATION  .init(options.value_of("duration").unwrap().parse::<f64>().unwrap());
     139                }
     140        }
    49141
    50142        let s = (1000000 as u64).to_formatted_string(&Locale::en);
    51143        assert_eq!(&s, "1,000,000");
    52144
    53         let thddata : Arc<Vec<Arc<Partner>>> = Arc::new(
    54                 (0..tthreads).map(|i| {
    55                         let pi = (i + nthreads) % tthreads;
    56                         Arc::new(Partner{
    57                                 sem: sync::Semaphore::new(0),
    58                                 next: pi,
    59                         })
    60                 }).collect()
    61         );
     145
     146        let tthreads = nthreads * ring_size;
     147        THREADS_LEFT.store(tthreads as u64, Ordering::SeqCst);
     148        let thddata = Arc::new(prep(nthreads, tthreads));
    62149
    63150        let mut global_counter :u64 = 0;
     
    70157
    71158        runtime.block_on(async {
    72                 let threads: Vec<_> = (0..tthreads).map(|i| {
    73                         tokio::spawn(partner_main(i, thddata.clone(), exp.clone()))
    74                 }).collect();
    75                 println!("Starting");
    76 
    77                 let start = Instant::now();
    78 
    79                 for i in 0..nthreads {
    80                         thddata[i].sem.add_permits(1);
    81                 }
    82 
    83                 duration = exp.wait(&start).await;
    84 
    85                 println!("\nDone");
    86 
    87                 for i in 0..tthreads {
    88                         thddata[i].sem.add_permits(1);
    89                 }
    90 
    91                 for t in threads {
    92                         global_counter += t.await.unwrap();
     159                let mut result  : Vec<sync::oneshot::Receiver::<u64>> = Vec::with_capacity(tthreads);
     160                {
     161                        let mut threads = Vec::with_capacity(tthreads);
     162                        for i in 0..tthreads {
     163                                let (s, r) = sync::oneshot::channel::<u64>();
     164                                result.push(r);
     165                                threads.push(tokio::spawn(partner_main(s, i, thddata.clone())));
     166                        }
     167                        println!("Starting");
     168
     169                        let is_tty = stdout_isatty();
     170                        let start = Instant::now();
     171
     172                        for i in 0..nthreads {
     173                                thddata[i].sem.add_permits(1);
     174                        }
     175
     176                        wait(&start, is_tty).await;
     177
     178                        STOP.store(true, Ordering::SeqCst);
     179                        duration = start.elapsed();
     180
     181                        println!("\nDone");
     182
     183                        for i in 0..tthreads {
     184                                thddata[i].sem.add_permits(1);
     185                        }
     186
     187                        for _ in 0..tthreads {
     188                                global_counter += result.pop().unwrap().await.unwrap();
     189                        }
    93190                }
    94191        });
  • benchmark/readyQ/locality.go

    r2b4daf2 r42f6e07  
    22
    33import (
    4         "context"
    54        "flag"
    65        "fmt"
    76        "math/rand"
    87        "os"
    9         "syscall"
    108        "sync/atomic"
    119        "time"
    12         "unsafe"
    13         "golang.org/x/sync/semaphore"
    1410        "golang.org/x/text/language"
    1511        "golang.org/x/text/message"
    1612)
    1713
    18 // ==================================================
    19 type MyData struct {
    20         _p1 [16]uint64 // padding
    21         ttid int
    22         id int
    23         data [] uint64
    24         _p2 [16]uint64 // padding
     14func handshake(stop chan struct {}, c chan [] uint64, data [] uint64, share bool) (bool, [] uint64) {
     15        var s [] uint64 = data
     16        if !share {
     17                s = nil
     18        }
     19
     20        // send the data
     21        select {
     22        case <- stop:
     23                return true, nil
     24        case c <- s:
     25        }
     26
     27        // get the new data chunk
     28        select {
     29        case <- stop:
     30                return true, nil
     31        case n := <- c:
     32                if share {
     33                        return false, n
     34                }
     35                return false, data
     36        }
    2537}
    2638
    27 func NewData(id int, size uint64) (*MyData) {
     39func local(result chan uint64, start chan struct{}, stop chan struct{}, size uint64, cnt uint64, channels []chan [] uint64, chan_cnt uint64, share bool) {
    2840        var data [] uint64
    2941        data = make([]uint64, size)
     
    3143                data[i] = 0
    3244        }
    33         return &MyData{[16]uint64{0}, syscall.Gettid(), id, data,[16]uint64{0}}
     45        count := uint64(0)
     46        <- start
     47        for true {
     48                for i := uint64(0); i < cnt; i++ {
     49                        data[rand.Uint64() % size] += 1
     50                }
     51
     52                i := rand.Uint64() % chan_cnt
     53                var closed bool
     54                closed, data = handshake(stop, channels[i], data, share)
     55                count += 1
     56
     57                if  closed { break }
     58                if !clock_mode && count >= stop_count { break }
     59        }
     60
     61        atomic.AddInt64(&threads_left, -1);
     62        result <- count
    3463}
    3564
    36 func (this * MyData) moved( ttid int ) (uint64) {
    37         if this.ttid == ttid {
    38                 return 0
    39         }
    40         this.ttid = ttid
    41         return 1
    42 }
     65func main() {
    4366
    44 func (this * MyData) access( idx uint64 ) {
    45         this.data[idx % uint64(len(this.data))] += 1
    46 }
    47 
    48 // ==================================================
    49 type MyCtx struct {
    50         _p1 [16]uint64 // padding
    51         s * semaphore.Weighted
    52         d unsafe.Pointer
    53         c context.Context
    54         ttid int
    55         id int
    56         _p2 [16]uint64 // padding
    57 }
    58 
    59 func NewCtx( data * MyData, id int ) (MyCtx) {
    60         r := MyCtx{[16]uint64{0},semaphore.NewWeighted(1), unsafe.Pointer(data), context.Background(), syscall.Gettid(), id,[16]uint64{0}}
    61         r.s.Acquire(context.Background(), 1)
    62         return r
    63 }
    64 
    65 func (this * MyCtx) moved( ttid int ) (uint64) {
    66         if this.ttid == ttid {
    67                 return 0
    68         }
    69         this.ttid = ttid
    70         return 1
    71 }
    72 
    73 // ==================================================
    74 // Atomic object where a single thread can wait
    75 // May exchanges data
    76 type Spot struct {
    77         _p1 [16]uint64 // padding
    78         ptr uintptr // atomic variable use fo MES
    79         id int      // id for debugging
    80         _p2 [16]uint64 // padding
    81 }
    82 
    83 // Main handshake of the code
    84 // Single seat, first thread arriving waits
    85 // Next threads unblocks current one and blocks in its place
    86 // if share == true, exchange data in the process
    87 func (this * Spot) put( ctx * MyCtx, data * MyData, share bool) (* MyData, bool) {
    88         new := uintptr(unsafe.Pointer(ctx))
    89         // old_d := ctx.d
    90 
    91         // Attempt to CAS our context into the seat
    92         var raw uintptr
    93         for true {
    94                 raw = this.ptr
    95                 if raw == uintptr(1) { // Seat is closed, return
    96                         return nil, true
    97                 }
    98                 if atomic.CompareAndSwapUintptr(&this.ptr, raw, new) {
    99                         break // We got the seat
    100                 }
    101         }
    102 
    103         // If we aren't the fist in, wake someone
    104         if raw != uintptr(0) {
    105                 var val *MyCtx
    106                 val = (*MyCtx)(unsafe.Pointer(raw))
    107 
    108                 // If we are sharing, give them our data
    109                 if share {
    110                         // fmt.Printf("[%d] - %d update %d: %p -> %p\n", this.id, ctx.id, val.id, val.d, data)
    111                         atomic.StorePointer(&val.d, unsafe.Pointer(data))
    112                 }
    113 
    114                 // Wake them up
    115                 // fmt.Printf("[%d] - %d release %d\n", this.id, ctx.id, val.id)
    116                 val.s.Release(1)
    117         }
    118 
    119         // fmt.Printf("[%d] - %d enter\n", this.id, ctx.id)
    120 
    121         // Block once on the seat
    122         ctx.s.Acquire(ctx.c, 1)
    123 
    124         // Someone woke us up, get the new data
    125         ret := (* MyData)(atomic.LoadPointer(&ctx.d))
    126         // fmt.Printf("[%d] - %d leave: %p -> %p\n", this.id, ctx.id, ret, old_d)
    127 
    128         return ret, false
    129 }
    130 
    131 // Shutdown the spot
    132 // Wake current thread and mark seat as closed
    133 func (this * Spot) release() {
    134         val := (*MyCtx)(unsafe.Pointer(atomic.SwapUintptr(&this.ptr, uintptr(1))))
    135         if val == nil {
    136                 return
    137         }
    138 
    139         // Someone was there, release them
    140         val.s.Release(1)
    141 }
    142 
    143 // ==================================================
    144 // Struct for result, Go doesn't support passing tuple in channels
    145 type Result struct {
    146         count uint64
    147         gmigs uint64
    148         dmigs uint64
    149 }
    150 
    151 func NewResult() (Result) {
    152         return Result{0, 0, 0}
    153 }
    154 
    155 // ==================================================
    156 // Random number generator, Go's native one is to slow and global
    157 func __xorshift64( state * uint64 ) (uint64) {
    158         x := *state
    159         x ^= x << 13
    160         x ^= x >> 7
    161         x ^= x << 17
    162         *state = x
    163         return x
    164 }
    165 
    166 // ==================================================
    167 // Do some work by accessing 'cnt' cells in the array
    168 func work(data * MyData, cnt uint64, state * uint64) {
    169         for i := uint64(0); i < cnt; i++ {
    170                 data.access(__xorshift64(state))
    171         }
    172 }
    173 
    174 // Main body of the threads
    175 func local(result chan Result, start chan struct{}, size uint64, cnt uint64, channels [] Spot, share bool, id int) {
    176         // Initialize some data
    177         state := rand.Uint64()    // RNG state
    178         data := NewData(id, size) // Starting piece of data
    179         ctx := NewCtx(data, id)   // Goroutine local context
    180 
    181         // Prepare results
    182         r := NewResult()
    183 
    184         // Wait for start
    185         <- start
    186 
    187         // Main loop
    188         for true {
    189                 // Touch our current data, write to invalidate remote cache lines
    190                 work(data, cnt, &state)
    191 
    192                 // Wait on a random spot
    193                 i := __xorshift64(&state) % uint64(len(channels))
    194                 var closed bool
    195                 data, closed = channels[i].put(&ctx, data, share)
    196 
    197                 // Check if the experiment is over
    198                 if closed { break }                                       // yes, spot was closed
    199                 if  clock_mode && atomic.LoadInt32(&stop) == 1 { break }  // yes, time's up
    200                 if !clock_mode && r.count >= stop_count { break }         // yes, iterations reached
    201 
    202                 // Check everything is consistent
    203                 if uint64(len(data.data)) != size { panic("Data has weird size") }
    204 
    205                 // write down progress and check migrations
    206                 ttid := syscall.Gettid()
    207                 r.count += 1
    208                 r.gmigs += ctx .moved(ttid)
    209                 r.dmigs += data.moved(ttid)
    210         }
    211 
    212         // Mark goroutine as done
    213         atomic.AddInt64(&threads_left, -1);
    214 
    215         // return result
    216         result <- r
    217 }
    218 
    219 // ==================================================
    220 // Program main
    221 func main() {
    222         // Benchmark specific command line arguments
    223         nspotsOpt    := flag.Int   ("n", 0    , "Number of spots where threads sleep (nthreads - nspots are active at the same time)")
    224         work_sizeOpt := flag.Uint64("w", 2    , "Size of the array for each threads, in words (64bit)")
    225         countOpt     := flag.Uint64("c", 2    , "Number of words to touch when working (random pick, cells can be picked more than once)")
     67        work_sizeOpt := flag.Uint64("w", 2    , "Number of words (uint64) per threads")
     68        countOpt     := flag.Uint64("c", 2    , "Number of words (uint64) to touch")
    22669        shareOpt     := flag.Bool  ("s", false, "Pass the work data to the next thread when blocking")
    22770
    228         // General benchmark initialization and deinitialization
    229         defer bench_init()()
     71        bench_init()
    23072
    231         // Eval command line arguments
    232         nspots:= *nspotsOpt
    23373        size  := *work_sizeOpt
    23474        cnt   := *countOpt
    23575        share := *shareOpt
    23676
    237         if nspots == 0 { nspots = nthreads - nprocs; }
    238 
    239         // Check params
    24077        if ! (nthreads > nprocs) {
    24178                fmt.Fprintf(os.Stderr, "Must have more threads than procs\n")
     
    24380        }
    24481
    245         // Make global data
    246         barrierStart := make(chan struct{})         // Barrier used at the start
    247         threads_left = int64(nthreads - nspots)                // Counter for active threads (not 'nthreads' because at all times 'nthreads - nprocs' are blocked)
    248         result  := make(chan Result)                // Channel for results
    249         channels := make([]Spot, nspots) // Number of spots
     82        barrierStart := make(chan struct{})
     83        barrierStop  := make(chan struct{})
     84        threads_left = int64(nthreads)
     85        result  := make(chan uint64)
     86        channels := make([]chan [] uint64, nthreads - nprocs)
    25087        for i := range channels {
    251                 channels[i] = Spot{[16]uint64{0},uintptr(0), i,[16]uint64{0}}     // init spots
     88                channels[i] = make(chan [] uint64, 1)
    25289        }
    25390
    254         // start the goroutines
    25591        for i := 0; i < nthreads; i++ {
    256                 go local(result, barrierStart, size, cnt, channels, share, i)
     92                go local(result, barrierStart, barrierStop, size, cnt, channels, uint64(nthreads - nprocs), share)
    25793        }
    25894        fmt.Printf("Starting\n");
    25995
    260         atomic.StoreInt32(&stop, 0)
    26196        start := time.Now()
    262         close(barrierStart) // release barrier
     97        close(barrierStart)
    26398
    264         wait(start, true);  // general benchmark wait
     99        wait(start, true);
    265100
    266         atomic.StoreInt32(&stop, 1)
     101        close(barrierStop)
    267102        end := time.Now()
    268103        delta := end.Sub(start)
     
    270105        fmt.Printf("\nDone\n")
    271106
    272         // release all the blocked threads
    273         for i := range channels {
    274                 channels[i].release()
     107        global_counter := uint64(0)
     108        for i := 0; i < nthreads; i++ {
     109                global_counter += <- result
    275110        }
    276111
    277         // Join and accumulate results
    278         results := NewResult()
    279         for i := 0; i < nthreads; i++ {
    280                 r := <- result
    281                 results.count += r.count
    282                 results.gmigs += r.gmigs
    283                 results.dmigs += r.dmigs
    284         }
    285 
    286         // Print with nice 's, i.e. 1'000'000 instead of 1000000
    287112        p := message.NewPrinter(language.English)
    288         p.Printf("Duration (s)           : %f\n", delta.Seconds());
     113        p.Printf("Duration (ms)          : %f\n", delta.Seconds());
    289114        p.Printf("Number of processors   : %d\n", nprocs);
    290115        p.Printf("Number of threads      : %d\n", nthreads);
    291116        p.Printf("Work size (64bit words): %d\n", size);
    292         p.Printf("Total Operations(ops)  : %15d\n", results.count)
    293         p.Printf("Total G Migrations     : %15d\n", results.gmigs)
    294         p.Printf("Total D Migrations     : %15d\n", results.dmigs)
    295         p.Printf("Ops per second         : %18.2f\n", float64(results.count) / delta.Seconds())
    296         p.Printf("ns per ops             : %18.2f\n", float64(delta.Nanoseconds()) / float64(results.count))
    297         p.Printf("Ops per threads        : %15d\n", results.count / uint64(nthreads))
    298         p.Printf("Ops per procs          : %15d\n", results.count / uint64(nprocs))
    299         p.Printf("Ops/sec/procs          : %18.2f\n", (float64(results.count) / float64(nprocs)) / delta.Seconds())
    300         p.Printf("ns per ops/procs       : %18.2f\n", float64(delta.Nanoseconds()) / (float64(results.count) / float64(nprocs)))
     117        p.Printf("Total Operations(ops)  : %15d\n", global_counter)
     118        p.Printf("Ops per second         : %18.2f\n", float64(global_counter) / delta.Seconds())
     119        p.Printf("ns per ops             : %18.2f\n", float64(delta.Nanoseconds()) / float64(global_counter))
     120        p.Printf("Ops per threads        : %15d\n", global_counter / uint64(nthreads))
     121        p.Printf("Ops per procs          : %15d\n", global_counter / uint64(nprocs))
     122        p.Printf("Ops/sec/procs          : %18.2f\n", (float64(global_counter) / float64(nprocs)) / delta.Seconds())
     123        p.Printf("ns per ops/procs       : %18.2f\n", float64(delta.Nanoseconds()) / (float64(global_counter) / float64(nprocs)))
    301124}
  • benchmark/readyQ/rq_bench.hfa

    r2b4daf2 r42f6e07  
    3939                } else if(stop_count > 0) { \
    4040                        clock_mode = false; \
    41                         printf("Running for %llu iterations\n", stop_count); \
     41                        printf("Running for %lu iterations\n", stop_count); \
    4242                } else { \
    4343                        duration = 5; clock_mode = true;\
  • benchmark/readyQ/rq_bench.hpp

    r2b4daf2 r42f6e07  
    9797}
    9898
    99 bool parse_truefalse(const char * arg, bool & value) {
    100         if(strcmp(arg, "true") == 0) {
    101                 value = true;
    102                 return true;
    103         }
    104 
    105         if(strcmp(arg, "false") == 0) {
    106                 value = false;
    107                 return true;
    108         }
    109 
    110         return false;
    111 }
    112 
    11399bool parse_settrue (const char *, bool & value ) {
    114100        value = true;
     
    240226        {
    241227                int idx = 0;
    242                 for(size_t i = 0; i < opt_count; i++) {
     228                for(int i = 0; i < opt_count; i++) {
    243229                        if(options[i].long_name) {
    244230                                optarr[idx].name = options[i].long_name;
     
    270256        {
    271257                int idx = 0;
    272                 for(size_t i = 0; i < opt_count; i++) {
     258                for(int i = 0; i < opt_count; i++) {
    273259                        optstring[idx] = options[i].short_name;
    274260                        idx++;
     
    293279                        case 'h':
    294280                                out = stdout;
    295                                 [[fallthrough]];
    296281                        case '?':
    297282                                usage(argv[0], options, opt_count, usage_msg, out);
    298283                        default:
    299                                 for(size_t i = 0; i < opt_count; i++) {
     284                                for(int i = 0; i < opt_count; i++) {
    300285                                        if(opt == options[i].short_name) {
    301286                                                const char * arg = optarg ? optarg : "";
    302                                                 if( arg[0] == '=' ) { arg++; }
    303287                                                bool success = options[i].parse_fun( arg, options[i].variable );
    304288                                                if(success) goto NEXT_ARG;
     
    335319        int width = 0;
    336320        {
    337                 for(size_t i = 0; i < opt_count; i++) {
     321                for(int i = 0; i < opt_count; i++) {
    338322                        if(options[i].long_name) {
    339323                                int w = strlen(options[i].long_name);
     
    354338        fprintf(out, "Usage:\n  %s %s\n", cmd, help);
    355339
    356         for(size_t i = 0; i < opt_count; i++) {
     340        for(int i = 0; i < opt_count; i++) {
    357341                printopt(out, width, max_width, options[i].short_name, options[i].long_name, options[i].help);
    358342        }
  • configure.ac

    r2b4daf2 r42f6e07  
    295295# Some of our makefile don't need to be distributed
    296296AM_CONDITIONAL([CFORALL_DISTRIBUTE], [test -e $TOP_SRCDIR/autogen.sh])
    297 AM_COND_IF([CFORALL_DISTRIBUTE], [
    298         AC_CONFIG_FILES([
     297AM_COND_IF([CFORALL_DISTRIBUTE],
     298        [AC_CONFIG_FILES([
    299299                longrun_tests/Makefile
    300300                benchmark/Makefile
     
    302302                tools/Makefile
    303303                tools/prettyprinter/Makefile
    304         ])
    305 
    306         AC_OUTPUT(benchmark/Cargo.toml)
    307 ])
     304                ])])
    308305
    309306AC_CONFIG_LINKS([tests/test.py:tests/test.py])
  • doc/theses/thierry_delisle_PhD/thesis/Makefile

    r2b4daf2 r42f6e07  
    2828        base \
    2929        empty \
    30         emptybit \
    31         emptytls \
    32         emptytree \
    33         fairness \
    3430        system \
    3531}
     
    7773        ${LaTeX} $<
    7874
    79 build/fairness.svg : fig/fairness.py | ${Build}
    80         python3 $< $@
    81 
    8275## Define the default recipes.
    8376
     
    9588        fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t
    9689
    97 %.pstex : build/%.svg | ${Build}
    98         inkscape -z -D --file=$< --export-eps=${Build}/$@ --export-latex
    99         mv ${Build}/$@_tex ${Build}/$@_t
    100         echo "sed -i 's/$@/${Build}/$@/g' ${Build}/$@_t"
    101         sed -i 's/$@/${Build}\/$@/g' ${Build}/$@_t
    102 
    10390## pstex with inverted colors
    10491%.dark.pstex : fig/%.fig Makefile | ${Build}
  • doc/theses/thierry_delisle_PhD/thesis/glossary.tex

    r2b4daf2 r42f6e07  
    77\newacronym{io}{I/O}{Input and Output}
    88\newacronym{numa}{NUMA}{Non-Uniform Memory Access}
    9 \newacronym{prng}{PRNG}{Pseudo Random Number Generator}
    109\newacronym{raii}{RAII}{Resource Acquisition Is Initialization}
    1110\newacronym{tls}{TLS}{Thread Local Storage}
  • doc/theses/thierry_delisle_PhD/thesis/local.bib

    r2b4daf2 r42f6e07  
    609609  note = "[Online; accessed 23-October-2020]"
    610610}
    611 
    612 @misc{wiki:lcg,
    613   author = "{Wikipedia contributors}",
    614   title = "Linear congruential generator --- {W}ikipedia{,} The Free Encyclopedia",
    615   year = "2020",
    616   url = "https://en.wikipedia.org/wiki/Linear_congruential_generator",
    617   note = "[Online; accessed 2-January-2021]"
    618 }
  • doc/theses/thierry_delisle_PhD/thesis/text/core.tex

    r2b4daf2 r42f6e07  
    11\chapter{Scheduling Core}\label{core}
    22
    3 Before discussing scheduling in general, where it is important to address systems that are changing states, this document discusses scheduling in a somewhat ideal scenerio, where the system has reached a steady state. For this purpose, a steady state is loosely defined as a state where there are always \glspl{thrd} ready to run and the system has the ressources necessary to accomplish the work, \eg, enough workers. In short, the system is neither overloaded nor underloaded.
     3Before discussing scheduling in general, where it is important to address systems that are changing states, this document discusses scheduling in a somewhat ideal scenerio, where the system has reached a steady state. For this purpose, a steady state is loosely defined as a state where there are always \glspl{thrd} ready to run and but the system has the ressources necessary to accomplish the work. In short, the system is neither overloaded or underloaded.
    44
    5 I believe it is important to discuss the steady state first because it is the easiest case to handle and, relatedly, the case in which the best performance is to be expected. As such, when the system is either overloaded or underloaded, a common approach is to try to adapt the system to the new load and return to the steady state, \eg, adding or removing workers. Flaws in the scheduling when the system is in the steady state can therefore to be pervasive in all states.
     5I believe it is important to discuss the steady state first because it is the easiest case to handle and, relatedly, the case in which the best performance is to be expected. As such, when the system is either overloaded or underloaded, a common approach is to try to adapt the system to the new load and return to the steady state. Flaws in the scheduling in the steady state tend therefore to be pervasive in all states.
    66
    77\section{Design Goals}
    8 As with most of the design decisions behind \CFA, an important goal is to match the expectation of the programmer, according to their probable mental model. To match these expectations, the design must offer the programmers sufficient guarantees so that, as long as they respect the mental model, the system will also respect this model.
     8As with most of the design decisions behind \CFA, the main goal is to match the expectation of the programmer, according to their probable mental model. To match these expectations, the design must offer the programmers sufficient guarantees so that, as long as the programmer respects the mental model, the system will also respect this model.
    99
    1010For threading, a simple and common mental model is the ``Ideal multi-tasking CPU'' :
     
    1616Applied to threads, this model states that every ready \gls{thrd} immediately runs in parallel with all other ready \glspl{thrd}. While a strict implementation of this model is not feasible, programmers still have expectations about scheduling that come from this model.
    1717
    18 In general, the expectation at the center of this model is that ready \glspl{thrd} do not interfere with eachother but simply share the hardware. This makes it easier to reason about threading because ready \glspl{thrd} can be taken in isolation and the effect of the scheduler can be virtually ignored. This expectation of \gls{thrd} independence means the scheduler is expected to offer two guarantees:
     18In general, the expectation at the center of this model is that ready \glspl{thrd} do not interfere with eachother but simply share the hardware. This makes it easier to reason about threading because ready \glspl{thrd} can be taken in isolation and the effect of the scheduler can be virtually ignored. This expectation of \gls{thrd} independence means the scheduler is expected to offer 2 guarantees:
    1919\begin{enumerate}
    2020        \item A fairness guarantee: a \gls{thrd} that is ready to run will not be prevented to do so by another thread.
     
    2424It is important to note that these guarantees are expected only up to a point. \Glspl{thrd} that are ready to run should not be prevented to do so, but they still need to share a limited amount of hardware. Therefore, the guarantee is considered respected if a \gls{thrd} gets access to a \emph{fair share} of the hardware, even if that share is very small.
    2525
    26 Similarly the performance guarantee, the lack of interferance between threads, is only relevant up to a point. Ideally the cost of running and blocking would be constant regardless of contention, but the guarantee is considered satisfied if the cost is not \emph{too high} with or without contention. How much is an acceptable cost is obviously highly variable. For this document the performance experimentation will attempt to show that the cost of scheduling is at worst equivalent to existing algorithms used in popular languages. This demonstration can be made by comparing application built in \CFA to applications built with other languages or other models. Recall from a few paragraphs ago that the expectation of programmers is that the impact of the scheduler can be ignored. Therefore, if the cost of scheduling is equivalent or lower to other popular languages, I will consider the guarantee achieved.
     26Similarly the performance guarantee, the lack of interferance between threads is only relevant op to a point. Ideally the cost of running and blocking would be constant regardless of contention, but the guarantee is considered satisfied if the cost is not \emph{too high} with or without contention. How much is an acceptable cost is obviously highly variable. For this document the performance experimentation will attempt to show that the cost of scheduling is not a major factor in application performance. This demonstration can be made by comparing application built in \CFA to applications built with other languages or other models. If the performance of an application built in \CFA is not meaningfully different than one built with a different runtime, then the scheduler has a negigeable impact on performance, \ie its impact can be ignored. Recall from a few paragraphs ago that the expectation of programmers is that the impact of the scheduler can be ignored. Therefore, if the cost of scheduling is not a significant portion of the runtime of several different application, I will consider the guarantee achieved.
    2727
    28 More precisely the scheduler should be:
    29 \begin{itemize}
    30         \item As fast as other schedulers that are less fair.
    31         \item Faster than other scheduler that have equal or better fairness.
    32 \end{itemize}
    33 
    34 \subsection{Fairness vs Scheduler Locality}
    35 An important performance factor in modern architectures is cache locality. Waiting for data not present in the cache can have a major impact on performance, and having multiple \glspl{hthrd} writing to the same cache lines can lead to cache lines that need to be waited on again. It is therefore preferable to divide the data among each \gls{hthrd}\footnote{This can be an explicit division up front or using data structures where different \glspl{hthrd} are naturally routed to different cache lines.}.
    36 
    37 For a scheduler, having good locality\footnote{This section discusses \emph{internal} locality, \ie, the locality of the data used by the scheduler. \emph{External locality}, \ie, how the data used by the application is affected by scheduling, is a much more complicated subject and will be discussed in the chapters on evaluation.}, \ie, having the data be local to each \gls{hthrd}, generally conflicts with fairness. Indeed, good locality often requires avoiding the movement of cache lines, while fairness requires dynamically moving \gls{thrd}, and as a consequence cache lines, to \glspl{hthrd} that are currently more appropriate.
    38 
    39 However, I claim that in practice it is possible to strike a balance between fairness and performance because the need for these do not necessarily overlap temporaly. Figure~\ref{fig:fair} shows an visual representation of this behaviour. As mentionned, a little bit of unfairness can be acceptable, therefore it can be desirable to have an algorithm that prioritizes cache locality as long as no threads is left behind for too long.
    40 
    41 \begin{figure}
    42         \begin{center}
    43                 \input{fairness.pstex_t}
    44         \end{center}
    45         \caption{Fairness vs Locality}
    46         \label{fig:fair}
    47         Rule of thumb graph: Importance of Fairness and Locality while a ready \gls{thrd} waits run.
    48         As the time a ready \gls{thrd} waits increases, ``Ready Time'', the chances that its data is still in cache decreases. At the same time, the need for fairness increases since other \glspl{thrd} may have the chance to run many times, breaking the fairness model mentionned above. Since the actual values and curves of this graph can be highly variable, the graph is left intentionally fuzzy and innacurate.
    49 \end{figure}
     28\todo{This paragraph should be moved later}
     29% The next step is then to decide what is considered a \emph{fair share}, \ie what metric is used to measure fairness. Since \CFA is intended to allow numerous short lived threads, I decided to avoid total CPU time as the measure of fairness. Total CPU time inherently favors new \glspl{thrd} over older ones which isn't necessarily a good thing. Instead, fairness is measured in terms of opportunities to run. This metric is more appropriate for a mix of short and long lived \glspl{thrd}.
    5030
    5131\section{Design}
    52 A naive strictly \glsxtrshort{fifo} ready-queue does not offer sufficient performance. As shown in the evaluation sections, most production schedulers scale when adding multiple \glspl{hthrd} and that is not possible with a single point of contention. Therefore it is vital to shard the ready-queue so that multiple \glspl{hthrd} can access the ready-queue without performance degradation.
     32While avoiding the pitfalls of Feedback Scheduling is fairly easy, scheduling does not innately require feedback, avoiding prioritization of \glspl{thrd} is more difficult because of implicitly priorities, see Subsection~\ref{priority}. A strictly \glsxtrshort{fifo} rea
    5333
    54 \subsection{Sharding} \label{sec:sharding}
    55 An interesting approach to sharding a queue is presented in \cit{Trevors paper}. This algorithm represents a queue with relaxed \glsxtrshort{fifo} guarantee using an array of strictly \glsxtrshort{fifo} sublists as shown in Figure~\ref{fig:base}. Each cell of the array contains a linked-list with a lock and each node in these list is marked with a timestamp indicating when they were added to the list. Push operations are done by picking a random cell and attempting to push to its list. If the cell is already locked, the operation is simply retried on a new cell until a lock is acquired. Pop operations are done in a similar fashion except two random cells are picked. If both cells are not already locked and both cells contain non-empty lists, the operation pops the node with the oldest timestamp. If only one of the cell is unlocked and non-empty, the operation pops from that cell. If both cells are either locked or empty, the operation picks two new cells and tries again.
     34\subsection{Sharding}
    5635
    5736\begin{figure}
     
    6645
    6746\subsection{Finding threads}
    68 Once threads have been distributed onto multiple queues, indentifying which queues are empty and which are not can become a problem. Indeed, if the number of \glspl{thrd} does not far exceed the number of queues, it is probable that several of these queues are empty. Figure~\ref{fig:empty} shows an example with 2 \glspl{thrd} running on 8 queues, where the chances of getting an empty queue is 75\% per pick, meaning two random picks yield a \gls{thrd} only half the time.
     47Once threads have been distributed onto multiple queues, indentifying which queues are empty and which aren't can become a problem.
     48Indeed, if the number of \glspl{thrd} does not far exceed the number of queues, it is probable that several of these queues are empty.
     49Figure~\ref{fig:empty} shows an example with 2 \glspl{thrd} running on 8 queues, where the chances of getting an empty queue is 75\% per pick, meaning two random picks yield a \gls{thrd} only half the time.
    6950
    7051
     
    8061This can lead to performance problems since picks that do not yield a \gls{thrd} are not useful and do not necessarily help make more informed guesses.
    8162
    82 Solutions to this problem can take many forms, but they ultimately all have to encode where the threads are in some form. My results show that the density and locality of this encoding is generally the dominating factor in these scheme. Classic solutions to this problem use one of three techniques to encode the information:
     63Solutions to this problem can take many forms, but they ultimately all have to encode where the threads are in some form. My results show that the density and locality of this encoding is generally the dominating factor in these scheme.
    8364
    84 \begin{figure}
    85         \begin{center}
    86                 {\resizebox{0.73\textwidth}{!}{\input{emptybit.pstex_t}}}
    87         \end{center}
    88         \vspace*{-5pt}
    89         \caption{Underloaded queue with added bitmask to indicate which array cells have items.}
    90         \label{fig:emptybit}
    91         \begin{center}
    92                 {\resizebox{0.73\textwidth}{!}{\input{emptytree.pstex_t}}}
    93         \end{center}
    94         \vspace*{-5pt}
    95         \caption{Underloaded queue with added binary search tree indicate which array cells have items.}
    96         \label{fig:emptytree}
    97         \begin{center}
    98                 {\resizebox{0.9\textwidth}{!}{\input{emptytls.pstex_t}}}
    99         \end{center}
    100         \vspace*{-5pt}
    101         \caption{Underloaded queue with added per processor bitmask to indicate which array cells have items.}
    102         \label{fig:emptytls}
    103 \end{figure}
    104 
    105 \paragraph{Dense Information} Figure~\ref{fig:emptybit} shows a dense bitmask to identify which inner queues are currently in use. This approach means processors can often find \glspl{thrd} in constant time, regardless of how many underlying queues are empty. Furthermore, modern x86 CPUs have extended bit manipulation instructions (BMI2) that allow using the bitmask with very little overhead compared to the randomized selection approach for a filled ready queue, offering good performance even in cases with many empty inner queues. However, this technique has its limits: with a single word\footnote{Word refers here to however many bits can be written atomically.} bitmask, the total number of underlying queues in the ready queue is limited to the number of bits in the word. With a multi-word bitmask, this maximum limit can be increased arbitrarily, but the look-up will nolonger be constant time. Finally, a dense bitmap, either single or multi-word, causes additional contention problems which reduces performance because of cache misses after updates. This central update bottleneck also means the information in the bitmask is more often stale before a processor can use it to find an item, \ie mask read says there are available \glspl{thrd} but none on queue.
    106 
    107 \paragraph{Sparse Information} Figure~\ref{fig:emptytree} shows an approach using a hierarchical tree data-structure to reduce contention and has been shown to work in similar cases~\cite{ellen2007snzi}. However, this approach may lead to poorer performance due to the inherent pointer chasing cost while still allowing more contention on the nodes of the tree if the tree is not deep enough.
    108 
    109 \paragraph{Local Information} Figure~\ref{fig:emptytls} shows an approach using dense information, similar to the bitmap, but have each thread keep its own independent copy of it. While this approach can offer good scalability \emph{and} low latency, the liveliness and discovery of the information can become a problem. This case is made worst in systems with few processors where even blind random picks can find \glspl{thrd} in few tries.
    110 
    111 I built a prototype of these approach and none of these techniques offer satisfying performance when few threads are present. All of these approach hit the same 2 problems. First, blindly picking two sub-queues is very fast which means that any improvement to the hit rate can easily be countered by a slow-down in look-up speed. Second, the array is already as sharded as is needed to avoid contention bottlenecks, so any denser data structure will tend to become a bottleneck. In all cases, these factors meant that the best cases scenerio, many threads, would get worst throughput and the worst case scenario, few threads, would get a better hit rate, but an equivalent throughput. As a result I tried an entirely different approach.
    112 
    113 \subsection{Dynamic Entropy}\cit{https://xkcd.com/2318/}
    114 In the worst case scenario there are few \glspl{thrd} ready to run, or more accuratly given $P$ \glspl{proc}, $T$ \glspl{thrd} and $\epsilon$, as usual, a very small number, in this case $\epsilon \ll P$, we have $T = P + \epsilon$. An important thing to note is that in this case, fairness is effectively irrelevant. Indeed, this case is close to \emph{actually matching} the model of the ``Ideal multi-tasking CPU'' presented in this chapter\footnote{For simplicity, this assumes there is a one-to-one match between \glspl{proc} and \glspl{hthrd}.}. Therefore, in this context it is possible to use a purely internal locality based approach and still meet the fairness requirements. This approach would simply have each \gls{proc} running a single \gls{thrd} repeatedly. Or from the shared ready-queue viewpoint, each \gls{proc} would push to a given sub-queue and then pop from the \emph{same} subqueue. Ideally, the scheduler would achieve this without affecting the fairness guarantees in cases where $T \gg P$.
    115 
    116 To achieve this, I use a communication channel I have not mentionned yet and which I believe I use in a novel way : the \glsxtrshort{prng}. If the scheduler has a \glsxtrshort{prng} instance per \gls{proc} exclusively used for scheduling, its seed effectively encodes a list of all the accessed subqueues, from the latest to the oldest. The only requirement to achieve this is to be able to ``replay'' the \glsxtrshort{prng} backwards. As it turns out, this is an entirely reasonnable requirement and there already exist \glsxtrshort{prng}s that are fast, compact \emph{and} can be run forward and backwards. Linear congruential generators\cite{wiki:lcg} are an example of \glsxtrshort{prng}s that match these requirements.
    117 
    118 The algorithm works as follows :
    119 \begin{itemize}
    120         \item Each \gls{proc} has two \glsxtrshort{prng} instances, $F$ and $B$.
    121         \item Push and Pop operations happen as mentionned in Section~\ref{sec:sharding} with the following exceptions:
    122         \begin{itemize}
    123                 \item Push operations use $F$ going forward on each try and on success $F$ is copied into $B$.
    124                 \item Pop operations use $B$ going backwards on each try.
    125         \end{itemize}
    126 \end{itemize}
    127 
    128 The main benefit of this technique is that it basically repects the desired properties of Figure~\ref{fig:fair}. When looking for work, \glspl{proc} will look first at the last cells they pushed to, if any, and then move backwards through the cells. As the \glspl{proc} continue looking for work, $F$ moves back and $B$ stays in place. As a result the relation between the two becomes weaker, which means that the probablisitic fairness of the algorithm reverts to normal. Chapter~\ref{proofs} discusses more formally the fairness guarantees of this algorithm.
    129 
    130 \section{Details}
     65\paragraph{Dense Information}
  • doc/theses/thierry_delisle_PhD/thesis/text/existing.tex

    r2b4daf2 r42f6e07  
    4242\paragraph{Task Placement} Since modern computers rely heavily on cache hierarchies\cit{Do I need a citation for this}, migrating tasks from one core to another can be .  \cite{DBLP:journals/tpds/SquillanteL93}
    4343
    44 \todo{The survey is not great on this subject}
     44\TODO{The survey is not great on this subject}
    4545
    4646\paragraph{Complex Machine Architecture} Another aspect that has been looked at is how well Work Stealing is applicable to different machine architectures.
  • libcfa/src/Makefile.am

    r2b4daf2 r42f6e07  
    5858        concurrency/iofwd.hfa \
    5959        containers/list.hfa \
    60         containers/stackLockFree.hfa \
    61         vec/vec.hfa \
    62         vec/vec2.hfa \
    63         vec/vec3.hfa \
    64         vec/vec4.hfa
     60        containers/stackLockFree.hfa
    6561
    6662inst_headers_src = \
     
    9894        concurrency/clib/cfathread.h \
    9995        concurrency/invoke.h \
    100         concurrency/future.hfa \
    10196        concurrency/kernel/fwd.hfa
    10297
  • libcfa/src/bits/collection.hfa

    r2b4daf2 r42f6e07  
    11#pragma once
    2 #include <stdio.h> // REMOVE THIS AFTER DEBUGGING
    3 
    42
    53struct Colable {
    6         struct Colable * next;                                                                          // next node in the list
     4        Colable * next;                                                                         // next node in the list
    75        // invariant: (next != 0) <=> listed()
    86};
    9 #ifdef __cforall
    10 static inline {
     7
     8inline {
    119        // PUBLIC
    1210
     
    3028        }
    3129
    32         // // wrappers to make Collection have T
    33         // forall( dtype T ) {
    34         //      T *& Next( T * n ) {
    35         //              return (T *)Next( (Colable *)n );
    36         //      }
    37         // } // distribution
     30        // wrappers to make Collection have T
     31        forall( dtype T ) {
     32                T *& Next( T * n ) {
     33                        return (T *)Next( (Colable *)n );
     34                }
     35
     36                bool listed( T * n ) {
     37                        return Next( (Colable *)n ) != 0p;
     38                }
     39        } // distribution
    3840} // distribution
    3941
    40 forall( dtype T | { T *& Next ( T * ); } ) {
    41         bool listed( T * n ) {
    42                 return Next( n ) != 0p;
    43         }
    44 }
    4542
    4643struct Collection {
     
    4845};
    4946
    50 static inline {
     47inline {
    5148        // class invariant: root == 0 & empty() | *root in *this
    5249        void ?{}( Collection &, const Collection & ) = void; // no copy
     
    6865
    6966struct ColIter {
    70         void * curr;                                                                            // element returned by |
     67        void * curr;                                                                            // element to be returned by >>
    7168};
    7269
    73 static inline {
     70inline {
    7471        void ?{}( ColIter & colIter ) with( colIter ) {
    7572                curr = 0p;
     
    8279        } // distribution
    8380} // distribution
    84 #endif
  • libcfa/src/bits/containers.hfa

    r2b4daf2 r42f6e07  
    3636        #define __small_array_t(T) __small_array(T)
    3737#else
    38         #define __small_array_t(T) __small_array
     38        #define __small_array_t(T) struct __small_array
    3939#endif
    4040
  • libcfa/src/bits/defs.hfa

    r2b4daf2 r42f6e07  
    2929#define __cfa_anonymous_object(x) inline struct x
    3030#else
    31 #define __cfa_anonymous_object(x) struct x __cfa_anonymous_object
     31#define __cfa_anonymous_object(x) x __cfa_anonymous_object
    3232#endif
    3333
  • libcfa/src/bits/locks.hfa

    r2b4daf2 r42f6e07  
    283283                void ^?{}(future_t &) {}
    284284
    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 
    290285                // check if the future is available
    291286                bool available( future_t & this ) {
     
    345340
    346341                // 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
     342                void abandon( future_t & this ) {
    351343                        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;
    355344
    356345                        // got == 2p: the future is ready but the context hasn't fully been consumed
     
    358347                        if( got == 2p ) {
    359348                                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;
     349                        }
     350                        return;
    367351                }
    368352
  • libcfa/src/bits/queue.hfa

    r2b4daf2 r42f6e07  
    33#include "bits/collection.hfa"
    44
    5 // A Queue(T) is a Collection(T) defining the ordering that nodes are returned by drop() in the same order from those
    6 // added by add(). T must be a public descendant of uColable.
    7 
    8 // The implementation is a typical singly-linked list, except the next field of the last element points to itself
    9 // instead of being null.
    10 
    11 forall( dtype T | { T *& Next ( T * ); } ) {
     5forall( dtype T ) {
    126        struct Queue {
    137                inline Collection;                                                              // Plan 9 inheritance
     
    4034                } // post: n == tail() & succ(n) == 0 | n != tail() & *succ(n) in *q
    4135
    42                 T & addHead( Queue(T) & q, T & n ) with( q ) {
     36                void addHead( Queue(T) & q, T & n ) with( q ) {
    4337                        #ifdef __CFA_DEBUG__
    4438                        if ( listed( &n ) ) abort( "(Queue &)%p.addHead( %p ) : Node is already on another list.", &q, &n );
     
    5145                                Next( &n ) = &n;                                                // last node points to itself
    5246                        }
    53                         return n;
    5447                }
    5548
    56                 T & addTail( Queue(T) & q, T & n ) with( q ) {
     49                void addTail( Queue(T) & q, T & n ) with( q ) {
    5750                        #ifdef __CFA_DEBUG__
    5851                        if ( listed( &n ) ) abort( "(Queue &)%p.addTail( %p ) : Node is already on another list.", &q, &n );
     
    6255                        last = &n;
    6356                        Next( &n ) = &n;                                                        // last node points to itself
    64                         return n;
    6557                }
    6658
    67                 T & add( Queue(T) & q, T & n ) with( q ) {
    68                         return addTail( q, n );
     59                void add( Queue(T) & q, T & n ) with( q ) {
     60                        addTail( q, n );
    6961                }
    7062
     
    7264                        T & t = head( q );
    7365                        if ( root ) {
    74                                 root = Next( (T *)root );
     66                                root = Next( root );
    7567                                if ( &head( q ) == &t ) {
    7668                                        root = last = 0p;                                       // only one element
     
    8577                }
    8678
    87                 T & remove( Queue(T) & q, T & n ) with( q ) {   // O(n)
     79                void remove( Queue(T) & q, T & n ) with( q ) {  // O(n)
    8880                        #ifdef __CFA_DEBUG__
    8981                        if ( ! listed( (Colable &)n ) ) abort( "(Queue &)%p.remove( %p ) : Node is not on a list.", &q, &n );
     
    111103                                curr = Next( curr );
    112104                        }
    113                         return n;
    114105                } // post: ! listed( n )
    115106
    116                 T & dropTail( Queue(T) & q ) with( q ) {                // O(n)
     107                T & dropTail( Queue(T) & q ) with( q ) { // O(n)
    117108                        T & n = tail( q );
    118109                        return &n ? remove( q, n ), n : *0p;
     
    151142} // distribution
    152143
    153 forall( dtype T | { T *& Next ( T * ); } ) {
     144forall( dtype T ) {
    154145        struct QueueIter {
    155146                inline ColIter;                                                                 // Plan 9 inheritance
     
    161152                } // post: curr == 0p
    162153
    163                 // create an iterator active in queue q
     154                // create an iterator active in Queue q
    164155                void ?{}( QueueIter(T) & qi, Queue(T) & q ) with( qi ) {
    165156                        curr = &head( q );
     
    170161                } // post: curr = {e in q}
    171162
    172                 // make existing iterator active in queue q
     163                // make existing iterator active in Queue q
    173164                void over( QueueIter(T) & qi, Queue(T) & q ) with( qi ) {
    174165                        curr = &head( q );
    175166                } // post: curr = {e in q}
    176167
    177                 bool ?|?( QueueIter(T) & qi, T && tp ) with( qi ) {
     168                bool ?>>?( QueueIter(T) & qi, T && tp ) with( qi ) {
    178169                        if ( curr ) {
    179170                                &tp = Curr( qi );
     
    183174                        return &tp != 0p;
    184175                }
    185                 // post: elts == null & !operator|(tp) | elts != null & *tp' in elts & elts' == elts - *tp & operator|(tp)
     176                // post: elts == null & !operator>>(tp) | elts != null & *tp' in elts & elts' == elts - *tp & operator>>(tp)
    186177        } // distribution
    187178} // distribution
  • libcfa/src/bits/sequence.hfa

    r2b4daf2 r42f6e07  
    22
    33#include "bits/collection.hfa"
    4 #include "bits/defs.hfa"
    54
    65struct Seqable {
    7         __cfa_anonymous_object(Colable);
    8         struct Seqable * back;                                                                          // pointer to previous node in the list
     6        inline Colable;
     7        Seqable * back;                                                                         // pointer to previous node in the list
    98};
    109
    11 #ifdef __cforall
    12 static inline {
     10inline {
    1311        // PUBLIC
    1412
     
    2826        }
    2927
    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
     28        // wrappers to make Collection have T
     29        forall( dtype T ) {
     30                T *& Back( T * n ) {
     31                        return (T *)Back( (Seqable *)n );
     32                }
     33        } // distribution
    3634} // distribution
    3735
    38 
    39 // A Sequence(T) is a Collection(T) defining the ordering of a uStack and uQueue, and to insert and remove elements
    40 // anywhere in the sequence. T must be a public descendant of uSeqable.
    41 
    42 // The implementation is a typical doubly-linked list, except the next field of the last node points at the first node
    43 // and the back field of the last node points at the first node (circular).
    44 
    45 forall( dtype T | { T *& Back ( T * ); T *& Next ( T * ); } ) {
     36forall( dtype T ) {
    4637        struct Sequence {
    4738                inline Collection;                                                              // Plan 9 inheritance
    4839        };
    4940
    50         static inline {
     41        inline {
    5142                // wrappers to make Collection have T
    5243                T & head( Sequence(T) & s ) with( s ) {
     
    5950                void ?{}( Sequence(T) & s ) with( s ) {
    6051                        ((Collection &)s){};
    61                 }       // post: isEmpty()
    62 
    63                 // Return a pointer to the last sequence element, without removing it.
     52                }       // post: isEmpty().
     53
     54                // Return a pointer to the last sequence element, without removing it. 
    6455                T & tail( Sequence(T) & s ) with( s ) {
    6556                        return root ? (T &)*Back( &head( s ) ) : *0p;
     
    7465                } // post: n == tail() & succ(n) == 0 | n != tail() & *succ(n) in *s
    7566
    76                 // Return a pointer to the element before *n, or 0p if list empty.
     67                // Return a pointer to the element before *n, or 0p if there isn't one.
    7768                T * pred( Sequence(T) & s, T * n ) with( s ) {  // pre: *n in *s
    7869                        #ifdef __CFA_DEBUG__
     
    8071                        #endif // __CFA_DEBUG__
    8172                        return n == &head( s ) ? 0p : Back( n );
    82                 } // post: n == head() & head(n) == 0 | n != head() & *pred(n) in *s
    83 
    84 
    85                 // Insert *n into the sequence before *bef, or at the end if bef == 0p.
    86                 T & insertBef( Sequence(T) & s, T & n, T & bef ) with( s ) { // pre: !n->listed() & *bef in *s
     73                }       // post: n == head() & head(n) == 0 | n != head() & *pred(n) in *s
     74
     75
     76                // Insert *n into the sequence before *bef, or at the end if bef == 0.
     77                void insertBef( Sequence(T) & s, T & n, T & bef ) with( s ) { // pre: !n->listed() & *bef in *s
    8778                        #ifdef __CFA_DEBUG__
    8879                        if ( listed( &n ) ) abort( "(Sequence &)%p.insertBef( %p, %p ) : Node is already on another list.", &s, n, &bef );
     
    112103                                Next( Back( &n ) ) = &n;
    113104                        } // if
    114                         return n;
    115105                }       // post: n->listed() & *n in *s & succ(n) == bef
    116106
    117107
    118108                // Insert *n into the sequence after *aft, or at the beginning if aft == 0.
    119                 T & insertAft( Sequence(T) & s, T & aft, T & n ) with( s ) {    // pre: !n->listed() & *aft in *s
     109                void insertAft( Sequence(T) & s, T & aft, T & n ) with( s ) {   // pre: !n->listed() & *aft in *s
    120110                        #ifdef __CFA_DEBUG__
    121111                        if ( listed( &n ) ) abort( "(Sequence &)%p.insertAft( %p, %p ) : Node is already on another list.", &s, &aft, &n );
     
    143133                                Next( &aft ) = &n;
    144134                        } // if
    145                         return n;
    146                 } // post: n->listed() & *n in *s & succ(n) == bef
     135                }         // post: n->listed() & *n in *s & succ(n) == bef
    147136               
    148137                // pre: n->listed() & *n in *s
    149                 T & remove( Sequence(T) & s, T & n ) with( s ) { // O(1)
     138                void remove( Sequence(T) & s, T & n ) with( s ) { // O(1)
    150139                        #ifdef __CFA_DEBUG__
    151140                        if ( ! listed( &n ) ) abort( "(Sequence &)%p.remove( %p ) : Node is not on a list.", &s, &n );
     
    158147                        Next( Back( &n ) ) = Next( &n );
    159148                        Next( &n ) = Back( &n ) = 0p;
    160                         return n;
    161                 } // post: !n->listed()
     149                }                                                       // post: !n->listed().
    162150
    163151                // Add an element to the head of the sequence.
    164                 T & addHead( Sequence(T) & s, T & n ) {                 // pre: !n->listed(); post: n->listed() & head() == n
    165                         return insertAft( s, *0p, n );
    166                 }
    167 
     152                void addHead( Sequence(T) & s, T & n ) {                // pre: !n->listed(); post: n->listed() & head() == n
     153                        insertAft( s, *0p, n );
     154                }
    168155                // Add an element to the tail of the sequence.
    169                 T & addTail( Sequence(T) & s, T & n ) {                 // pre: !n->listed(); post: n->listed() & head() == n
    170                         return insertBef( s, n, *0p );
    171                 }
    172 
     156                void addTail( Sequence(T) & s, T & n ) {                // pre: !n->listed(); post: n->listed() & head() == n
     157                        insertBef( s, n, *0p );
     158                }
    173159                // Add an element to the tail of the sequence.
    174                 T & add( Sequence(T) & s, T & n ) {                             // pre: !n->listed(); post: n->listed() & head() == n
    175                         return addTail( s, n );
    176                 }
    177 
     160                void add( Sequence(T) & s, T & n ) {                    // pre: !n->listed(); post: n->listed() & head() == n
     161                        addTail( s, n );
     162                }
    178163                // Remove and return the head element in the sequence.
    179164                T & dropHead( Sequence(T) & s ) {
     
    181166                        return &n ? remove( s, n ), n : *0p;
    182167                }
    183 
    184168                // Remove and return the head element in the sequence.
    185169                T & drop( Sequence(T) & s ) {
    186170                        return dropHead( s );
    187171                }
    188 
    189172                // Remove and return the tail element in the sequence.
    190173                T & dropTail( Sequence(T) & s ) {
     
    201184                                T * toEnd = Back( &head( s ) );
    202185                                T * fromEnd = Back( &head( from ) );
    203                                 Back( (T *)root ) = fromEnd;
     186                                Back( root ) = fromEnd;
    204187                                Next( fromEnd ) = &head( s );
    205                                 Back( (T *)from.root ) = toEnd;
     188                                Back( from.root ) = toEnd;
    206189                                Next( toEnd ) = &head( from );
    207190                        } // if
     
    231214} // distribution
    232215
    233 forall( dtype T | { T *& Back ( T * ); T *& Next ( T * ); } ) {
     216forall( dtype T ) {
    234217        // SeqIter(T) is used to iterate over a Sequence(T) in head-to-tail order.
    235218        struct SeqIter {
     
    241224        };
    242225
    243         static inline {
     226        inline {
    244227                void ?{}( SeqIter(T) & si ) with( si ) {
    245228                        ((ColIter &)si){};
    246229                        seq = 0p;
    247                 } // post: elts = null
    248 
    249                 // Create a iterator active in sequence s.
     230                } // post: elts = null.
     231
    250232                void ?{}( SeqIter(T) & si, Sequence(T) & s ) with( si ) {
    251233                        ((ColIter &)si){};
    252234                        seq = &s;
    253235                        curr = &head( s );
    254                 } // post: elts = null
     236                } // post: elts = null.
    255237
    256238                void ?{}( SeqIter(T) & si, Sequence(T) & s, T & start ) with( si ) {
     
    258240                        seq = &s;
    259241                        curr = &start;
    260                 } // post: elts = null
    261 
    262                 // Make the iterator active in sequence s.
     242                } // post: elts = null.
     243
    263244                void over( SeqIter(T) & si, Sequence(T) & s ) with( si ) {
    264245                        seq = &s;
    265246                        curr = &head( s );
    266                 } // post: elts = {e in s}
    267 
    268                 bool ?|?( SeqIter(T) & si, T && tp ) with( si ) {
     247                } // post: elts = {e in s}.
     248
     249                bool ?>>?( SeqIter(T) & si, T && tp ) with( si ) {
    269250                        if ( curr ) {
    270251                                &tp = Curr( si );
     
    284265        };
    285266
    286         static inline {
     267        inline {
    287268                void ?{}( SeqIterRev(T) & si ) with( si ) {     
    288269                        ((ColIter &)si){};
    289270                        seq = 0p;
    290                 } // post: elts = null
    291 
    292                 // Create a iterator active in sequence s.
     271                } // post: elts = null.
     272
    293273                void ?{}( SeqIterRev(T) & si, Sequence(T) & s ) with( si ) {   
    294274                        ((ColIter &)si){};
    295275                        seq = &s;
    296276                        curr = &tail( s );
    297                 } // post: elts = null
     277                } // post: elts = null.
    298278
    299279                void ?{}( SeqIterRev(T) & si, Sequence(T) & s, T & start ) with( si ) {
     
    301281                        seq = &s;
    302282                        curr = &start;
    303                 } // post: elts = null
    304 
    305                 // Make the iterator active in sequence s.
     283                } // post: elts = null.
     284
    306285                void over( SeqIterRev(T) & si, Sequence(T) & s ) with( si ) {
    307286                        seq = &s;
    308287                        curr = &tail( s );
    309                 } // post: elts = {e in s}
    310 
    311                 bool ?|?( SeqIterRev(T) & si, T && tp ) with( si ) {
     288                } // post: elts = {e in s}.
     289
     290                bool ?>>?( SeqIterRev(T) & si, T && tp ) with( si ) {
    312291                        if ( curr ) {
    313292                                &tp = Curr( si );
     
    319298        } // distribution
    320299} // distribution
    321 
    322 #endif
  • libcfa/src/bits/stack.hfa

    r2b4daf2 r42f6e07  
    33#include "bits/collection.hfa"
    44
    5 // A Stack(T) is a Collection(T) defining the ordering that nodes are returned by drop() in the reverse order from those
    6 // added by add(). T must be a public descendant of uColable.
    7 
    8 // The implementation is a typical singly-linked list, except the next field of the last element points to itself
    9 // instead of being null.
    10 
    11 forall( dtype T | { T *& Next ( T * ); } ) {
     5forall( dtype T ) {
    126        struct Stack {
    137                inline Collection;                                                              // Plan 9 inheritance
     
    3125                }
    3226
    33                 T & addHead( Stack(T) & s, T & n ) with( s ) {
     27                void addHead( Stack(T) & s, T & n ) with( s ) {
    3428                        #ifdef __CFA_DEBUG__
    3529                        if ( listed( (Colable &)(n) ) ) abort( "(Stack &)%p.addHead( %p ) : Node is already on another list.", &s, n );
     
    3731                        Next( &n ) = &head( s ) ? &head( s ) : &n;
    3832                        root = &n;
    39                         return n;
    4033                }
    4134
    42                 T & add( Stack(T) & s, T & n ) with( s ) {
    43                         return addHead( s, n );
     35                void add( Stack(T) & s, T & n ) with( s ) {
     36                        addHead( s, n );
    4437                }
    4538
    46                 T & push( Stack(T) & s, T & n ) with( s ) {
    47                         return addHead( s, n );
     39                void push( Stack(T) & s, T & n ) with( s ) {
     40                        addHead( s, n );
    4841                }
    4942
     
    5144                        T & t = head( s );
    5245                        if ( root ) {
    53                                 root = ( T *)Next( (T *)root );
     46                                root = ( T *)Next( root );
    5447                                if ( &head( s ) == &t ) root = 0p;              // only one element ?
    5548                                Next( &t ) = 0p;
     
    6457} // distribution
    6558
    66 // A StackIter(T) is a subclass of ColIter(T) that generates the elements of a Stack(T).  It returns the elements in the
    67 // order returned by drop().
    6859
    69 forall( dtype T | { T *& Next ( T * ); } ) {
     60forall( dtype T ) {
    7061        struct StackIter {
    7162                inline ColIter;                                                                 // Plan 9 inheritance
     
    7768                } // post: curr == 0p
    7869
    79                 // create an iterator active in stack s
     70                // create an iterator active in Stack s
    8071                void ?{}( StackIter(T) & si, Stack(T) & s ) with( si ) {
    8172                        curr = &head( s );
     
    8677                } // post: curr = {e in s}
    8778
    88                 // make existing iterator active in stack s
     79                // make existing iterator active in Stack q
    8980                void over( StackIter(T) & si, Stack(T) & s ) with( si ) {
    9081                        curr = &head( s );
    9182                } // post: curr = {e in s}
    9283
    93                 bool ?|?( StackIter(T) & si, T && tp ) with( si ) {
     84                bool ?>>?( StackIter(T) & si, T && tp ) with( si ) {
    9485                        if ( curr ) {
    9586                                &tp = Curr( si );
  • libcfa/src/concurrency/invoke.h

    r2b4daf2 r42f6e07  
    189189                struct __monitor_group_t monitors;
    190190
    191                 // used to put threads on user data structures
    192                 struct {
    193                         struct $thread * next;
    194                         struct $thread * back;
    195                 } seqable;
    196 
    197191                struct {
    198192                        struct $thread * next;
     
    224218                }
    225219
    226                 static inline $thread *& Back( $thread * this ) __attribute__((const)) {
    227                         return this->seqable.back;
    228                 }
    229 
    230                 static inline $thread *& Next( $thread * this ) __attribute__((const)) {
    231                         return this->seqable.next;
    232                 }
    233 
    234                 static inline bool listed( $thread * this ) {
    235                         return this->seqable.next != 0p;
    236                 }
    237 
    238220                static inline void ?{}(__monitor_group_t & this) {
    239221                        (this.data){0p};
  • libcfa/src/concurrency/kernel/startup.cfa

    r2b4daf2 r42f6e07  
    118118
    119119extern size_t __page_size;
    120 extern int __map_prot;
    121120
    122121//-----------------------------------------------------------------------------
     
    726725                }
    727726        #else
    728                 __cfaabi_dbg_debug_do(
    729                         // pthread has no mechanism to create the guard page in user supplied stack.
    730                         if ( mprotect( stack, __page_size, __map_prot ) == -1 ) {
    731                                 abort( "mprotect : internal error, mprotect failure, error(%d) %s.", errno, strerror( errno ) );
    732                         } // if
    733                 );
    734727                free( stack );
    735728        #endif
  • libcfa/src/concurrency/locks.cfa

    r2b4daf2 r42f6e07  
    11#include "locks.hfa"
    22#include "kernel_private.hfa"
     3#include <stdlib.h>
     4#include <stdio.h>
    35
    46#include <kernel.hfa>
    57#include <stdlib.hfa>
    6 
    7 //-----------------------------------------------------------------------------
    8 // info_thread
     8#include <thread.hfa>
     9
     10///////////////////////////////////////////////////////////////////
     11//// info_thread
     12///////////////////////////////////////////////////////////////////
     13
    914forall(dtype L | is_blocking_lock(L)) {
    10         struct info_thread {
    11                 // used to put info_thread on a dl queue (aka sequence)
    12                 inline Seqable;
    13 
    14                 // waiting thread
    15                 struct $thread * t;
    16 
    17                 // shadow field
    18                 uintptr_t info;
    19 
    20                 // lock that is passed to wait() (if one is passed)
    21                 L * lock;
    22 
    23                 // true when signalled and false when timeout wakes thread
    24                 bool signalled;
    25         };
    26 
    27         void ?{}( info_thread(L) & this, $thread * t, uintptr_t info, L * l ) {
     15        void ?{}( info_thread(L) & this, $thread * t ) {
     16                ((Seqable &) this){};
     17                this.t = t;
     18                this.lock = 0p;
     19                this.listed = false;
     20        }
     21
     22        void ?{}( info_thread(L) & this, $thread * t, uintptr_t info ) {
    2823                ((Seqable &) this){};
    2924                this.t = t;
    3025                this.info = info;
    31                 this.lock = l;
    32         }
    33 
    34         void ^?{}( info_thread(L) & this ) {}
    35 
    36         info_thread(L) *& Back( info_thread(L) * this ) {
    37                 return (info_thread(L) *)Back( (Seqable *)this );
    38         }
    39 
    40         info_thread(L) *& Next( info_thread(L) * this ) {
    41                 return (info_thread(L) *)Next( (Colable *)this );
    42         }
    43 }
    44 
    45 //-----------------------------------------------------------------------------
    46 // Blocking Locks
     26                this.lock = 0p;
     27                this.listed = false;
     28        }
     29
     30        void ^?{}( info_thread(L) & this ){ }
     31}
     32
     33///////////////////////////////////////////////////////////////////
     34//// Blocking Locks
     35///////////////////////////////////////////////////////////////////
     36
    4737void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner ) {
    4838        this.lock{};
     
    5646
    5747void ^?{}( blocking_lock & this ) {}
    58 void  ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };}
     48void ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };}
    5949void ^?{}( single_acquisition_lock & this ) {}
    60 void  ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };}
     50void ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };}
    6151void ^?{}( owner_lock & this ) {}
    62 void  ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };}
     52void ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };}
    6353void ^?{}( multiple_acquisition_lock & this ) {}
    6454
    6555void lock( blocking_lock & this ) with( this ) {
    6656        lock( lock __cfaabi_dbg_ctx2 );
    67         $thread * thrd = active_thread();
    68 
    69         // single acquisition lock is held by current thread
    70         /* paranoid */ verifyf( owner != thrd || multi_acquisition, "Single acquisition lock holder (%p) attempted to reacquire the lock %p resulting in a deadlock.", owner, &this );
    71 
    72         // lock is held by some other thread
    73         if ( owner != 0p && owner != thrd ) {
    74                 addTail( blocked_threads, *thrd );
     57        if ( owner == active_thread() && !multi_acquisition) {
     58                abort("A single acquisition lock holder attempted to reacquire the lock resulting in a deadlock.");
     59        } else if ( owner != 0p && owner != active_thread() ) {
     60                append( blocked_threads, active_thread() );
    7561                wait_count++;
    7662                unlock( lock );
    7763                park( );
    78         }
    79         // multi acquisition lock is held by current thread
    80         else if ( owner == thrd && multi_acquisition ) {
     64        } else if ( owner == active_thread() && multi_acquisition ) {
    8165                recursion_count++;
    8266                unlock( lock );
    83         }
    84         // lock isn't held
    85         else {
    86                 owner = thrd;
     67        } else {
     68                owner = active_thread();
    8769                recursion_count = 1;
    8870                unlock( lock );
     
    9375        bool ret = false;
    9476        lock( lock __cfaabi_dbg_ctx2 );
    95 
    96         // lock isn't held
    9777        if ( owner == 0p ) {
    9878                owner = active_thread();
    9979                recursion_count = 1;
    10080                ret = true;
    101         }
    102         // multi acquisition lock is held by current thread
    103         else if ( owner == active_thread() && multi_acquisition ) {
     81        } else if ( owner == active_thread() && multi_acquisition ) {
    10482                recursion_count++;
    10583                ret = true;
    10684        }
    107 
    10885        unlock( lock );
    10986        return ret;
    11087}
    11188
     89void unlock_error_check( blocking_lock & this ) with( this ) {
     90        if ( owner == 0p ){ // no owner implies lock isn't held
     91                abort( "There was an attempt to release a lock that isn't held" );
     92        } else if ( strict_owner && owner != active_thread() ) {
     93                abort( "A thread other than the owner attempted to release an owner lock" );
     94        }
     95}
     96
    11297void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
    113         $thread * t = &dropHead( blocked_threads );
     98        $thread * t = pop_head( blocked_threads );
    11499        owner = t;
    115100        recursion_count = ( t ? 1 : 0 );
     
    120105void unlock( blocking_lock & this ) with( this ) {
    121106        lock( lock __cfaabi_dbg_ctx2 );
    122         /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
    123         /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this );
    124 
    125         // if recursion count is zero release lock and set new owner if one is waiting
     107        unlock_error_check( this );
    126108        recursion_count--;
    127109        if ( recursion_count == 0 ) {
     
    143125}
    144126
    145 void on_notify( blocking_lock & this, $thread * t ) with( this ) {
    146         lock( lock __cfaabi_dbg_ctx2 );
    147         // lock held
     127void add_( blocking_lock & this, $thread * t ) with( this ) {
     128    lock( lock __cfaabi_dbg_ctx2 );
    148129        if ( owner != 0p ) {
    149                 addTail( blocked_threads, *t );
     130                append( blocked_threads, t );
    150131                wait_count++;
    151132                unlock( lock );
    152         }
    153         // lock not held
    154         else {
     133        } else {
    155134                owner = t;
    156135                recursion_count = 1;
     
    160139}
    161140
    162 void on_wait( blocking_lock & this ) with( this ) {
    163         lock( lock __cfaabi_dbg_ctx2 );
    164         /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
    165         /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this );
    166 
     141void remove_( blocking_lock & this ) with( this ) {
     142    lock( lock __cfaabi_dbg_ctx2 );
     143        unlock_error_check( this );
    167144        pop_and_set_new_owner( this );
    168145        unlock( lock );
    169146}
    170147
    171 //-----------------------------------------------------------------------------
    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 ); }
     148///////////////////////////////////////////////////////////////////
     149//// Overloaded routines for traits
     150///////////////////////////////////////////////////////////////////
     151
     152// This is temporary until an inheritance bug is fixed
     153
     154void lock( single_acquisition_lock & this ){ lock( (blocking_lock &)this ); }
     155void unlock( single_acquisition_lock & this ){ unlock( (blocking_lock &)this ); }
     156void add_( single_acquisition_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
     157void remove_( single_acquisition_lock & this ){ remove_( (blocking_lock &)this ); }
     158void set_recursion_count( single_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
     159size_t get_recursion_count( single_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
     160
     161void lock( owner_lock & this ){ lock( (blocking_lock &)this ); }
     162void unlock( owner_lock & this ){ unlock( (blocking_lock &)this ); }
     163void add_( owner_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
     164void remove_( owner_lock & this ){ remove_( (blocking_lock &)this ); }
     165void set_recursion_count( owner_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
     166size_t get_recursion_count( owner_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
     167
     168void lock( multiple_acquisition_lock & this ){ lock( (blocking_lock &)this ); }
     169void unlock( multiple_acquisition_lock & this ){ unlock( (blocking_lock &)this ); }
     170void add_( multiple_acquisition_lock & this, struct $thread * t ){ add_( (blocking_lock &)this, t ); }
     171void remove_( multiple_acquisition_lock & this ){ remove_( (blocking_lock &)this ); }
     172void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
    193173size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
    194174
    195 //-----------------------------------------------------------------------------
    196 // alarm node wrapper
     175///////////////////////////////////////////////////////////////////
     176//// condition variable
     177///////////////////////////////////////////////////////////////////
     178
    197179forall(dtype L | is_blocking_lock(L)) {
    198         struct alarm_node_wrap {
    199                 alarm_node_t alarm_node;
    200                 condition_variable(L) * cond;
    201                 info_thread(L) * i;
    202         };
    203 
    204         void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback, condition_variable(L) * c, info_thread(L) * i ) {
    205                 this.alarm_node{ callback, alarm, period };
    206                 this.cond = c;
    207                 this.i = i;
    208         }
    209 
    210         void ^?{}( alarm_node_wrap(L) & this ) { }
    211180
    212181        void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
    213                 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
    214                 lock( cond->lock __cfaabi_dbg_ctx2 );
    215 
    216                 // this check is necessary to avoid a race condition since this timeout handler
    217                 //      may still be called after a thread has been removed from the queue but
    218                 //      before the alarm is unregistered
    219                 if ( listed(i) ) {      // is thread on queue
    220                         i->signalled = false;
    221                         // remove this thread O(1)
    222                         remove( cond->blocked_threads, *i );
     182        // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
     183            lock( cond->lock __cfaabi_dbg_ctx2 );
     184           
     185            if ( i->listed ) {                  // is thread on queue
     186                cond->last_thread = i;          // REMOVE THIS AFTER DEBUG
     187                        remove( cond->blocked_threads, *i );             //remove this thread O(1)
    223188                        cond->count--;
    224                         if( i->lock ) {
    225                                 // call lock's on_notify if a lock was passed
    226                                 on_notify(*i->lock, i->t);
    227                         } else {
    228                                 // otherwise wake thread
     189                        if( !i->lock ) {
    229190                                unpark( i->t );
    230                         }
    231                 }
    232                 unlock( cond->lock );
    233         }
    234 
    235         // this casts the alarm node to our wrapped type since we used type erasure
     191                } else {
     192                        add_(*i->lock, i->t);                   // call lock's add_
     193                }
     194            }
     195            unlock( cond->lock );
     196        }
     197
    236198        void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); }
    237 }
    238 
    239 //-----------------------------------------------------------------------------
    240 // condition variable
    241 forall(dtype L | is_blocking_lock(L)) {
    242199
    243200        void ?{}( condition_variable(L) & this ){
     
    245202                this.blocked_threads{};
    246203                this.count = 0;
     204                this.last_thread = 0p; // REMOVE AFTER DEBUG
    247205        }
    248206
    249207        void ^?{}( condition_variable(L) & this ){ }
     208
     209        void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback ) {
     210                this.alarm_node{ callback, alarm, period };
     211        }
     212
     213        void ^?{}( alarm_node_wrap(L) & this ) { }
    250214
    251215        void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) {
    252216                if(&popped != 0p) {
    253                         popped.signalled = true;
     217                        popped.listed = false;
    254218                        count--;
    255219                        if (popped.lock) {
    256                                 // if lock passed call on_notify
    257                                 on_notify(*popped.lock, popped.t);
     220                                add_(*popped.lock, popped.t);
    258221                        } else {
    259                                 // otherwise wake thread
    260222                                unpark(popped.t);
    261223                        }
     
    290252
    291253        size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
    292                 // add info_thread to waiting queue
    293254                addTail( blocked_threads, *i );
    294255                count++;
     256                i->listed = true;
    295257                size_t recursion_count = 0;
    296258                if (i->lock) {
    297                         // if lock was passed get recursion count to reset to after waking thread
     259                        i->t->link.next = 1p;
    298260                        recursion_count = get_recursion_count(*i->lock);
    299                         on_wait( *i->lock );
     261                        remove_( *i->lock );
    300262                }
    301263                return recursion_count;
     
    307269                size_t recursion_count = queue_and_get_recursion(this, &i);
    308270                unlock( lock );
    309 
    310                 // blocks here
    311                 park( );
    312 
    313                 // resets recursion count here after waking
    314                 if (i.lock) set_recursion_count(*i.lock, recursion_count);
    315         }
    316 
    317         #define WAIT( u, l ) \
    318                 info_thread( L ) i = { active_thread(), u, l }; \
    319                 queue_info_thread( this, i );
     271                park( ); // blocks here
     272                if (i.lock) set_recursion_count(*i.lock, recursion_count); // resets recursion count here after waking
     273        }
    320274
    321275        // helper for wait()'s' with a timeout
     
    323277                lock( lock __cfaabi_dbg_ctx2 );
    324278                size_t recursion_count = queue_and_get_recursion(this, &info);
    325                 alarm_node_wrap(L) node_wrap = { t, 0`s, alarm_node_wrap_cast, &this, &info };
     279                alarm_node_wrap(L) node_wrap = { t, 0`s, alarm_node_wrap_cast };
     280                node_wrap.cond = &this;
     281                node_wrap.i = &info;
    326282                register_self( &node_wrap.alarm_node );
    327283                unlock( lock );
    328 
    329                 // blocks here
    330284                park();
    331 
    332                 // unregisters alarm so it doesn't go off if this happens first
    333285                unregister_self( &node_wrap.alarm_node );
    334 
    335                 // resets recursion count here after waking
    336286                if (info.lock) set_recursion_count(*info.lock, recursion_count);
    337287        }
    338288
    339         #define WAIT_TIME( u, l, t ) \
    340                 info_thread( L ) i = { active_thread(), u, l }; \
    341                 queue_info_thread_timeout(this, i, t ); \
    342                 return i.signalled;
    343 
    344         void wait( condition_variable(L) & this                        ) with(this) { WAIT( 0, 0p    ) }
    345         void wait( condition_variable(L) & this, uintptr_t info        ) with(this) { WAIT( info, 0p ) }
    346         void wait( condition_variable(L) & this, L & l                 ) with(this) { WAIT( 0, &l    ) }
    347         void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) { WAIT( info, &l ) }
    348 
    349         bool wait( condition_variable(L) & this, Duration duration                        ) with(this) { WAIT_TIME( 0   , 0p , __kernel_get_time() + duration ) }
    350         bool wait( condition_variable(L) & this, uintptr_t info, Duration duration        ) with(this) { WAIT_TIME( info, 0p , __kernel_get_time() + duration ) }
    351         bool wait( condition_variable(L) & this, Time time                                ) with(this) { WAIT_TIME( 0   , 0p , time ) }
    352         bool wait( condition_variable(L) & this, uintptr_t info, Time time                ) with(this) { WAIT_TIME( info, 0p , time ) }
    353         bool wait( condition_variable(L) & this, L & l, Duration duration                 ) with(this) { WAIT_TIME( 0   , &l , __kernel_get_time() + duration ) }
    354         bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, &l , __kernel_get_time() + duration ) }
    355         bool wait( condition_variable(L) & this, L & l, Time time                         ) with(this) { WAIT_TIME( 0   , &l , time ) }
    356         bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time         ) with(this) { WAIT_TIME( info, &l , time ) }
    357 }
     289        void wait( condition_variable(L) & this ) with(this) {
     290                info_thread( L ) i = { active_thread() };
     291                queue_info_thread( this, i );
     292        }
     293
     294        void wait( condition_variable(L) & this, uintptr_t info ) with(this) {
     295                info_thread( L ) i = { active_thread(), info };
     296                queue_info_thread( this, i );
     297        }
     298       
     299        void wait( condition_variable(L) & this, Duration duration ) with(this) {
     300                info_thread( L ) i = { active_thread() };
     301                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
     302        }
     303
     304        void wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) {
     305                info_thread( L ) i = { active_thread(), info };
     306                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
     307        }
     308
     309        void wait( condition_variable(L) & this, Time time ) with(this) {
     310                info_thread( L ) i = { active_thread() };
     311                queue_info_thread_timeout(this, i, time);
     312        }
     313
     314        void wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) {
     315                info_thread( L ) i = { active_thread(), info };
     316                queue_info_thread_timeout(this, i, time);
     317        }
     318
     319        void wait( condition_variable(L) & this, L & l ) with(this) {
     320                info_thread(L) i = { active_thread() };
     321                i.lock = &l;
     322                queue_info_thread( this, i );
     323        }
     324
     325        void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) {
     326                info_thread(L) i = { active_thread(), info };
     327                i.lock = &l;
     328                queue_info_thread( this, i );
     329        }
     330       
     331        void wait( condition_variable(L) & this, L & l, Duration duration ) with(this) {
     332                info_thread(L) i = { active_thread() };
     333                i.lock = &l;
     334                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
     335        }
     336       
     337        void wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) {
     338                info_thread(L) i = { active_thread(), info };
     339                i.lock = &l;
     340                queue_info_thread_timeout(this, i, __kernel_get_time() + duration );
     341        }
     342       
     343        void wait( condition_variable(L) & this, L & l, Time time ) with(this) {
     344                info_thread(L) i = { active_thread() };
     345                i.lock = &l;
     346                queue_info_thread_timeout(this, i, time );
     347        }
     348       
     349        void wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) {
     350                info_thread(L) i = { active_thread(), info };
     351                i.lock = &l;
     352                queue_info_thread_timeout(this, i, time );
     353        }
     354}
  • libcfa/src/concurrency/locks.hfa

    r2b4daf2 r42f6e07  
    33#include <stdbool.h>
    44
     5#include "bits/algorithm.hfa"
    56#include "bits/locks.hfa"
    67#include "bits/sequence.hfa"
     8#include "bits/containers.hfa"
    79
    810#include "invoke.h"
     
    1012#include "time_t.hfa"
    1113#include "time.hfa"
     14#include <sys/time.h>
     15#include "alarm.hfa"
    1216
    13 //-----------------------------------------------------------------------------
    14 // is_blocking_lock
     17///////////////////////////////////////////////////////////////////
     18//// is_blocking_lock
     19///////////////////////////////////////////////////////////////////
     20
    1521trait is_blocking_lock(dtype L | sized(L)) {
    16         // For synchronization locks to use when acquiring
    17         void on_notify( L &, struct $thread * );
    18 
    19         // For synchronization locks to use when releasing
    20         void on_wait( L & );
    21 
    22         // to get recursion count for cond lock to reset after waking
    23         size_t get_recursion_count( L & );
    24 
    25         // to set recursion count after getting signalled;
    26         void set_recursion_count( L &, size_t recursion );
     22        void add_( L &, struct $thread * );             // For synchronization locks to use when acquiring
     23        void remove_( L & );    // For synchronization locks to use when releasing
     24        size_t get_recursion_count( L & ); // to get recursion count for cond lock to reset after waking
     25        void set_recursion_count( L &, size_t recursion ); // to set recursion count after getting signalled;
    2726};
    2827
    29 //-----------------------------------------------------------------------------
    30 // info_thread
    31 // the info thread is a wrapper around a thread used
    32 // to store extra data for use in the condition variable
     28///////////////////////////////////////////////////////////////////
     29//// info_thread
     30///////////////////////////////////////////////////////////////////
     31
    3332forall(dtype L | is_blocking_lock(L)) {
    34         struct info_thread;
     33        struct info_thread {
     34                inline Seqable;
     35                struct $thread * t;
     36                uintptr_t info;
     37                L * lock;
     38                bool listed;                                    // true if info_thread is on queue, false otherwise;
     39        };
    3540
    36         // for use by sequence
    37         info_thread(L) *& Back( info_thread(L) * this );
    38         info_thread(L) *& Next( info_thread(L) * this );
     41
     42        void ?{}( info_thread(L) & this, $thread * t );
     43        void ?{}( info_thread(L) & this, $thread * t, uintptr_t info );
     44        void ^?{}( info_thread(L) & this );
    3945}
    4046
    41 //-----------------------------------------------------------------------------
    42 // Blocking Locks
     47///////////////////////////////////////////////////////////////////
     48//// Blocking Locks
     49///////////////////////////////////////////////////////////////////
     50
     51// struct lock_thread {
     52//      struct $thread * t;
     53//      lock_thread * next;
     54// };
     55
     56// void ?{}( lock_thread & this, struct $thread * thd );
     57// void ^?{}( lock_thread & this );
     58
     59// lock_thread *& get_next( lock_thread & );
     60
    4361struct blocking_lock {
    4462        // Spin lock used for mutual exclusion
     
    4664
    4765        // List of blocked threads
    48         Sequence( $thread ) blocked_threads;
     66        __queue_t( $thread ) blocked_threads;
    4967
    5068        // Count of current blocked threads
     
    7694};
    7795
    78 void  ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner );
     96void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner );
    7997void ^?{}( blocking_lock & this );
    8098
    81 void  ?{}( single_acquisition_lock & this );
     99void ?{}( single_acquisition_lock & this );
    82100void ^?{}( single_acquisition_lock & this );
    83101
    84 void  ?{}( owner_lock & this );
     102void ?{}( owner_lock & this );
    85103void ^?{}( owner_lock & this );
    86104
    87 void  ?{}( multiple_acquisition_lock & this );
     105void ?{}( multiple_acquisition_lock & this );
    88106void ^?{}( multiple_acquisition_lock & this );
    89107
     
    91109bool try_lock( blocking_lock & this );
    92110void unlock( blocking_lock & this );
    93 void on_notify( blocking_lock & this, struct $thread * t );
    94 void on_wait( blocking_lock & this );
     111void add_( blocking_lock & this, struct $thread * t );
     112void remove_( blocking_lock & this );
    95113size_t wait_count( blocking_lock & this );
    96114void set_recursion_count( blocking_lock & this, size_t recursion );
     
    99117void lock( single_acquisition_lock & this );
    100118void unlock( single_acquisition_lock & this );
    101 void on_notify( single_acquisition_lock & this, struct $thread * t );
    102 void on_wait( single_acquisition_lock & this );
     119void add_( single_acquisition_lock & this, struct $thread * t );
     120void remove_( single_acquisition_lock & this );
    103121void set_recursion_count( single_acquisition_lock & this, size_t recursion );
    104122size_t get_recursion_count( single_acquisition_lock & this );
     
    106124void lock( owner_lock & this );
    107125void unlock( owner_lock & this );
    108 void on_notify( owner_lock & this, struct $thread * t );
    109 void on_wait( owner_lock & this );
     126void add_( owner_lock & this, struct $thread * t );
     127void remove_( owner_lock & this );
    110128void set_recursion_count( owner_lock & this, size_t recursion );
    111129size_t get_recursion_count( owner_lock & this );
     
    113131void lock( multiple_acquisition_lock & this );
    114132void unlock( multiple_acquisition_lock & this );
    115 void on_notify( multiple_acquisition_lock & this, struct $thread * t );
    116 void on_wait( multiple_acquisition_lock & this );
     133void add_( multiple_acquisition_lock & this, struct $thread * t );
     134void remove_( multiple_acquisition_lock & this );
    117135void set_recursion_count( multiple_acquisition_lock & this, size_t recursion );
    118136size_t get_recursion_count( multiple_acquisition_lock & this );
    119137
    120 //-----------------------------------------------------------------------------
    121 // Synchronization Locks
     138///////////////////////////////////////////////////////////////////
     139//// Synchronization Locks
     140///////////////////////////////////////////////////////////////////
    122141forall(dtype L | is_blocking_lock(L)) {
    123142        struct condition_variable {
    124143                // Spin lock used for mutual exclusion
    125144                __spinlock_t lock;
     145
     146                info_thread(L) * last_thread;
    126147
    127148                // List of blocked threads
     
    132153        };
    133154
    134         void  ?{}( condition_variable(L) & this );
     155        void ?{}( condition_variable(L) & this );
    135156        void ^?{}( condition_variable(L) & this );
     157
     158        struct alarm_node_wrap {
     159                alarm_node_t alarm_node;
     160
     161                condition_variable(L) * cond;
     162
     163                info_thread(L) * i;
     164        };
     165
     166        void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback );
     167        void ^?{}( alarm_node_wrap(L) & this );
     168
     169        void alarm_node_callback( alarm_node_wrap(L) & this );
     170
     171        void alarm_node_wrap_cast( alarm_node_t & a );
    136172
    137173        bool notify_one( condition_variable(L) & this );
     
    140176        uintptr_t front( condition_variable(L) & this );
    141177
    142         bool empty  ( condition_variable(L) & this );
    143         int  counter( condition_variable(L) & this );
     178        bool empty( condition_variable(L) & this );
     179        int counter( condition_variable(L) & this );
    144180
     181        // TODO: look into changing timout routines to return bool showing if signalled or woken by kernel
    145182        void wait( condition_variable(L) & this );
    146183        void wait( condition_variable(L) & this, uintptr_t info );
    147         bool wait( condition_variable(L) & this, Duration duration );
    148         bool wait( condition_variable(L) & this, uintptr_t info, Duration duration );
    149         bool wait( condition_variable(L) & this, Time time );
    150         bool wait( condition_variable(L) & this, uintptr_t info, Time time );
     184        void wait( condition_variable(L) & this, Duration duration );
     185        void wait( condition_variable(L) & this, uintptr_t info, Duration duration );
     186        void wait( condition_variable(L) & this, Time time );
     187        void wait( condition_variable(L) & this, uintptr_t info, Time time );
    151188
    152189        void wait( condition_variable(L) & this, L & l );
    153190        void wait( condition_variable(L) & this, L & l, uintptr_t info );
    154         bool wait( condition_variable(L) & this, L & l, Duration duration );
    155         bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration );
    156         bool wait( condition_variable(L) & this, L & l, Time time );
    157         bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time );
     191        void wait( condition_variable(L) & this, L & l, Duration duration );
     192        void wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration );
     193        void wait( condition_variable(L) & this, L & l, Time time );
     194        void wait( condition_variable(L) & this, L & l, uintptr_t info, Time time );
    158195}
  • libcfa/src/concurrency/monitor.hfa

    r2b4daf2 r42f6e07  
    132132
    133133              void wait        ( condition & this, uintptr_t user_info = 0 );
    134 static inline bool is_empty    ( condition & this ) { return this.blocked.head == 1p; }
    135134              bool signal      ( condition & this );
    136135              bool signal_block( condition & this );
    137 static inline bool signal_all  ( condition & this ) { bool ret = false; while(!is_empty(this)) { ret = signal(this) || ret; } return ret; }
     136static inline bool is_empty    ( condition & this ) { return this.blocked.head == 1p; }
    138137         uintptr_t front       ( condition & this );
    139138
  • libcfa/src/concurrency/thread.cfa

    r2b4daf2 r42f6e07  
    4343                canary = 0x0D15EA5E0D15EA5Ep;
    4444        #endif
    45 
    46         seqable.next = 0p;
    47         seqable.back = 0p;
    4845
    4946        node.next = 0p;
     
    133130
    134131        this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP];
    135         /* paranoid */ verify( this_thrd->context.SP );
     132        verify( this_thrd->context.SP );
    136133
    137134        __schedule_thread( this_thrd );
  • libcfa/src/heap.cfa

    r2b4daf2 r42f6e07  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 16 12:28:25 2020
    13 // Update Count     : 1023
     12// Last Modified On : Tue Dec 15 21:37:54 2020
     13// Update Count     : 1013
    1414//
    1515
     
    438438        header = headerAddr( addr );
    439439
    440   if ( unlikely( addr < heapBegin || heapEnd < addr ) ) { // mmapped ?
     440  if ( unlikely( heapEnd < addr ) ) {                                   // mmapped ?
    441441                fakeHeader( header, alignment );
    442442                size = header->kind.real.blockSize & -3;                // mmap size
     
    445445
    446446        #ifdef __CFA_DEBUG__
    447         checkHeader( header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
     447        checkHeader( addr < heapBegin, name, addr );            // bad low address ?
    448448        #endif // __CFA_DEBUG__
    449449
     
    484484#endif // __CFA_DEBUG__
    485485
    486 
    487486#define NO_MEMORY_MSG "insufficient heap memory available for allocating %zd new bytes."
    488487
     488#include <unistd.h>
    489489static inline void * extend( size_t size ) with( heapManager ) {
    490490        lock( extlock __cfaabi_dbg_ctx2 );
     
    511511                #ifdef __CFA_DEBUG__
    512512                // Set new memory to garbage so subsequent uninitialized usages might fail.
    513                 memset( (char *)heapEnd + heapRemaining, '\xde', increase );
     513                memset( (char *)heapEnd + heapRemaining, '\hde', increase );
    514514                //Memset( (char *)heapEnd + heapRemaining, increase );
    515515                #endif // __CFA_DEBUG__
     
    586586                #ifdef __CFA_DEBUG__
    587587                // Set new memory to garbage so subsequent uninitialized usages might fail.
    588                 memset( block, '\xde', tsize );
     588                memset( block, '\hde', tsize );
    589589                //Memset( block, tsize );
    590590                #endif // __CFA_DEBUG__
     
    634634                #ifdef __CFA_DEBUG__
    635635                // Set free memory to garbage so subsequent usages might fail.
    636                 memset( ((HeapManager.Storage *)header)->data, '\xde', freeElem->blockSize - sizeof( HeapManager.Storage ) );
     636                memset( ((HeapManager.Storage *)header)->data, '\hde', freeElem->blockSize - sizeof( HeapManager.Storage ) );
    637637                //Memset( ((HeapManager.Storage *)header)->data, freeElem->blockSize - sizeof( HeapManager.Storage ) );
    638638                #endif // __CFA_DEBUG__
     
    10291029        } // cmemalign
    10301030
    1031 
    10321031        // Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple
    10331032    // of alignment. This requirement is universally ignored.
     
    10461045                return 0;
    10471046        } // posix_memalign
    1048 
    10491047
    10501048        // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the
  • libcfa/src/memory.cfa

    r2b4daf2 r42f6e07  
    6666forall(dtype T | sized(T), ttype Args | { void ?{}(T&, Args); })
    6767void ?{}(counter_ptr(T) & this, Args args) {
    68         this.data = (counter_data(T)*)new(args);
     68        this.data = new(args);
    6969}
    7070
     
    126126forall(dtype T | sized(T), ttype Args | { void ?{}(T &, Args); })
    127127void ?{}(unique_ptr(T) & this, Args args) {
    128         this.data = (T *)new(args);
     128        this.data = new(args);
    129129}
    130130
  • libcfa/src/parseargs.cfa

    r2b4daf2 r42f6e07  
    105105                                        if(opt == options[i].short_name) {
    106106                                                const char * arg = optarg ? optarg : "";
    107                                                 if( arg[0] == '=' ) { arg++; }
    108107                                                bool success = options[i].parse( arg, options[i].variable );
    109108                                                if(success) continue NEXT_ARG;
     
    186185}
    187186
    188 bool parse_truefalse(const char * arg, bool & value) {
    189         if(strcmp(arg, "true") == 0) {
    190                 value = true;
    191                 return true;
    192         }
    193 
    194         if(strcmp(arg, "false") == 0) {
    195                 value = false;
    196                 return true;
    197         }
    198 
    199         return false;
    200 }
    201 
    202187bool parse_settrue (const char *, bool & value ) {
    203188        value = true;
  • libcfa/src/parseargs.hfa

    r2b4daf2 r42f6e07  
    3737void print_args_usage(int argc, char * argv[], cfa_option options[], size_t opt_count, const char * usage, bool error)  __attribute__ ((noreturn));
    3838
    39 bool parse_yesno    (const char *, bool & );
    40 bool parse_truefalse(const char *, bool & );
    41 bool parse_settrue  (const char *, bool & );
    42 bool parse_setfalse (const char *, bool & );
     39bool parse_yesno   (const char *, bool & );
     40bool parse_settrue (const char *, bool & );
     41bool parse_setfalse(const char *, bool & );
    4342
    4443bool parse(const char *, const char * & );
  • libcfa/src/stdlib.hfa

    r2b4daf2 r42f6e07  
    267267static inline forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } )
    268268T * new( TT p ) {
    269         return &(*(T *)malloc()){ p };                                                  // run constructor
     269        return &(*malloc()){ p };                                                       // run constructor
    270270} // new
    271271
  • longrun_tests/Makefile.am

    r2b4daf2 r42f6e07  
    4444        -DTEST_$(shell cat .type | tr a-z A-Z)
    4545
    46 TESTS = block coroutine create disjoint enter enter3 locks processor stack wait yield
     46TESTS = block coroutine create disjoint enter enter3 processor stack wait yield
    4747
    4848# .INTERMEDIATE: $(TESTS)
  • src/AST/Convert.cpp

    r2b4daf2 r42f6e07  
    205205                ftype->parameters = get<DeclarationWithType>().acceptL(node->params);
    206206
    207                 ftype->forall = get<TypeDecl>().acceptL( node->type_params );
    208                 if (!node->assertions.empty()) {
    209                         assert(!ftype->forall.empty());
    210                         // find somewhere to place assertions back, for convenience it is the last slot
    211                         ftype->forall.back()->assertions = get<DeclarationWithType>().acceptL(node->assertions);
    212                 }
     207                ftype->forall = get<TypeDecl>().acceptL( node->type->forall );
    213208
    214209                visitType(node->type, ftype);
     
    607602
    608603                for (decltype(src->begin()) src_i = src->begin(); src_i != src->end(); src_i++) {
    609                         rslt->add( src_i->first.typeString(),
     604                        rslt->add( src_i->first,
    610605                                   get<Type>().accept1(src_i->second) );
     606                }
     607
     608                for (decltype(src->beginVar()) src_i = src->beginVar(); src_i != src->endVar(); src_i++) {
     609                        rslt->addVar( src_i->first,
     610                                      get<Expression>().accept1(src_i->second) );
    611611                }
    612612
     
    12121212                // ty->returnVals = get<DeclarationWithType>().acceptL( node->returns );
    12131213                // ty->parameters = get<DeclarationWithType>().acceptL( node->params );
    1214 
    1215                 auto types = get<TypeInstType>().acceptL( node->forall );
    1216                 for (auto t : types) {
    1217                         auto newT = new TypeDecl(*t->baseType);
    1218                         newT->name = t->name; // converted by typeString()
    1219                         for (auto asst : newT->assertions) delete asst;
    1220                         newT->assertions.clear();
    1221                         ty->forall.push_back(newT);
    1222                 }
    1223                 auto assts = get<VariableExpr>().acceptL( node->assertions );
    1224                 if (!assts.empty()) {
    1225                         assert(!types.empty());
    1226                         for (auto asst : assts) {
    1227                                 auto newDecl = new ObjectDecl(*strict_dynamic_cast<ObjectDecl*>(asst->var));
    1228                                 delete newDecl->type;
    1229                                 newDecl->type = asst->result->clone();
    1230                                 newDecl->storageClasses.is_extern = true; // hack
    1231                                 ty->forall.back()->assertions.push_back(newDecl);
    1232                         }
    1233                 }
    1234 
     1214                ty->forall = get<TypeDecl>().acceptL( node->forall );
    12351215                return visitType( node, ty );
    12361216        }
     
    13191299                        ty = new TypeInstType{
    13201300                                cv( node ),
    1321                                 node->typeString(),
     1301                                node->name,
    13221302                                get<TypeDecl>().accept1( node->base ),
    13231303                                get<Attribute>().acceptL( node->attributes )
     
    13261306                        ty = new TypeInstType{
    13271307                                cv( node ),
    1328                                 node->typeString(),
     1308                                node->name,
    13291309                                node->kind == ast::TypeDecl::Ftype,
    13301310                                get<Attribute>().acceptL( node->attributes )
     
    14511431        /// at conversion stage, all created nodes are guaranteed to be unique, therefore
    14521432        /// const_casting out of smart pointers is permitted.
    1453         std::unordered_map< const BaseSyntaxNode *, ast::readonly<ast::Node> > cache = {};
     1433        std::unordered_map< const BaseSyntaxNode *, ast::ptr<ast::Node> > cache = {};
    14541434
    14551435        // Local Utilities:
     
    15851565                // can function type have attributes? seems not to be the case.
    15861566                // visitType(old->type, ftype);
    1587 
    1588                 // collect assertions and put directly in FunctionDecl
    1589                 std::vector<ast::ptr<ast::DeclWithType>> assertions;
    1590                 for (auto & param: forall) {
    1591                         for (auto & asst: param->assertions) {
    1592                                 assertf(asst->unique(), "newly converted decl must be unique");
    1593                                 assertions.emplace_back(asst);
    1594                         }
    1595                         auto mut = param.get_and_mutate();
    1596                         assertf(mut == param, "newly converted decl must be unique");
    1597                         mut->assertions.clear();
    1598                 }
    15991567
    16001568                auto decl = new ast::FunctionDecl{
     
    16161584                cache.emplace( old, decl );
    16171585
    1618                 decl->assertions = std::move(assertions);
    16191586                decl->withExprs = GET_ACCEPT_V(withExprs, Expr);
    16201587                decl->stmts = GET_ACCEPT_1(statements, CompoundStmt);
     
    20992066        }
    21002067
    2101         // TypeSubstitution shouldn't exist yet in old.
    21022068        ast::TypeSubstitution * convertTypeSubstitution(const TypeSubstitution * old) {
    2103                
     2069
    21042070                if (!old) return nullptr;
    2105                 if (old->empty()) return nullptr;
    2106                 assert(false);
    2107 
    2108                 /*
     2071
    21092072                ast::TypeSubstitution *rslt = new ast::TypeSubstitution();
    21102073
     
    21142077                }
    21152078
     2079                for (decltype(old->beginVar()) old_i = old->beginVar(); old_i != old->endVar(); old_i++) {
     2080                        rslt->addVar( old_i->first,
     2081                                      getAccept1<ast::Expr>(old_i->second) );
     2082                }
     2083
    21162084                return rslt;
    2117                 */
    21182085        }
    21192086
     
    26432610                        ty->params.emplace_back(v->get_type());
    26442611                }
    2645                 // xxx - when will this be non-null?
    2646                 // will have to create dangling (no-owner) decls to be pointed to
    2647                 auto foralls = GET_ACCEPT_V( forall, TypeDecl );
    2648 
    2649                 for (auto & param : foralls) {
    2650                         ty->forall.emplace_back(new ast::TypeInstType(param->name, param));
    2651                         for (auto asst : param->assertions) {
    2652                                 ty->assertions.emplace_back(new ast::VariableExpr({}, asst));
    2653                         }
    2654                 }
     2612                ty->forall = GET_ACCEPT_V( forall, TypeDecl );
    26552613                visitType( old, ty );
    26562614        }
  • src/AST/Decl.cpp

    r2b4daf2 r42f6e07  
    5050
    5151FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name,
    52         std::vector<ptr<TypeDecl>>&& forall,
    53         std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    54         CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
    55         std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
    56 : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
    57         type_params(std::move(forall)), stmts( stmts ) {
    58         FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs));
    59         for (auto & param : this->params) {
    60                 ftype->params.emplace_back(param->get_type());
    61         }
    62         for (auto & ret : this->returns) {
    63                 ftype->returns.emplace_back(ret->get_type());
    64         }
    65         for (auto & tp : this->type_params) {
    66                 ftype->forall.emplace_back(new TypeInstType(tp->name, tp));
    67         }
    68         this->type = ftype;
    69 }
     52                std::vector<ptr<TypeDecl>>&& forall,
     53                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
     54                CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
     55                std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
     56        : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
     57          stmts( stmts ) {
     58                  FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs));
     59                  for (auto & param : this->params) {
     60                          ftype->params.emplace_back(param->get_type());
     61                  }
     62                  for (auto & ret : this->returns) {
     63                          ftype->returns.emplace_back(ret->get_type());
     64                  }
     65                  ftype->forall = std::move(forall);
     66                  this->type = ftype;
     67          }
    7068
    7169
  • src/AST/Decl.hpp

    r2b4daf2 r42f6e07  
    127127        std::vector<ptr<DeclWithType>> params;
    128128        std::vector<ptr<DeclWithType>> returns;
    129         std::vector<ptr<TypeDecl>> type_params;
    130         std::vector<ptr<DeclWithType>> assertions;
    131129        // declared type, derived from parameter declarations
    132130        ptr<FunctionType> type;
    133131        ptr<CompoundStmt> stmts;
    134132        std::vector< ptr<Expr> > withExprs;
    135 
    136133
    137134        FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
  • src/AST/Expr.cpp

    r2b4daf2 r42f6e07  
    206206        assert( aggregate->result );
    207207
    208         result = mem->get_type();
     208        // Deep copy on result type avoids mutation on transitively multiply referenced object.
     209        //
     210        // Example, adapted from parts of builtins and bootloader:
     211        //
     212        // forall(dtype T)
     213        // struct __Destructor {
     214        //   T * object;
     215        //   void (*dtor)(T *);
     216        // };
     217        //
     218        // forall(dtype S)
     219        // void foo(__Destructor(S) &d) {
     220        //   if (d.dtor) {  // here
     221        //   }
     222        // }
     223        //
     224        // Let e be the "d.dtor" guard espression, which is MemberExpr after resolve.  Let d be the
     225        // declaration of member __Destructor.dtor (an ObjectDecl), as accessed via the top-level
     226        // declaration of __Destructor.  Consider the types e.result and d.type.  In the old AST, one
     227        // is a clone of the other.  Ordinary new-AST use would set them up as a multiply-referenced
     228        // object.
     229        //
     230        // e.result: PointerType
     231        // .base: FunctionType
     232        // .params.front(): ObjectDecl, the anonymous parameter of type T*
     233        // .type: PointerType
     234        // .base: TypeInstType
     235        // let x = that
     236        // let y = similar, except start from d.type
     237        //
     238        // Consider two code lines down, genericSubstitution(...).apply(result).
     239        //
     240        // Applying this chosen-candidate's type substitution means modifying x, substituting
     241        // S for T.  This mutation should affect x and not y.
     242
     243        result = deepCopy(mem->get_type());
    209244
    210245        // substitute aggregate generic parameters into member type
  • src/AST/Node.hpp

    r2b4daf2 r42f6e07  
    229229        const node_t & operator* () const { _check(); return *node; }
    230230        explicit operator bool() const { _check(); return node; }
    231         operator const node_t * () const & { _check(); return node; }
    232         operator const node_t * () && = delete;
     231        operator const node_t * () const { _check(); return node; }
    233232
    234233        const node_t * release() {
  • src/AST/Pass.hpp

    r2b4daf2 r42f6e07  
    3434
    3535#include "AST/SymbolTable.hpp"
     36
     37#include "AST/ForallSubstitutionTable.hpp"
    3638
    3739// Private prelude header, needed for some of the magic tricks this class pulls off
     
    6466// | WithVisitorRef        - provides an pointer to the templated visitor wrapper
    6567// | WithSymbolTable       - provides symbol table functionality
     68// | WithForallSubstitutor - maintains links between TypeInstType and TypeDecl under mutation
    6669//
    6770// Other Special Members:
     
    255258        container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
    256259
     260        /// Mutate forall-list, accounting for presence of type substitution map
     261        template<typename node_t>
     262        void mutate_forall( const node_t *& );
     263
    257264public:
    258265        /// Logic to call the accept and mutate the parent if needed, delegates call to accept
     
    391398};
    392399
     400/// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl
     401struct WithForallSubstitutor {
     402        ForallSubstitutionTable subs;
     403};
     404
    393405}
    394406
  • src/AST/Pass.impl.hpp

    r2b4daf2 r42f6e07  
    367367        }
    368368
     369
     370        template< typename core_t >
     371        template< typename node_t >
     372        void ast::Pass< core_t >::mutate_forall( const node_t *& node ) {
     373                if ( auto subs = __pass::forall::subs( core, 0 ) ) {
     374                        // tracking TypeDecl substitution, full clone
     375                        if ( node->forall.empty() ) return;
     376
     377                        node_t * mut = __pass::mutate<core_t>( node );
     378                        mut->forall = subs->clone( node->forall, *this );
     379                        node = mut;
     380                } else {
     381                        // not tracking TypeDecl substitution, just mutate
     382                        maybe_accept( node, &node_t::forall );
     383                }
     384        }
    369385}
    370386
     
    488504                        __pass::symtab::addId( core, 0, func );
    489505                        VISIT(
    490                                 // parameter declarations
     506                                // parameter declarations are now directly here
    491507                                maybe_accept( node, &FunctionDecl::params );
    492508                                maybe_accept( node, &FunctionDecl::returns );
    493                                 // type params and assertions
    494                                 maybe_accept( node, &FunctionDecl::type_params );
    495                                 maybe_accept( node, &FunctionDecl::assertions );
     509                                // foralls are still in function type
     510                                maybe_accept( node, &FunctionDecl::type );
    496511                                // First remember that we are now within a function.
    497512                                ValueGuard< bool > oldInFunction( inFunction );
     
    17431758
    17441759        VISIT({
    1745                 // guard_forall_subs forall_guard { *this, node };
    1746                 // mutate_forall( node );
    1747                 maybe_accept( node, &FunctionType::assertions );
     1760                guard_forall_subs forall_guard { *this, node };
     1761                mutate_forall( node );
    17481762                maybe_accept( node, &FunctionType::returns );
    17491763                maybe_accept( node, &FunctionType::params  );
     
    19671981                {
    19681982                        bool mutated = false;
    1969                         std::unordered_map< ast::TypeInstType::TypeEnvKey, ast::ptr< ast::Type > > new_map;
     1983                        std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;
    19701984                        for ( const auto & p : node->typeEnv ) {
    19711985                                guard_symtab guard { *this };
     
    19801994                        }
    19811995                }
     1996
     1997                {
     1998                        bool mutated = false;
     1999                        std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;
     2000                        for ( const auto & p : node->varEnv ) {
     2001                                guard_symtab guard { *this };
     2002                                auto new_node = p.second->accept( *this );
     2003                                if (new_node != p.second) mutated = true;
     2004                                new_map.insert({ p.first, new_node });
     2005                        }
     2006                        if (mutated) {
     2007                                auto new_node = __pass::mutate<core_t>( node );
     2008                                new_node->varEnv.swap( new_map );
     2009                                node = new_node;
     2010                        }
     2011                }
    19822012        )
    19832013
  • src/AST/Pass.proto.hpp

    r2b4daf2 r42f6e07  
    413413                static inline auto leave( core_t &, long, const ast::FunctionType * ) {}
    414414
     415                // Get the substitution table, if present
     416                template<typename core_t>
     417                static inline auto subs( core_t & core, int ) -> decltype( &core.subs ) {
     418                        return &core.subs;
     419                }
     420
     421                template<typename core_t>
     422                static inline ast::ForallSubstitutionTable * subs( core_t &, long ) { return nullptr; }
     423
    415424                // Replaces a TypeInstType's base TypeDecl according to the table
    416425                template<typename core_t>
  • src/AST/Print.cpp

    r2b4daf2 r42f6e07  
    155155        }
    156156
    157         void print( const ast::FunctionType::AssertionList & assts ) {
    158                 if (assts.empty()) return;
    159                 os << "with assertions" << endl;
    160                 ++indent;
    161                 printAll(assts);
    162                 os << indent;
    163                 --indent;
    164         }
    165 
    166157        void print( const std::vector<ptr<Attribute>> & attrs ) {
    167158                if ( attrs.empty() ) return;
     
    215206        void preprint( const ast::NamedTypeDecl * node ) {
    216207                if ( ! node->name.empty() ) {
    217                         os << node->name << ": ";
     208                        if( deterministic_output && isUnboundType(node->name) ) os << "[unbound]:";
     209                        else os << node->name << ": ";
    218210                }
    219211
     
    269261        void preprint( const ast::FunctionType * node ) {
    270262                print( node->forall );
    271                 print( node->assertions );
    272263                print( node->qualifiers );
    273264        }
     
    13841375        virtual const ast::Type * visit( const ast::TypeInstType * node ) override final {
    13851376                preprint( node );
    1386                 const auto & _name = deterministic_output && isUnboundType(node) ? "[unbound]" : node->typeString();
     1377                const auto & _name = deterministic_output && isUnboundType(node) ? "[unbound]" : node->name;
    13871378                os << "instance of type " << _name
    13881379                   << " (" << (node->kind == ast::TypeDecl::Ftype ? "" : "not ") << "function type)";
     
    15111502                os << indent << "Types:" << endl;
    15121503                for ( const auto& i : *node ) {
    1513                         os << indent+1 << i.first.typeString() << " -> ";
     1504                        os << indent+1 << i.first << " -> ";
    15141505                        indent += 2;
    15151506                        safe_print( i.second );
     1507                        indent -= 2;
     1508                        os << endl;
     1509                }
     1510                os << indent << "Non-types:" << endl;
     1511                for ( auto i = node->beginVar(); i != node->endVar(); ++i ) {
     1512                        os << indent+1 << i->first << " -> ";
     1513                        indent += 2;
     1514                        safe_print( i->second );
    15161515                        indent -= 2;
    15171516                        os << endl;
  • src/AST/SymbolTable.cpp

    r2b4daf2 r42f6e07  
    414414
    415415void SymbolTable::addFunction( const FunctionDecl * func ) {
    416         for (auto & td : func->type_params) {
    417                 addType(td);
    418         }
    419         for (auto & asst : func->assertions) {
    420                 addId(asst);
    421         }
    422         // addTypes( func->type->forall );
     416        addTypes( func->type->forall );
    423417        addIds( func->returns );
    424418        addIds( func->params );
  • src/AST/Type.cpp

    r2b4daf2 r42f6e07  
    2121
    2222#include "Decl.hpp"
     23#include "ForallSubstitutor.hpp" // for substituteForall
    2324#include "Init.hpp"
    2425#include "Common/utility.h"      // for copy, move
     
    9192// GENERATED END
    9293
     94// --- ParameterizedType
     95
     96void FunctionType::initWithSub(
     97        const FunctionType & o, Pass< ForallSubstitutor > & sub
     98) {
     99        forall = sub.core( o.forall );
     100}
     101
    93102// --- FunctionType
     103
     104
     105FunctionType::FunctionType( const FunctionType & o )
     106: Type( o.qualifiers, copy( o.attributes ) ), returns(), params(),
     107  isVarArgs( o.isVarArgs ) {
     108        Pass< ForallSubstitutor > sub;
     109        initWithSub( o, sub );           // initialize substitution map
     110        returns = sub.core( o.returns ); // apply to return and parameter types
     111        params = sub.core( o.params );
     112}
     113
    94114namespace {
    95115        bool containsTtype( const std::vector<ptr<Type>> & l ) {
     
    179199                // TODO: once TypeInstType representation is updated, it should properly check
    180200                // if the context id is filled. this is a temporary hack for now
    181                 return typeInst->formal_usage > 0;
     201                return isUnboundType(typeInst->name);
     202        }
     203        return false;
     204}
     205
     206bool isUnboundType(const std::string & tname) {
     207        // xxx - look for a type name produced by renameTyVars.
     208
     209        // TODO: once TypeInstType representation is updated, it should properly check
     210        // if the context id is filled. this is a temporary hack for now
     211        if (std::count(tname.begin(), tname.end(), '_') >= 3) {
     212                return true;
    182213        }
    183214        return false;
  • src/AST/Type.hpp

    r2b4daf2 r42f6e07  
    3636
    3737template< typename T > class Pass;
     38
     39struct ForallSubstitutor;
    3840
    3941class Type : public Node {
     
    270272/// Type of a function `[R1, R2](*)(P1, P2, P3)`
    271273class FunctionType final : public Type {
    272 public:
    273         using ForallList = std::vector<ptr<TypeInstType>>;
    274         using AssertionList = std::vector<ptr<VariableExpr>>;
     274        protected:
     275        /// initializes forall with substitutor
     276        void initWithSub( const FunctionType & o, Pass< ForallSubstitutor > & sub );
     277public:
     278        using ForallList = std::vector<ptr<TypeDecl>>;
    275279        ForallList forall;
    276         AssertionList assertions;
    277280
    278281        std::vector<ptr<Type>> returns;
     
    289292        : Type(q), returns(), params(), isVarArgs(va) {}
    290293
    291         FunctionType( const FunctionType & o ) = default;
     294        FunctionType( const FunctionType & o );
    292295
    293296        /// true if either the parameters or return values contain a tttype
     
    394397public:
    395398        readonly<TypeDecl> base;
    396         // previously from renameTyVars; now directly use integer fields instead of synthesized strings
    397         // a nonzero value of formal_usage indicates a formal type (only used in function type)
    398         // a zero value of formal_usage indicates an actual type (referenced inside body of parametric structs and functions)
    399399        TypeDecl::Kind kind;
    400         int formal_usage = 0;
    401         int expr_id = 0;
    402 
    403         // compact representation used for map lookups.
    404         struct TypeEnvKey {
    405                 const TypeDecl * base;
    406                 int formal_usage;
    407                 int expr_id;
    408 
    409                 TypeEnvKey() = default;
    410                 TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0): base(base), formal_usage(formal_usage), expr_id(expr_id) {}
    411                 TypeEnvKey(const TypeInstType & inst): base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {}
    412                 std::string typeString() const { return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + base->name; }
    413                 bool operator==(const TypeEnvKey & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
    414 
    415         };
    416 
    417         bool operator==(const TypeInstType & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
    418400
    419401        TypeInstType(
     
    427409        TypeInstType( const TypeInstType & o ) = default;
    428410
    429         TypeInstType( const TypeEnvKey & key )
    430         : BaseInstType(key.base->name), base(key.base), kind(key.base->kind), formal_usage(key.formal_usage), expr_id(key.expr_id) {}
    431 
    432411        /// sets `base`, updating `kind` correctly
    433412        void set_base( const TypeDecl * );
     
    439418
    440419        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    441 
    442         std::string typeString() const {
    443                 if (formal_usage > 0) return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + name;
    444                 else return name;
    445         }
    446420private:
    447421        TypeInstType * clone() const override { return new TypeInstType{ *this }; }
     
    536510
    537511bool isUnboundType(const Type * type);
    538 
    539 }
    540 
    541 namespace std {
    542         template<>
    543         struct hash<typename ast::TypeInstType::TypeEnvKey> {
    544                 size_t operator() (const ast::TypeInstType::TypeEnvKey & x) const {
    545                         const size_t p = 1000007;
    546                         size_t res = reinterpret_cast<size_t>(x.base);
    547                         res = p * res + x.formal_usage;
    548                         res = p * res + x.expr_id;
    549                         return res;
    550                 }
    551         };
     512bool isUnboundType(const std::string & tname);
     513
    552514}
    553515
  • src/AST/TypeEnvironment.cpp

    r2b4daf2 r42f6e07  
    5252        for ( const auto & i : open ) {
    5353                if ( first ) { first = false; } else { out << ' '; }
    54                 out << i.first.typeString() << "(" << i.second << ")";
     54                out << i.first << "(" << i.second << ")";
    5555        }
    5656}
     
    6262                if(first) first = false;
    6363                else out << " ";
    64 
    65                 if( deterministic_output ) out << "[unbound]";
    66                 else out << "_" << var.formal_usage << "_" << var.expr_id << "_";
    67 
    68                 out << var.base->name;
     64                if( deterministic_output && isUnboundType(var) ) out << "[unbound]";
     65                else out << var;
    6966        }
    7067        out << ")";
     
    8279}
    8380
    84 const EqvClass * TypeEnvironment::lookup( const TypeInstType::TypeEnvKey & var ) const {
     81const EqvClass * TypeEnvironment::lookup( const std::string & var ) const {
    8582        for ( ClassList::const_iterator i = env.begin(); i != env.end(); ++i ) {
    8683                if ( i->vars.find( var ) != i->vars.end() ) return &*i;
     
    109106
    110107void TypeEnvironment::add( const FunctionType::ForallList & tyDecls ) {
    111         for ( auto & tyDecl : tyDecls ) {
     108        for ( const TypeDecl * tyDecl : tyDecls ) {
    112109                env.emplace_back( tyDecl );
    113110        }
     
    122119void TypeEnvironment::writeToSubstitution( TypeSubstitution & sub ) const {
    123120        for ( const auto & clz : env ) {
    124                 TypeInstType::TypeEnvKey clzRep;
    125                 bool first = true;
     121                std::string clzRep;
    126122                for ( const auto & var : clz.vars ) {
    127123                        if ( clz.bound ) {
    128124                                sub.add( var, clz.bound );
    129                         } else if ( first ) {
     125                        } else if ( clzRep.empty() ) {
    130126                                clzRep = var;
    131                                 first = false;
    132127                        } else {
    133                                 sub.add( var, new TypeInstType{ clzRep } );
     128                                sub.add( var, new TypeInstType{ clzRep, clz.data.kind } );
    134129                        }
    135130                }
     
    146141        struct Occurs : public ast::WithVisitorRef<Occurs> {
    147142                bool result;
    148                 std::unordered_set< TypeInstType::TypeEnvKey > vars;
     143                std::set< std::string > vars;
    149144                const TypeEnvironment & tenv;
    150145
    151                 Occurs( const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env )
     146                Occurs( const std::string & var, const TypeEnvironment & env )
    152147                : result( false ), vars(), tenv( env ) {
    153148                        if ( const EqvClass * clz = tenv.lookup( var ) ) {
     
    159154
    160155                void previsit( const TypeInstType * typeInst ) {
    161                         if ( vars.count( *typeInst ) ) {
     156                        if ( vars.count( typeInst->name ) ) {
    162157                                result = true;
    163                         } else if ( const EqvClass * clz = tenv.lookup( *typeInst ) ) {
     158                        } else if ( const EqvClass * clz = tenv.lookup( typeInst->name ) ) {
    164159                                if ( clz->bound ) {
    165160                                        clz->bound->accept( *visitor );
     
    170165
    171166        /// true if `var` occurs in `ty` under `env`
    172         bool occurs( const Type * ty, const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env ) {
     167        bool occurs( const Type * ty, const std::string & var, const TypeEnvironment & env ) {
    173168                Pass<Occurs> occur{ var, env };
    174169                maybe_accept( ty, occur );
     
    285280        // remove references from bound type, so that type variables can only bind to value types
    286281        ptr<Type> target = bindTo->stripReferences();
    287         auto tyvar = open.find( *typeInst );
     282        auto tyvar = open.find( typeInst->name );
    288283        assert( tyvar != open.end() );
    289284        if ( ! tyVarCompatible( tyvar->second, target ) ) return false;
    290         if ( occurs( target, *typeInst, *this ) ) return false;
    291 
    292         auto it = internal_lookup( *typeInst );
     285        if ( occurs( target, typeInst->name, *this ) ) return false;
     286
     287        auto it = internal_lookup( typeInst->name );
    293288        if ( it != env.end() ) {
    294289                if ( it->bound ) {
     
    313308        } else {
    314309                env.emplace_back(
    315                         *typeInst, target, widen.first && widen.second, data );
     310                        typeInst->name, target, widen.first && widen.second, data );
    316311        }
    317312        return true;
     
    323318                WidenMode widen, const SymbolTable & symtab
    324319) {
    325         auto c1 = internal_lookup( *var1 );
    326         auto c2 = internal_lookup( *var2 );
     320        auto c1 = internal_lookup( var1->name );
     321        auto c2 = internal_lookup( var2->name );
    327322
    328323        // exit early if variables already bound together
     
    338333        if ( c1 != env.end() ) {
    339334                if ( c1->bound ) {
    340                         if ( occurs( c1->bound, *var2, *this ) ) return false;
     335                        if ( occurs( c1->bound, var2->name, *this ) ) return false;
    341336                        type1 = c1->bound;
    342337                }
     
    345340        if ( c2 != env.end() ) {
    346341                if ( c2->bound ) {
    347                         if ( occurs( c2->bound, *var1, *this ) ) return false;
     342                        if ( occurs( c2->bound, var1->name, *this ) ) return false;
    348343                        type2 = c2->bound;
    349344                }
     
    383378        } else if ( c1 != env.end() ) {
    384379                // var2 unbound, add to env[c1]
    385                 c1->vars.emplace( *var2 );
     380                c1->vars.emplace( var2->name );
    386381                c1->allowWidening = widen1;
    387382                c1->data.isComplete |= data.isComplete;
    388383        } else if ( c2 != env.end() ) {
    389384                // var1 unbound, add to env[c2]
    390                 c2->vars.emplace( *var1 );
     385                c2->vars.emplace( var1->name );
    391386                c2->allowWidening = widen2;
    392387                c2->data.isComplete |= data.isComplete;
    393388        } else {
    394389                // neither var bound, create new class
    395                 env.emplace_back( *var1, *var2, widen1 && widen2, data );
     390                env.emplace_back( var1->name, var2->name, widen1 && widen2, data );
    396391        }
    397392
     
    457452}
    458453
    459 TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const TypeInstType::TypeEnvKey & var ) {
     454TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const std::string & var ) {
    460455        for ( ClassList::iterator i = env.begin(); i != env.end(); ++i ) {
    461456                if ( i->vars.count( var ) ) return i;
  • src/AST/TypeEnvironment.hpp

    r2b4daf2 r42f6e07  
    5555/// recorded. More investigation is needed.
    5656struct AssertCompare {
    57         bool operator()( const VariableExpr * d1, const VariableExpr * d2 ) const {
    58                 int cmp = d1->var->name.compare( d2->var->name );
    59                 return cmp < 0 || ( cmp == 0 && d1->result < d2->result );
     57        bool operator()( const DeclWithType * d1, const DeclWithType * d2 ) const {
     58                int cmp = d1->name.compare( d2->name );
     59                return cmp < 0 || ( cmp == 0 && d1->get_type() < d2->get_type() );
    6060        }
    6161};
     
    7070
    7171/// Set of assertions pending satisfaction
    72 using AssertionSet = std::map< const VariableExpr *, AssertionSetValue, AssertCompare >;
     72using AssertionSet = std::map< readonly<DeclWithType>, AssertionSetValue, AssertCompare >;
    7373
    7474/// Set of open variables
    75 using OpenVarSet = std::unordered_map< TypeInstType::TypeEnvKey, TypeDecl::Data >;
     75using OpenVarSet = std::unordered_map< std::string, TypeDecl::Data >;
    7676
    7777/// Merges one set of open vars into another
     
    8989/// they bind to.
    9090struct EqvClass {
    91         std::unordered_set< TypeInstType::TypeEnvKey > vars;
     91        std::set< std::string > vars;
    9292        ptr<Type> bound;
    9393        bool allowWidening;
     
    101101
    102102        /// Singleton class constructor from TypeDecl
    103         EqvClass( const TypeInstType * inst )
    104         : vars{ *inst }, bound(), allowWidening( true ), data( inst->base ) {}
     103        EqvClass( const TypeDecl * decl )
     104        : vars{ decl->name }, bound(), allowWidening( true ), data( decl ) {}
    105105
    106106        /// Singleton class constructor from substitution
    107         EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b )
     107        EqvClass( const std::string & v, const Type * b )
    108108        : vars{ v }, bound( b ), allowWidening( false ), data( TypeDecl::Dtype, false ) {}
    109109
    110110        /// Single-var constructor (strips qualifiers from bound type)
    111         EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b, bool w, const TypeDecl::Data & d )
     111        EqvClass( const std::string & v, const Type * b, bool w, const TypeDecl::Data & d )
    112112        : vars{ v }, bound( b ), allowWidening( w ), data( d ) {
    113113                reset_qualifiers( bound );
     
    115115
    116116        /// Double-var constructor
    117         EqvClass( const TypeInstType::TypeEnvKey & v, const TypeInstType::TypeEnvKey & u, bool w, const TypeDecl::Data & d )
     117        EqvClass( const std::string & v, const std::string & u, bool w, const TypeDecl::Data & d )
    118118        : vars{ v, u }, bound(), allowWidening( w ), data( d ) {}
    119119
     
    131131public:
    132132        /// Finds the equivalence class containing a variable; nullptr for none such
    133         const EqvClass * lookup( const TypeInstType::TypeEnvKey & var ) const;
     133        const EqvClass * lookup( const std::string & var ) const;
    134134
    135135        /// Add a new equivalence class for each type variable
     
    207207
    208208        /// Private lookup API; returns array index of string, or env.size() for not found
    209         ClassList::iterator internal_lookup( const TypeInstType::TypeEnvKey & );
     209        ClassList::iterator internal_lookup( const std::string & );
    210210};
    211211
  • src/AST/TypeSubstitution.cpp

    r2b4daf2 r42f6e07  
    3939void TypeSubstitution::initialize( const TypeSubstitution &src, TypeSubstitution &dest ) {
    4040        dest.typeEnv.clear();
     41        dest.varEnv.clear();
    4142        dest.add( src );
    4243}
     
    4647                typeEnv[ i->first ] = i->second;
    4748        } // for
    48 }
    49 
    50 void TypeSubstitution::add( const TypeInstType * formalType, const Type *actualType ) {
    51         typeEnv[ *formalType ] = actualType;
    52 }
    53 
    54 void TypeSubstitution::add( const TypeInstType::TypeEnvKey & key, const Type * actualType) {
    55         typeEnv[ key ] = actualType;
    56 }
    57 
    58 void TypeSubstitution::remove( const TypeInstType * formalType ) {
    59         TypeEnvType::iterator i = typeEnv.find( *formalType );
     49        for ( VarEnvType::const_iterator i = other.varEnv.begin(); i != other.varEnv.end(); ++i ) {
     50                varEnv[ i->first ] = i->second;
     51        } // for
     52}
     53
     54void TypeSubstitution::add( std::string formalType, const Type *actualType ) {
     55        typeEnv[ formalType ] = actualType;
     56}
     57
     58void TypeSubstitution::addVar( std::string formalExpr, const Expr *actualExpr ) {
     59        varEnv[ formalExpr ] = actualExpr;
     60}
     61
     62void TypeSubstitution::remove( std::string formalType ) {
     63        TypeEnvType::iterator i = typeEnv.find( formalType );
    6064        if ( i != typeEnv.end() ) {
    61                 typeEnv.erase( *formalType );
    62         } // if
    63 }
    64 
    65 const Type *TypeSubstitution::lookup( const TypeInstType * formalType ) const {
    66         TypeEnvType::const_iterator i = typeEnv.find( *formalType );
     65                typeEnv.erase( formalType );
     66        } // if
     67}
     68
     69const Type *TypeSubstitution::lookup( std::string formalType ) const {
     70        TypeEnvType::const_iterator i = typeEnv.find( formalType );
    6771
    6872        // break on not in substitution set
     
    7175        // attempt to transitively follow TypeInstType links.
    7276        while ( const TypeInstType *actualType = i->second.as<TypeInstType>()) {
     77                const std::string& typeName = actualType->name;
     78
    7379                // break cycles in the transitive follow
    74                 if ( *formalType == *actualType ) break;
     80                if ( formalType == typeName ) break;
    7581
    7682                // Look for the type this maps to, returning previous mapping if none-such
    77                 i = typeEnv.find( *actualType );
     83                i = typeEnv.find( typeName );
    7884                if ( i == typeEnv.end() ) return actualType;
    7985        }
     
    8490
    8591bool TypeSubstitution::empty() const {
    86         return typeEnv.empty();
     92        return typeEnv.empty() && varEnv.empty();
    8793}
    8894
     
    9298                TypeSubstitution * newEnv;
    9399                EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
    94                 void previsit( FunctionType * ftype ) {
     100                void previsit( TypeDecl * tyDecl ) {
    95101                        // transfer known bindings for seen type variables
    96                         for (auto & formal : ftype->forall) {
    97                                 if ( const Type * t = env->lookup( formal ) ) {
    98                                         newEnv->add( formal, t );
    99                                 }
     102                        if ( const Type * t = env->lookup( tyDecl->name ) ) {
     103                                newEnv->add( tyDecl->name, t );
    100104                        }
    101105                }
     
    126130
    127131const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
    128         BoundVarsType::const_iterator bound = boundVars.find( *inst );
     132        BoundVarsType::const_iterator bound = boundVars.find( inst->name );
    129133        if ( bound != boundVars.end() ) return inst;
    130134
    131         TypeEnvType::const_iterator i = sub.typeEnv.find( *inst );
     135        TypeEnvType::const_iterator i = sub.typeEnv.find( inst->name );
    132136        if ( i == sub.typeEnv.end() ) {
    133137                return inst;
     
    137141                // TODO: investigate preventing type variables from being bound to themselves in the first place.
    138142                if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
    139                         if ( *inst == *replacement ) {
     143                        if ( inst->name == replacement->name ) {
    140144                                return inst;
    141145                        }
     
    152156}
    153157
     158const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) {
     159        VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
     160        if ( i == sub.varEnv.end() ) {
     161                return nameExpr;
     162        } else {
     163                subCount++;
     164                return i->second;
     165        } // if
     166}
     167
    154168void TypeSubstitution::Substituter::previsit( const FunctionType * ptype ) {
    155169        GuardValue( boundVars );
    156170        // bind type variables from forall-qualifiers
    157171        if ( freeOnly ) {
    158                 for ( auto & tyvar : ptype->forall ) {
    159                                 boundVars.insert( *tyvar );
     172                for ( const TypeDecl * tyvar : ptype->forall ) {
     173                                boundVars.insert( tyvar->name );
    160174                } // for
    161175        } // if
    162176}
    163177
    164 /*
    165178void TypeSubstitution::Substituter::handleAggregateType( const BaseInstType * type ) {
    166179        GuardValue( boundVars );
     
    171184                        if ( ! type->params.empty() ) {
    172185                                for ( const TypeDecl * tyvar : decl->params ) {
    173                                         boundVars.insert( *tyvar );
     186                                        boundVars.insert( tyvar->name );
    174187                                } // for
    175188                        } // if
     
    185198        handleAggregateType( aggregateUseType );
    186199}
    187 */
    188200
    189201} // namespace ast
  • src/AST/TypeSubstitution.hpp

    r2b4daf2 r42f6e07  
    6969        }
    7070
    71         void add( const TypeInstType * formalType, const Type *actualType );
    72         void add( const TypeInstType::TypeEnvKey & key, const Type *actualType );
     71        void add( std::string formalType, const Type *actualType );
    7372        void add( const TypeSubstitution &other );
    74         void remove( const TypeInstType * formalType );
    75         const Type *lookup( const TypeInstType * formalType ) const;
     73        void remove( std::string formalType );
     74        const Type *lookup( std::string formalType ) const;
    7675        bool empty() const;
     76
     77        void addVar( std::string formalExpr, const Expr *actualExpr );
    7778
    7879        template< typename FormalIterator, typename ActualIterator >
     
    100101        friend class Pass;
    101102
    102         typedef std::unordered_map< TypeInstType::TypeEnvKey, ptr<Type> > TypeEnvType;
     103        typedef std::unordered_map< std::string, ptr<Type> > TypeEnvType;
     104        typedef std::unordered_map< std::string, ptr<Expr> > VarEnvType;
    103105        TypeEnvType typeEnv;
     106        VarEnvType varEnv;
    104107
    105108  public:
     
    110113        auto   end() const -> decltype( typeEnv.  end() ) { return typeEnv.  end(); }
    111114
     115        auto beginVar()       -> decltype( varEnv.begin() ) { return varEnv.begin(); }
     116        auto   endVar()       -> decltype( varEnv.  end() ) { return varEnv.  end(); }
     117        auto beginVar() const -> decltype( varEnv.begin() ) { return varEnv.begin(); }
     118        auto   endVar() const -> decltype( varEnv.  end() ) { return varEnv.  end(); }
    112119};
    113120
    114 // this is the only place where type parameters outside a function formal may be substituted.
    115121template< typename FormalIterator, typename ActualIterator >
    116122void TypeSubstitution::add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
     
    123129                        if ( const TypeExpr *actual = actualIt->template as<TypeExpr>() ) {
    124130                                if ( formal->name != "" ) {
    125                                         typeEnv[ formal ] = actual->type;
     131                                        typeEnv[ formal->name ] = actual->type;
    126132                                } // if
    127133                        } else {
     
    129135                        } // if
    130136                } else {
    131                        
     137                        // TODO: type check the formal and actual parameters
     138                        if ( (*formalIt)->name != "" ) {
     139                                varEnv[ (*formalIt)->name ] = *actualIt;
     140                        } // if
    132141                } // if
    133142        } // for
    134143}
    135 
    136 
    137144
    138145template< typename FormalIterator, typename ActualIterator >
     
    140147        add( formalBegin, formalEnd, actualBegin );
    141148}
    142 
    143149
    144150} // namespace ast
     
    158164
    159165                const Type * postvisit( const TypeInstType * aggregateUseType );
     166                const Expr * postvisit( const NameExpr * nameExpr );
    160167
    161168                /// Records type variable bindings from forall-statements
    162169                void previsit( const FunctionType * type );
    163170                /// Records type variable bindings from forall-statements and instantiations of generic types
    164                 // void handleAggregateType( const BaseInstType * type );
    165 
    166                 // void previsit( const StructInstType * aggregateUseType );
    167                 // void previsit( const UnionInstType * aggregateUseType );
     171                void handleAggregateType( const BaseInstType * type );
     172
     173                void previsit( const StructInstType * aggregateUseType );
     174                void previsit( const UnionInstType * aggregateUseType );
    168175
    169176                const TypeSubstitution & sub;
    170177                int subCount = 0;
    171178                bool freeOnly;
    172                 typedef std::unordered_set< TypeInstType::TypeEnvKey > BoundVarsType;
     179                typedef std::unordered_set< std::string > BoundVarsType;
    173180                BoundVarsType boundVars;
    174181
  • src/AST/module.mk

    r2b4daf2 r42f6e07  
    3333        AST/Expr.cpp \
    3434        AST/Expr.hpp \
     35        AST/ForallSubstitutionTable.cpp \
     36        AST/ForallSubstitutionTable.hpp \
     37        AST/ForallSubstitutor.hpp \
    3538        AST/FunctionSpec.hpp \
    3639        AST/Fwd.hpp \
  • src/GenPoly/GenPoly.cc

    r2b4daf2 r42f6e07  
    115115                if (!env) return type;
    116116                if (auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) {
    117                         auto newType = env->lookup(typeInst);
     117                        auto newType = env->lookup(typeInst->name);
    118118                        if (newType) return newType;
    119119                }
     
    172172
    173173                if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
    174                         return tyVars.find(typeInst->typeString()) != tyVars.end() ? type : nullptr;
     174                        return tyVars.find(typeInst->name) != tyVars.end() ? type : nullptr;
    175175                } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
    176176                        return isPolyType( arrayType->base, env );
     
    552552        }
    553553
    554         void addToTyVarMap( const ast::TypeInstType * tyVar, TyVarMap & tyVarMap) {
    555                 tyVarMap.insert(tyVar->typeString(), convData(ast::TypeDecl::Data{tyVar->base}));
     554        void addToTyVarMap( const ast::TypeDecl * tyVar, TyVarMap & tyVarMap) {
     555                tyVarMap.insert(tyVar->name, convData(ast::TypeDecl::Data{tyVar}));
    556556        }
    557557
  • src/InitTweak/GenInit.cc

    r2b4daf2 r42f6e07  
    122122        };
    123123
    124         struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {
    125                 /// hoist dimension from array types in object declaration so that it uses a single
    126                 /// const variable of type size_t, so that side effecting array dimensions are only
    127                 /// computed once.
    128                 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
    129 
    130                 void premutate( ObjectDecl * objectDecl );
    131                 DeclarationWithType * postmutate( ObjectDecl * objectDecl );
    132                 void premutate( FunctionDecl *functionDecl );
    133                 // should not traverse into any of these declarations to find objects
    134                 // that need to be constructed or destructed
    135                 void premutate( AggregateDecl * ) { visit_children = false; }
    136                 void premutate( NamedTypeDecl * ) { visit_children = false; }
    137                 void premutate( FunctionType * ) { visit_children = false; }
    138 
    139                 void hoist( Type * type );
    140 
    141                 Type::StorageClasses storageClasses;
    142                 bool inFunction = false;
    143         };
    144 
    145124        void genInit( std::list< Declaration * > & translationUnit ) {
    146                 if (!useNewAST) {
    147                         HoistArrayDimension::hoistArrayDimension( translationUnit );
    148                 }
    149                 else {
    150                         HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );
    151                 }
     125                HoistArrayDimension::hoistArrayDimension( translationUnit );
    152126                fixReturnStatements( translationUnit );
    153127
     
    222196
    223197                        // need to resolve array dimensions in order to accurately determine if constexpr
    224                         ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
    225                         // array is variable-length when the dimension is not constexpr
    226                         arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
     198                        if (!useNewAST) {
     199                                ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
     200                                // array is variable-length when the dimension is not constexpr
     201                                arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
     202                        }
    227203                        // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
    228204                        // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
     
    242218
    243219        void HoistArrayDimension::premutate( FunctionDecl * ) {
    244                 GuardValue( inFunction );
    245                 inFunction = true;
    246         }
    247 
    248         // precompute array dimension expression, because constructor generation may duplicate it,
    249         // which would be incorrect if it is a side-effecting computation.
    250         void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
    251                 PassVisitor<HoistArrayDimension_NoResolve> hoister;
    252                 mutateAll( translationUnit, hoister );
    253         }
    254 
    255         void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) {
    256                 GuardValue( storageClasses );
    257                 storageClasses = objectDecl->get_storageClasses();
    258         }
    259 
    260         DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) {
    261                 hoist( objectDecl->get_type() );
    262                 return objectDecl;
    263         }
    264 
    265         void HoistArrayDimension_NoResolve::hoist( Type * type ) {
    266                 // if in function, generate const size_t var
    267                 static UniqueName dimensionName( "_array_dim" );
    268 
    269                 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
    270                 if ( ! inFunction ) return;
    271                 if ( storageClasses.is_static ) return;
    272 
    273                 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    274                         if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
    275                         // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
    276                         // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
    277                         // still try to detect constant expressions
    278                         if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
    279 
    280                         ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
    281                         arrayDimension->get_type()->set_const( true );
    282 
    283                         arrayType->set_dimension( new VariableExpr( arrayDimension ) );
    284                         declsToAddBefore.push_back( arrayDimension );
    285 
    286                         hoist( arrayType->get_base() );
    287                         return;
    288                 }
    289         }
    290 
    291         void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) {
    292220                GuardValue( inFunction );
    293221                inFunction = true;
  • src/ResolvExpr/AdjustExprType.cc

    r2b4daf2 r42f6e07  
    133133                const ast::Type * postvisit( const ast::TypeInstType * inst ) {
    134134                        // replace known function-type-variables with pointer-to-function
    135                         if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) {
     135                        if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
    136136                                if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
    137137                                        return new ast::PointerType{ inst };
  • src/ResolvExpr/CandidateFinder.cpp

    r2b4daf2 r42f6e07  
    212212                // mark type variable and specialization cost of forall clause
    213213                convCost.incVar( function->forall.size() );
    214                 convCost.decSpec( function->assertions.size() );
     214                for ( const ast::TypeDecl * td : function->forall ) {
     215                        convCost.decSpec( td->assertions.size() );
     216                }
    215217
    216218                return convCost;
     
    221223                ast::AssertionSet & need
    222224        ) {
    223                 for ( auto & tyvar : type->forall ) {
    224                         unifiableVars[ *tyvar ] = ast::TypeDecl::Data{ tyvar->base };
    225                 }
    226                 for ( auto & assn : type->assertions ) {
    227                         need[ assn ].isUsed = true;
     225                for ( const ast::TypeDecl * tyvar : type->forall ) {
     226                        unifiableVars[ tyvar->name ] = ast::TypeDecl::Data{ tyvar };
     227                        for ( const ast::DeclWithType * assn : tyvar->assertions ) {
     228                                need[ assn ].isUsed = true;
     229                        }
    228230                }
    229231        }
     
    905907                        // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
    906908                        // this means there exists ctor/assign functions with a tuple as first parameter.
    907                         ResolvMode mode = {
    908                                 true, // adjust
    909                                 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
    910                                 selfFinder.candidates.empty() // failfast if other options are not found
    911                         };
    912                         funcFinder.find( untypedExpr->func, mode );
     909                        funcFinder.find( untypedExpr->func, selfFinder.candidates.empty() ? ResolvMode::withAdjustment() : ResolvMode::withoutFailFast() );
    913910                        // short-circuit if no candidates
    914911                        // if ( funcFinder.candidates.empty() ) return;
     
    956953                                                auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
    957954                                        ) {
    958                                                 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
     955                                                if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
    959956                                                        if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    960957                                                                CandidateRef newFunc{ new Candidate{ *func } };
     
    10801077                        assert( toType );
    10811078                        toType = resolveTypeof( toType, symtab );
    1082                         // toType = SymTab::validateType( castExpr->location, toType, symtab );
     1079                        toType = SymTab::validateType( castExpr->location, toType, symtab );
    10831080                        toType = adjustExprType( toType, tenv, symtab );
    10841081
     
    11651162
    11661163                                        if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
    1167                                                 auto td = cand->env.lookup(*insttype);
     1164                                                auto td = cand->env.lookup(insttype->name);
    11681165                                                if(!td) { continue; }
    11691166                                                expr = td->bound.get();
     
    15711568                                // calculate target type
    15721569                                const ast::Type * toType = resolveTypeof( initAlt.type, symtab );
    1573                                 // toType = SymTab::validateType( initExpr->location, toType, symtab );
     1570                                toType = SymTab::validateType( initExpr->location, toType, symtab );
    15741571                                toType = adjustExprType( toType, tenv, symtab );
    15751572                                // The call to find must occur inside this loop, otherwise polymorphic return
  • src/ResolvExpr/CastCost.cc

    r2b4daf2 r42f6e07  
    202202) {
    203203        if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    204                 if ( const ast::EqvClass * eqvClass = env.lookup( *typeInst ) ) {
     204                if ( const ast::EqvClass * eqvClass = env.lookup( typeInst->name ) ) {
    205205                        // check cast cost against bound type, if present
    206206                        if ( eqvClass->bound ) {
  • src/ResolvExpr/CommonType.cc

    r2b4daf2 r42f6e07  
    713713                        const ast::Type * base = oPtr->base;
    714714                        if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) {
    715                                 auto entry = open.find( *var );
     715                                auto entry = open.find( var->name );
    716716                                if ( entry != open.end() ) {
    717717                                        ast::AssertionSet need, have;
  • src/ResolvExpr/ConversionCost.cc

    r2b4daf2 r42f6e07  
    498498) {
    499499        if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    500                 if ( const ast::EqvClass * eqv = env.lookup( *inst ) ) {
     500                if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) {
    501501                        if ( eqv->bound ) {
    502502                                return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env );
     
    675675
    676676void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) {
    677         if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) {
     677        if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
    678678                cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env );
    679679        } else if ( const ast::TypeInstType * dstAsInst =
    680680                        dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    681                 if ( *typeInstType == *dstAsInst ) {
     681                if ( typeInstType->name == dstAsInst->name ) {
    682682                        cost = Cost::zero;
    683683                }
  • src/ResolvExpr/FindOpenVars.cc

    r2b4daf2 r42f6e07  
    112112                                // mark open/closed variables
    113113                                if ( nextIsOpen ) {
    114                                         for ( auto & decl : type->forall ) {
    115                                                 open[ *decl ] = ast::TypeDecl::Data{ decl->base };
    116                                         }
    117                                         for ( auto & assert : type->assertions ) {
    118                                                 need[ assert ].isUsed = false;
     114                                        for ( const ast::TypeDecl * decl : type->forall ) {
     115                                                open[ decl->name ] = ast::TypeDecl::Data{ decl };
     116                                                for ( const ast::DeclWithType * assert : decl->assertions ) {
     117                                                        need[ assert ].isUsed = false;
     118                                                }
    119119                                        }
    120120                                } else {
    121                                         for ( auto & decl : type->forall ) {
    122                                                 closed[ *decl ] = ast::TypeDecl::Data{ decl->base };   
    123                                         }
    124                                         for ( auto & assert : type->assertions ) {
    125                                                 have[ assert ].isUsed = false;
     121                                        for ( const ast::TypeDecl * decl : type->forall ) {
     122                                                closed[ decl->name ] = ast::TypeDecl::Data{ decl };
     123                                                for ( const ast::DeclWithType * assert : decl->assertions ) {
     124                                                        have[ assert ].isUsed = false;
     125                                                }
    126126                                        }
    127127                                }
  • src/ResolvExpr/PolyCost.cc

    r2b4daf2 r42f6e07  
    6868
    6969        void previsit( const ast::TypeInstType * type ) {
    70                 if ( const ast::EqvClass * eqv = env_.lookup( *type ) ) /* && */ if ( eqv->bound ) {
     70                if ( const ast::EqvClass * eqv = env_.lookup( type->name ) ) /* && */ if ( eqv->bound ) {
    7171                        if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) {
    7272                                if ( symtab.lookupType( otherType->name ) ) {
  • src/ResolvExpr/PtrsAssignable.cc

    r2b4daf2 r42f6e07  
    134134        }
    135135        void postvisit( const ast::TypeInstType * inst ) {
    136                 if ( const ast::EqvClass * eqv = typeEnv.lookup( *inst ) ) {
     136                if ( const ast::EqvClass * eqv = typeEnv.lookup( inst->name ) ) {
    137137                        if ( eqv->bound ) {
    138138                                // T * = S * for any S depends on the type bound to T
     
    146146                const ast::TypeEnvironment & env ) {
    147147        if ( const ast::TypeInstType * dstAsInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    148                 if ( const ast::EqvClass * eqv = env.lookup( *dstAsInst ) ) {
     148                if ( const ast::EqvClass * eqv = env.lookup( dstAsInst->name ) ) {
    149149                        return ptrsAssignable( src, eqv->bound, env );
    150150                }
  • src/ResolvExpr/PtrsCastable.cc

    r2b4daf2 r42f6e07  
    180180                                        }
    181181                                }
    182                         } else if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
     182                        } else if ( const ast::EqvClass * eqvClass = env.lookup( inst->name ) ) {
    183183                                if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
    184184                                        return -1;
     
    283283) {
    284284        if ( auto inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    285                 if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
     285                if ( const ast::EqvClass * eqvClass = env.lookup( inst->name ) ) {
    286286                        return ptrsAssignable( src, eqvClass->bound, env );
    287287                }
  • src/ResolvExpr/RenameVars.cc

    r2b4daf2 r42f6e07  
    1919#include <utility>                 // for pair
    2020
     21#include "AST/ForallSubstitutionTable.hpp"
    2122#include "AST/Pass.hpp"
    2223#include "AST/Type.hpp"
     
    3839                int level = 0;
    3940                int resetCount = 0;
     41                ScopedMap< std::string, std::string > nameMap;
     42        public:
     43                ast::ForallSubstitutionTable subs;
    4044
    41                 int next_expr_id = 1;
    42                 int next_usage_id = 1;
    43                 ScopedMap< std::string, std::string > nameMap;
    44                 ScopedMap< std::string, ast::TypeInstType::TypeEnvKey > idMap;
    45         public:
    4645                void reset() {
    4746                        level = 0;
     
    5453                                type->name = it->second;
    5554                        }
    56                 }
    57 
    58                 void nextUsage() {
    59                         ++next_usage_id;
    6055                }
    6156
     
    8378
    8479                const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
     80                        // re-linking of base type handled by WithForallSubstitutor
     81
    8582                        // rename
    86                         auto it = idMap.find( type->name );
    87                         if ( it != idMap.end() ) {
    88                                 // unconditionally mutate because map will *always* have different name
    89                                 ast::TypeInstType * mut = ast::shallowCopy( type );
    90                                 // reconcile base node since some copies might have been made
    91                                 mut->base = it->second.base;
    92                                 mut->formal_usage = it->second.formal_usage;
    93                                 mut->expr_id = it->second.expr_id;
     83                        auto it = nameMap.find( type->name );
     84                        if ( it != nameMap.end() ) {
     85                                // unconditionally mutate because map will *always* have different name,
     86                                // if this mutates, will *always* have been mutated by ForallSubstitutor above
     87                                ast::TypeInstType * mut = ast::mutate( type );
     88                                mut->name = it->second;
    9489                    type = mut;
    9590                        }
     
    9893                }
    9994
    100                 const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
     95                const ast::FunctionType * openLevel( const ast::FunctionType * type ) {
    10196                        if ( type->forall.empty() ) return type;
    102                         idMap.beginScope();
     97
     98                        nameMap.beginScope();
    10399
    104100                        // Load new names from this forall clause and perform renaming.
    105                         auto mutType = ast::shallowCopy( type );
    106                         // assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
    107                         for ( auto & td : mutType->forall ) {
    108                                 auto mut = ast::shallowCopy( td.get() );
    109                                 // assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
     101                        auto mutType = ast::mutate( type );
     102                        assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
     103                        for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
     104                                assertf(dynamic_cast<ast::FunctionType *>(mutType), "renaming vars in non-function type");
     105                                std::ostringstream output;
     106                                output << "_" << resetCount << "_" << level << "_" << td->name;
     107                                std::string newname =  output.str();
     108                                nameMap[ td->name ] = newname;
     109                                ++level;
    110110
    111                                 if (mode == GEN_EXPR_ID) {
    112                                         mut->expr_id = next_expr_id;
    113                                         mut->formal_usage = -1;
    114                                         ++next_expr_id;
    115                                 }
    116                                 else if (mode == GEN_USAGE) {
    117                                         assertf(mut->expr_id, "unfilled expression id in generating candidate type");
    118                                         mut->formal_usage = next_usage_id;
    119                                 }
    120                                 else {
    121                                         assert(false);
    122                                 }
    123                                 idMap[ td->name ] = ast::TypeInstType::TypeEnvKey(*mut);
    124                                
    125                                 td = mut;
     111                                ast::TypeDecl * mutDecl = ast::mutate( td.get() );
     112                                assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
     113                                mutDecl->name = newname;
     114                                // assertion above means `td = mutDecl;` is unnecessary
    126115                        }
     116                        // assertion above means `type = mutType;` is unnecessary
    127117
    128                         return mutType;
     118                        return type;
    129119                }
    130120
    131121                void closeLevel( const ast::FunctionType * type ) {
    132122                        if ( type->forall.empty() ) return;
    133                         idMap.endScope();
     123
     124                        nameMap.endScope();
    134125                }
    135126        };
     
    151142        };
    152143
    153         struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
    154                 RenameMode mode;
     144        struct RenameVars_new /*: public ast::WithForallSubstitutor*/ {
     145                #warning when old RenameVars goes away, replace hack below with global pass inheriting from WithForallSubstitutor
     146                ast::ForallSubstitutionTable & subs = renaming.subs;
    155147
    156148                const ast::FunctionType * previsit( const ast::FunctionType * type ) {
    157                         return renaming.openLevel( type, mode );
     149                        return renaming.openLevel( type );
    158150                }
    159151
     
    171163
    172164                const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
    173                         if (mode == GEN_USAGE && !type->formal_usage) return type; // do not rename an actual type
    174165                        return renaming.rename( type );
    175166                }
     
    186177}
    187178
    188 const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) {
    189         // ast::Type *tc = ast::deepCopy(t);
     179const ast::Type * renameTyVars( const ast::Type * t ) {
     180        ast::Type *tc = ast::deepCopy(t);
    190181        ast::Pass<RenameVars_new> renamer;
    191         renamer.core.mode = mode;
    192         if (mode == GEN_USAGE && reset) {
    193                 renaming.nextUsage();
    194         }
    195         return t->accept( renamer );
     182//      return t->accept( renamer );
     183        return tc->accept( renamer );
    196184}
    197185
    198186void resetTyVarRenaming() {
    199187        renaming.reset();
    200         renaming.nextUsage();
    201188}
    202189
  • src/ResolvExpr/RenameVars.h

    r2b4daf2 r42f6e07  
    3030        /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
    3131        void renameTyVars( Type * );
    32 
    33         enum RenameMode {
    34                 GEN_USAGE, // for type in VariableExpr
    35                 GEN_EXPR_ID // for type in decl
    36         };
    37         const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true );
    38        
     32        const ast::Type * renameTyVars( const ast::Type * );
    3933
    4034        /// resets internal state of renamer to avoid overflow
    4135        void resetTyVarRenaming();
    42 
    43        
    4436} // namespace ResolvExpr
    4537
  • src/ResolvExpr/ResolvMode.h

    r2b4daf2 r42f6e07  
    2323                const bool failFast;         ///< Fail on no resulting alternatives? [true]
    2424
     25        private:
    2526                constexpr ResolvMode(bool a, bool p, bool ff)
    2627                : adjust(a), prune(p), failFast(ff) {}
    2728
     29        public:
    2830                /// Default settings
    2931                constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {}
  • src/ResolvExpr/ResolveAssertions.cc

    r2b4daf2 r42f6e07  
    397397
    398398        /// Limit to depth of recursion of assertion satisfaction
    399         static const int recursionLimit = 7;
     399        static const int recursionLimit = 4;
    400400        /// Maximum number of simultaneously-deferred assertions to attempt concurrent satisfaction of
    401401        static const int deferLimit = 10;
  • src/ResolvExpr/ResolveTypeof.cc

    r2b4daf2 r42f6e07  
    1515
    1616#include "ResolveTypeof.h"
    17 #include "RenameVars.h"
    1817
    1918#include <cassert>               // for assert
     
    219218                        mutDecl->mangleName = Mangle::mangle(mutDecl); // do not mangle unnamed variables
    220219               
    221                 mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID);
    222220                mutDecl->isTypeFixed = true;
    223221                return mutDecl;
  • src/ResolvExpr/Resolver.cc

    r2b4daf2 r42f6e07  
    986986                };
    987987        } // anonymous namespace
     988
    988989        /// Check if this expression is or includes a deleted expression
    989990        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
     
    11511152                        const ast::Expr * untyped, const ast::SymbolTable & symtab
    11521153                ) {
     1154                        resetTyVarRenaming();
    11531155                        ast::TypeEnvironment env;
    11541156                        ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, symtab, env );
     
    13101312        }
    13111313
    1312         const ast::Expr * resolveStmtExpr(
     1314        ast::ptr< ast::Expr > resolveStmtExpr(
    13131315                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab
    13141316        ) {
    13151317                assert( stmtExpr );
    13161318                ast::Pass< Resolver_new > resolver{ symtab };
    1317                 auto ret = mutate(stmtExpr->accept(resolver));
    1318                 strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
     1319                ast::ptr< ast::Expr > ret = stmtExpr;
     1320                ret = ret->accept( resolver );
     1321                strict_dynamic_cast< ast::StmtExpr * >( ret.get_and_mutate() )->computeResult();
    13191322                return ret;
    13201323        }
     
    13721375                        }
    13731376
    1374                         // handle assertions
     1377                        // handle assertions. (seems deep)
    13751378
    13761379                        symtab.enterScope();
    1377                         mutType->forall.clear();
    1378                         mutType->assertions.clear();
    1379                         for (auto & typeParam : mutDecl->type_params) {
    1380                                 symtab.addType(typeParam);
    1381                                 mutType->forall.emplace_back(new ast::TypeInstType(typeParam->name, typeParam));
    1382                         }
    1383                         for (auto & asst : mutDecl->assertions) {
    1384                                 asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab);
    1385                                 symtab.addId(asst);
    1386                                 mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
     1380                        for (auto & typeParam : mutType->forall) {
     1381                                auto mutParam = typeParam.get_and_mutate();
     1382                                symtab.addType(mutParam);
     1383                                for (auto & asst : mutParam->assertions) {
     1384                                        asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab);
     1385                                        symtab.addId(asst);
     1386                                }
     1387                                typeParam = mutParam;
    13871388                        }
    13881389
     
    14061407                        mutType->returns = std::move(returnTypes);
    14071408
    1408                         auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
    1409 
    14101409                        std::list<ast::ptr<ast::Stmt>> newStmts;
    14111410                        resolveWithExprs (mutDecl->withExprs, newStmts);
     
    14191418                        symtab.leaveScope();
    14201419
    1421                         mutDecl->type = renamedType;
    14221420                        mutDecl->mangleName = Mangle::mangle(mutDecl);
    14231421                        mutDecl->isTypeFixed = true;
     
    15361534        const PtrType * handlePtrType( const PtrType * type, const ast::SymbolTable & symtab ) {
    15371535                if ( type->dimension ) {
    1538                         ast::ptr< ast::Type > sizeType = ast::sizeType;
     1536                        #warning should use new equivalent to Validate::SizeType rather than sizeType here
     1537                        ast::ptr< ast::Type > sizeType = new ast::BasicType{ ast::BasicType::LongUnsignedInt };
    15391538                        ast::mutate_field(
    15401539                                type, &PtrType::dimension,
  • src/ResolvExpr/Resolver.h

    r2b4daf2 r42f6e07  
    7272        ast::ptr< ast::Init > resolveCtorInit(
    7373                const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab );
    74         /// Resolves a statement expression 
    75         const ast::Expr * resolveStmtExpr(
     74        /// Resolves a statement expression
     75        ast::ptr< ast::Expr > resolveStmtExpr(
    7676                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab );
    7777} // namespace ResolvExpr
  • src/ResolvExpr/SatisfyAssertions.cpp

    r2b4daf2 r42f6e07  
    5757                ast::UniqueId resnSlot;          ///< Slot for any recursive assertion IDs
    5858
    59                 AssnCandidate(
    60                         const ast::SymbolTable::IdData c, const ast::Type * at, ast::TypeEnvironment && e,
     59                AssnCandidate( 
     60                        const ast::SymbolTable::IdData c, const ast::Type * at, ast::TypeEnvironment && e, 
    6161                        ast::AssertionSet && h, ast::AssertionSet && n, ast::OpenVarSet && o, ast::UniqueId rs )
    62                 : cdata( c ), adjType( at ), env( std::move( e ) ), have( std::move( h ) ),
     62                : cdata( c ), adjType( at ), env( std::move( e ) ), have( std::move( h ) ), 
    6363                  need( std::move( n ) ), open( std::move( o ) ), resnSlot( rs ) {}
    6464        };
     
    6969        /// Reference to a single deferred item
    7070        struct DeferRef {
    71                 const ast::VariableExpr * expr;
     71                const ast::DeclWithType * decl;
    7272                const ast::AssertionSetValue & info;
    7373                const AssnCandidate & match;
    7474        };
    75 
    76         /// Wrapper for the deferred items from a single assertion satisfaction.
     75       
     76        /// Wrapper for the deferred items from a single assertion satisfaction. 
    7777        /// Acts like an indexed list of DeferRef
    7878        struct DeferItem {
    79                 const ast::VariableExpr * expr;
     79                const ast::DeclWithType * decl;
    8080                const ast::AssertionSetValue & info;
    8181                AssnCandidateList matches;
    8282
    83                 DeferItem(
    84                         const ast::VariableExpr * d, const ast::AssertionSetValue & i, AssnCandidateList && ms )
    85                 : expr( d ), info( i ), matches( std::move( ms ) ) {}
     83                DeferItem( 
     84                        const ast::DeclWithType * d, const ast::AssertionSetValue & i, AssnCandidateList && ms )
     85                : decl( d ), info( i ), matches( std::move( ms ) ) {}
    8686
    8787                bool empty() const { return matches.empty(); }
     
    8989                AssnCandidateList::size_type size() const { return matches.size(); }
    9090
    91                 DeferRef operator[] ( unsigned i ) const { return { expr, info, matches[i] }; }
     91                DeferRef operator[] ( unsigned i ) const { return { decl, info, matches[i] }; }
    9292        };
    9393
     
    117117                /// Initial satisfaction state for a candidate
    118118                SatState( CandidateRef & c, const ast::SymbolTable & syms )
    119                 : cand( c ), need(), newNeed(), deferred(), inferred(), costs{ Cost::zero },
     119                : cand( c ), need(), newNeed(), deferred(), inferred(), costs{ Cost::zero }, 
    120120                  symtab( syms ) { need.swap( c->need ); }
    121 
     121               
    122122                /// Update satisfaction state for next step after previous state
    123123                SatState( SatState && o, IterateFlag )
    124                 : cand( std::move( o.cand ) ), need( o.newNeed.begin(), o.newNeed.end() ), newNeed(),
    125                   deferred(), inferred( std::move( o.inferred ) ), costs( std::move( o.costs ) ),
     124                : cand( std::move( o.cand ) ), need( o.newNeed.begin(), o.newNeed.end() ), newNeed(), 
     125                  deferred(), inferred( std::move( o.inferred ) ), costs( std::move( o.costs ) ), 
    126126                  symtab( o.symtab ) { costs.emplace_back( Cost::zero ); }
    127 
     127               
    128128                /// Field-wise next step constructor
    129129                SatState(
    130                         CandidateRef && c, ast::AssertionSet && nn, InferCache && i, CostVec && cs,
     130                        CandidateRef && c, ast::AssertionSet && nn, InferCache && i, CostVec && cs, 
    131131                        ast::SymbolTable && syms )
    132                 : cand( std::move( c ) ), need( nn.begin(), nn.end() ), newNeed(), deferred(),
     132                : cand( std::move( c ) ), need( nn.begin(), nn.end() ), newNeed(), deferred(), 
    133133                  inferred( std::move( i ) ), costs( std::move( cs ) ), symtab( std::move( syms ) )
    134134                  { costs.emplace_back( Cost::zero ); }
     
    138138        void addToSymbolTable( const ast::AssertionSet & have, ast::SymbolTable & symtab ) {
    139139                for ( auto & i : have ) {
    140                         if ( i.second.isUsed ) { symtab.addId( i.first->var ); }
     140                        if ( i.second.isUsed ) { symtab.addId( i.first ); }
    141141                }
    142142        }
    143143
    144144        /// Binds a single assertion, updating satisfaction state
    145         void bindAssertion(
    146                 const ast::VariableExpr * expr, const ast::AssertionSetValue & info, CandidateRef & cand,
     145        void bindAssertion( 
     146                const ast::DeclWithType * decl, const ast::AssertionSetValue & info, CandidateRef & cand,
    147147                AssnCandidate & match, InferCache & inferred
    148148        ) {
    149149                const ast::DeclWithType * candidate = match.cdata.id;
    150                 assertf( candidate->uniqueId,
     150                assertf( candidate->uniqueId, 
    151151                        "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
    152 
     152               
    153153                ast::Expr * varExpr = match.cdata.combine( cand->expr->location, cand->cvtCost );
    154154                varExpr->result = match.adjType;
     
    156156
    157157                // place newly-inferred assertion in proper location in cache
    158                 inferred[ info.resnSlot ][ expr->var->uniqueId ] = ast::ParamEntry{
    159                         candidate->uniqueId, candidate, match.adjType, expr->result, varExpr };
     158                inferred[ info.resnSlot ][ decl->uniqueId ] = ast::ParamEntry{
     159                        candidate->uniqueId, candidate, match.adjType, decl->get_type(), varExpr };
    160160        }
    161161
     
    169169
    170170                std::vector<ast::SymbolTable::IdData> candidates;
    171                 auto kind = ast::SymbolTable::getSpecialFunctionKind(assn.first->var->name);
     171                auto kind = ast::SymbolTable::getSpecialFunctionKind(assn.first->name);
    172172                if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
    173173                        // prefilter special decls by argument type, if already known
    174                         ast::ptr<ast::Type> thisArgType = assn.first->result.strict_as<ast::PointerType>()->base
     174                        ast::ptr<ast::Type> thisArgType = strict_dynamic_cast<const ast::PointerType *>(assn.first->get_type())->base
    175175                                .strict_as<ast::FunctionType>()->params[0]
    176176                                .strict_as<ast::ReferenceType>()->base;
     
    184184                }
    185185                else {
    186                         candidates = sat.symtab.lookupId(assn.first->var->name);
     186                        candidates = sat.symtab.lookupId(assn.first->name);
    187187                }
    188188                for ( const ast::SymbolTable::IdData & cdata : candidates ) {
     
    200200                        ast::TypeEnvironment newEnv{ sat.cand->env };
    201201                        ast::OpenVarSet newOpen{ sat.cand->open };
    202                         ast::ptr< ast::Type > toType = assn.first->result;
    203                         ast::ptr< ast::Type > adjType =
    204                                 renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ), GEN_USAGE, false );
     202                        ast::ptr< ast::Type > toType = assn.first->get_type();
     203                        ast::ptr< ast::Type > adjType = 
     204                                renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ) );
    205205
    206206                        // only keep candidates which unify
     
    213213                                }
    214214
    215                                 matches.emplace_back(
     215                                matches.emplace_back( 
    216216                                        cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
    217217                                        std::move( newOpen ), crntResnSlot );
     
    287287        };
    288288
    289         /// Replace ResnSlots with InferParams and add alternative to output list, if it meets pruning
     289        /// Replace ResnSlots with InferParams and add alternative to output list, if it meets pruning 
    290290        /// threshold.
    291         void finalizeAssertions(
    292                 CandidateRef & cand, InferCache & inferred, PruneMap & thresholds, CostVec && costs,
    293                 CandidateList & out
     291        void finalizeAssertions( 
     292                CandidateRef & cand, InferCache & inferred, PruneMap & thresholds, CostVec && costs, 
     293                CandidateList & out 
    294294        ) {
    295295                // prune if cheaper alternative for same key has already been generated
     
    308308        }
    309309
    310         /// Combo iterator that combines candidates into an output list, merging their environments.
    311         /// Rejects an appended candidate if environments cannot be merged. See `Common/FilterCombos.h`
     310        /// Combo iterator that combines candidates into an output list, merging their environments. 
     311        /// Rejects an appended candidate if environments cannot be merged. See `Common/FilterCombos.h` 
    312312        /// for description of "combo iterator".
    313313        class CandidateEnvMerger {
     
    337337                                        // compute conversion cost from satisfying decl to assertion
    338338                                        cost += computeConversionCost(
    339                                                 assn.match.adjType, assn.expr->result, false, symtab, env );
     339                                                assn.match.adjType, assn.decl->get_type(), false, symtab, env );
    340340
    341341                                        // mark vars+specialization on function-type assertions
     
    350350                                        cost.incVar( func->forall.size() );
    351351
    352                                         cost.decSpec( func->assertions.size() );
     352                                        for ( const ast::TypeDecl * td : func->forall ) {
     353                                                cost.decSpec( td->assertions.size() );
     354                                        }
    353355                                }
    354356                        }
     
    385387
    386388        /// Limit to depth of recursion of assertion satisfaction
    387         static const int recursionLimit = 8;
     389        static const int recursionLimit = 4;
    388390        /// Maximum number of simultaneously-deferred assertions to attempt concurrent satisfaction of
    389391        static const int deferLimit = 10;
    390392} // anonymous namespace
    391393
    392 void satisfyAssertions(
    393         CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out,
     394void satisfyAssertions( 
     395        CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 
    394396        std::vector<std::string> & errors
    395397) {
     
    417419                        if ( it != thresholds.end() && it->second < sat.costs ) goto nextSat;
    418420
    419                         // should a limit be imposed? worst case here is O(n^2) but very unlikely to happen.
    420                         for (unsigned resetCount = 0; ; ++resetCount) {
    421                                 ast::AssertionList next;
    422                                 resetTyVarRenaming();
    423                                 // make initial pass at matching assertions
    424                                 for ( auto & assn : sat.need ) {
    425                                         // fail early if any assertion is not satisfiable
    426                                         if ( ! satisfyAssertion( assn, sat ) ) {
    427                                                 next.emplace_back(assn);
    428                                                 // goto nextSat;
    429                                         }
    430                                 }
    431                                 // success
    432                                 if (next.empty()) break;
    433                                 // fail if nothing resolves
    434                                 else if (next.size() == sat.need.size()) {
     421                        // make initial pass at matching assertions
     422                        for ( auto & assn : sat.need ) {
     423                                // fail early if any assertion is not satisfiable
     424                                if ( ! satisfyAssertion( assn, sat ) ) {
    435425                                        Indenter tabs{ 3 };
    436426                                        std::ostringstream ss;
     
    438428                                        print( ss, *sat.cand, ++tabs );
    439429                                        ss << (tabs-1) << "Could not satisfy assertion:\n";
    440                                         ast::print( ss, next[0].first, tabs );
     430                                        ast::print( ss, assn.first, tabs );
    441431
    442432                                        errors.emplace_back( ss.str() );
    443433                                        goto nextSat;
    444434                                }
    445                                 sat.need = std::move(next);
    446435                        }
    447436
     
    449438                                // either add successful match or push back next state
    450439                                if ( sat.newNeed.empty() ) {
    451                                         finalizeAssertions(
     440                                        finalizeAssertions( 
    452441                                                sat.cand, sat.inferred, thresholds, std::move( sat.costs ), out );
    453442                                } else {
     
    462451                                ss << (tabs-1) << "Too many non-unique satisfying assignments for assertions:\n";
    463452                                for ( const auto & d : sat.deferred ) {
    464                                         ast::print( ss, d.expr, tabs );
     453                                        ast::print( ss, d.decl, tabs );
    465454                                }
    466455
     
    471460                                std::vector< CandidateEnvMerger::OutType > compatible = filterCombos(
    472461                                        sat.deferred, CandidateEnvMerger{ sat.cand->env, sat.cand->open, sat.symtab } );
    473 
     462                               
    474463                                // fail early if no mutually-compatible assertion satisfaction
    475464                                if ( compatible.empty() ) {
     
    480469                                        ss << (tabs-1) << "No mutually-compatible satisfaction for assertions:\n";
    481470                                        for ( const auto& d : sat.deferred ) {
    482                                                 ast::print( ss, d.expr, tabs );
     471                                                ast::print( ss, d.decl, tabs );
    483472                                        }
    484473
     
    494483                                        // set up next satisfaction state
    495484                                        CandidateRef nextCand = std::make_shared<Candidate>(
    496                                                 sat.cand->expr, std::move( compat.env ), std::move( compat.open ),
     485                                                sat.cand->expr, std::move( compat.env ), std::move( compat.open ), 
    497486                                                ast::AssertionSet{} /* need moved into satisfaction state */,
    498487                                                sat.cand->cost, sat.cand->cvtCost );
     
    500489                                        ast::AssertionSet nextNewNeed{ sat.newNeed };
    501490                                        InferCache nextInferred{ sat.inferred };
    502 
     491                                       
    503492                                        CostVec nextCosts{ sat.costs };
    504493                                        nextCosts.back() += compat.cost;
    505 
     494                                                               
    506495                                        ast::SymbolTable nextSymtab{ sat.symtab };
    507496
     
    512501                                                nextNewNeed.insert( match.need.begin(), match.need.end() );
    513502
    514                                                 bindAssertion( r.expr, r.info, nextCand, match, nextInferred );
     503                                                bindAssertion( r.decl, r.info, nextCand, match, nextInferred );
    515504                                        }
    516505
    517506                                        // either add successful match or push back next state
    518507                                        if ( nextNewNeed.empty() ) {
    519                                                 finalizeAssertions(
     508                                                finalizeAssertions( 
    520509                                                        nextCand, nextInferred, thresholds, std::move( nextCosts ), out );
    521510                                        } else {
    522                                                 nextSats.emplace_back(
    523                                                         std::move( nextCand ), std::move( nextNewNeed ),
    524                                                         std::move( nextInferred ), std::move( nextCosts ),
     511                                                nextSats.emplace_back( 
     512                                                        std::move( nextCand ), std::move( nextNewNeed ), 
     513                                                        std::move( nextInferred ), std::move( nextCosts ), 
    525514                                                        std::move( nextSymtab ) );
    526515                                        }
     
    534523                nextSats.clear();
    535524        }
    536 
     525       
    537526        // exceeded recursion limit if reaches here
    538527        if ( out.empty() ) {
  • src/ResolvExpr/Unify.cc

    r2b4daf2 r42f6e07  
    773773
    774774                        const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
    775                                 if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
     775                                if ( const ast::EqvClass * clz = tenv.lookup( typeInst->name ) ) {
    776776                                        // expand ttype parameter into its actual type
    777777                                        if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
     
    811811                /// Creates a tuple type based on a list of DeclWithType
    812812                template< typename Iter >
    813                 static const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
     813                static ast::ptr< ast::Type > tupleFromTypes( Iter crnt, Iter end ) {
    814814                        std::vector< ast::ptr< ast::Type > > types;
    815815                        while ( crnt != end ) {
     
    821821                        }
    822822
    823                         return new ast::TupleType{ std::move(types) };
     823                        return { new ast::TupleType{ std::move(types) } };
    824824                }
    825825
     
    888888                }
    889889
    890                 static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
     890                static void markAssertionSet( ast::AssertionSet & assns, const ast::DeclWithType * assn ) {
    891891                        auto i = assns.find( assn );
    892892                        if ( i != assns.end() ) {
     
    900900                        const ast::FunctionType * type
    901901                ) {
    902                         for ( auto & assert : type->assertions ) {
    903                                 markAssertionSet( assn1, assert );
    904                                 markAssertionSet( assn2, assert );
     902                        for ( const auto & tyvar : type->forall ) {
     903                                for ( const ast::DeclWithType * assert : tyvar->assertions ) {
     904                                        markAssertionSet( assn1, assert );
     905                                        markAssertionSet( assn2, assert );
     906                                }
    905907                        }
    906908                }
     
    10281030
    10291031                void postvisit( const ast::TypeInstType * typeInst ) {
    1030                         assert( open.find( *typeInst ) == open.end() );
     1032                        assert( open.find( typeInst->name ) == open.end() );
    10311033                        handleRefType( typeInst, type2 );
    10321034                }
     
    10341036        private:
    10351037                /// Creates a tuple type based on a list of Type
    1036                 static const ast::Type * tupleFromTypes(
     1038                static ast::ptr< ast::Type > tupleFromTypes(
    10371039                        const std::vector< ast::ptr< ast::Type > > & tys
    10381040                ) {
     
    11691171                auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
    11701172                ast::OpenVarSet::const_iterator
    1171                         entry1 = var1 ? open.find( *var1 ) : open.end(),
    1172                         entry2 = var2 ? open.find( *var2 ) : open.end();
     1173                        entry1 = var1 ? open.find( var1->name ) : open.end(),
     1174                        entry2 = var2 ? open.find( var2->name ) : open.end();
    11731175                bool isopen1 = entry1 != open.end();
    11741176                bool isopen2 = entry2 != open.end();
  • src/SymTab/Mangler.cc

    r2b4daf2 r42f6e07  
    671671                                        int dcount = 0, fcount = 0, vcount = 0, acount = 0;
    672672                                        mangleName += Encoding::forall;
    673                                         for ( auto & decl : ptype->forall ) {
     673                                        for ( const ast::TypeDecl * decl : ptype->forall ) {
    674674                                                switch ( decl->kind ) {
    675675                                                case ast::TypeDecl::Kind::Dtype:
     
    686686                                                } // switch
    687687                                                varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
    688                                         } // for
    689                                         for ( auto & assert : ptype->assertions ) {
    690                                                 ast::Pass<Mangler_new> sub_mangler(
    691                                                         mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
    692                                                 assert->var->accept( sub_mangler );
    693                                                 assertionNames.push_back( sub_mangler.core.get_mangleName() );
    694                                                 acount++;
     688                                                for ( const ast::DeclWithType * assert : decl->assertions ) {
     689                                                        ast::Pass<Mangler_new> sub_mangler(
     690                                                                mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
     691                                                        assert->accept( sub_mangler );
     692                                                        assertionNames.push_back( sub_mangler.core.get_mangleName() );
     693                                                        acount++;
     694                                                } // for
    695695                                        } // for
    696696                                        mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
  • src/SymTab/Validate.cc

    r2b4daf2 r42f6e07  
    271271        };
    272272
    273         struct InitializerLength {
     273        struct ArrayLength : public WithIndexer {
    274274                /// for array types without an explicit length, compute the length and store it so that it
    275275                /// is known to the rest of the phases. For example,
     
    282282
    283283                void previsit( ObjectDecl * objDecl );
    284         };
    285 
    286         struct ArrayLength : public WithIndexer {
    287                 static void computeLength( std::list< Declaration * > & translationUnit );
    288 
    289284                void previsit( ArrayType * arrayType );
    290285        };
     
    387382                                        FixObjectType::fix, translationUnit);
    388383                        }
    389                         Stats::Time::TimeCall("Initializer Length",
    390                                 InitializerLength::computeLength, translationUnit);
    391                         if (!useNewAST) {
    392                                 Stats::Time::TimeCall("Array Length",
    393                                         ArrayLength::computeLength, translationUnit);
    394                         }
     384                        Stats::Time::TimeCall("Array Length",
     385                                ArrayLength::computeLength, translationUnit);
    395386                        Stats::Time::TimeCall("Find Special Declarations",
    396387                                Validate::findSpecialDecls, translationUnit);
     
    13411332        }
    13421333
    1343         void InitializerLength::computeLength( std::list< Declaration * > & translationUnit ) {
    1344                 PassVisitor<InitializerLength> len;
    1345                 acceptAll( translationUnit, len );
    1346         }
    1347 
    13481334        void ArrayLength::computeLength( std::list< Declaration * > & translationUnit ) {
    13491335                PassVisitor<ArrayLength> len;
     
    13511337        }
    13521338
    1353         void InitializerLength::previsit( ObjectDecl * objDecl ) {
     1339        void ArrayLength::previsit( ObjectDecl * objDecl ) {
    13541340                if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->type ) ) {
    13551341                        if ( at->dimension ) return;
     
    13611347
    13621348        void ArrayLength::previsit( ArrayType * type ) {
    1363                 if ( type->dimension ) {
    1364                         // need to resolve array dimensions early so that constructor code can correctly determine
    1365                         // if a type is a VLA (and hence whether its elements need to be constructed)
    1366                         ResolvExpr::findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
    1367 
    1368                         // must re-evaluate whether a type is a VLA, now that more information is available
    1369                         // (e.g. the dimension may have been an enumerator, which was unknown prior to this step)
    1370                         type->isVarLen = ! InitTweak::isConstExpr( type->dimension );
     1349                if (!useNewAST) {
     1350                        if ( type->dimension ) {
     1351                                // need to resolve array dimensions early so that constructor code can correctly determine
     1352                                // if a type is a VLA (and hence whether its elements need to be constructed)
     1353                                ResolvExpr::findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
     1354
     1355                                // must re-evaluate whether a type is a VLA, now that more information is available
     1356                                // (e.g. the dimension may have been an enumerator, which was unknown prior to this step)
     1357                                type->isVarLen = ! InitTweak::isConstExpr( type->dimension );
     1358                        }
    13711359                }
    13721360        }
     
    14741462                }
    14751463        }
    1476 
    1477         /*
    14781464
    14791465        /// Associates forward declarations of aggregates with their definitions
     
    18581844                }
    18591845        };
    1860         */
    18611846} // anonymous namespace
    18621847
    1863 /*
    18641848const ast::Type * validateType(
    18651849                const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab ) {
     
    18701854        return type->accept( lrt )->accept( fpd );
    18711855}
    1872 */
    18731856
    18741857} // namespace SymTab
  • src/Tuples/TupleAssignment.cc

    r2b4daf2 r42f6e07  
    504504
    505505                        std::vector< ast::ptr< ast::Expr > > match() override {
    506                                 static UniqueName lhsNamer( "__massassign_L" );
    507                                 static UniqueName rhsNamer( "__massassign_R" );
     506                                // temporary workaround for new and old ast to coexist and avoid name collision
     507                                static UniqueName lhsNamer( "__massassign_Ln" );
     508                                static UniqueName rhsNamer( "__massassign_Rn" );
    508509                                // empty tuple case falls into this matcher
    509510                                assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );
     
    534535
    535536                        std::vector< ast::ptr< ast::Expr > > match() override {
    536                                 static UniqueName lhsNamer( "__multassign_L" );
    537                                 static UniqueName rhsNamer( "__multassign_R" );
     537                                // temporary workaround for new and old ast to coexist and avoid name collision
     538                                static UniqueName lhsNamer( "__multassign_Ln" );
     539                                static UniqueName rhsNamer( "__multassign_Rn" );
    538540
    539541                                if ( lhs.size() != rhs.size() ) return {};
  • tests/.expect/KRfunctions.nast.x86.txt

    r2b4daf2 r42f6e07  
    8686    __attribute__ ((unused)) signed int (*_X11_retval_f11PA0i_1)[];
    8787}
    88 signed int (*_X3f12FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned int )10)]{
    89     __attribute__ ((unused)) signed int (*_X11_retval_f12PA0A0i_1)[][((unsigned int )10)];
     88signed int (*_X3f12FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned long int )10)]{
     89    __attribute__ ((unused)) signed int (*_X11_retval_f12PA0A0i_1)[][((unsigned long int )10)];
    9090}
    91 signed int (*_X3f13FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned int )10)]{
    92     __attribute__ ((unused)) signed int (*_X11_retval_f13PA0A0i_1)[][((unsigned int )10)];
     91signed int (*_X3f13FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned long int )10)]{
     92    __attribute__ ((unused)) signed int (*_X11_retval_f13PA0A0i_1)[][((unsigned long int )10)];
    9393}
    94 signed int (*_X3f14FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned int )10)]{
    95     __attribute__ ((unused)) signed int (*_X11_retval_f14PA0A0i_1)[][((unsigned int )10)];
     94signed int (*_X3f14FPA0A0i_iPiPi__1(signed int _X1ai_1, signed int *_X1bPi_1, signed int *_X1cPi_1))[][((unsigned long int )10)]{
     95    __attribute__ ((unused)) signed int (*_X11_retval_f14PA0A0i_1)[][((unsigned long int )10)];
    9696}
    9797signed int _X3f15Fi_iii__1(signed int _X1ai_1, signed int _X1bi_1, signed int _X1ci_1){
  • tests/.expect/attributes.nast.x86.txt

    r2b4daf2 r42f6e07  
    623623__attribute__ ((used,used,used,used)) const signed int *_X3vd3PKi_1;
    624624__attribute__ ((used,used,unused,used,unused)) const signed int *_X3vd4PKi_1;
    625 __attribute__ ((used,used,used)) const signed int _X3vd5A0Ki_1[((unsigned int )5)];
    626 __attribute__ ((used,used,unused,used)) const signed int _X3vd6A0Ki_1[((unsigned int )5)];
     625__attribute__ ((used,used,used)) const signed int _X3vd5A0Ki_1[((unsigned long int )5)];
     626__attribute__ ((used,used,unused,used)) const signed int _X3vd6A0Ki_1[((unsigned long int )5)];
    627627__attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
    628628__attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
     
    647647    __attribute__ ((unused,unused,used)) signed int _X2t1i_2;
    648648    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t2PPi_2;
    649     __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned int )5)];
    650     __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned int )5)];
     649    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)];
     650    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)];
    651651    __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
    652652    __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
     
    671671signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
    672672signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
    673 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned int )5)]));
     673signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned long int )5)]));
    674674signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    675675signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
     
    679679    __attribute__ ((used,unused)) signed int _X3ad1i_2;
    680680    __attribute__ ((unused,unused,unused)) signed int *_X3ad2Pi_2;
    681     __attribute__ ((unused,unused,unused)) signed int _X3ad3A0i_2[((unsigned int )5)];
    682     __attribute__ ((unused,unused,unused,unused,unused)) signed int (*_X3ad4PA0i_2)[((unsigned int )10)];
     681    __attribute__ ((unused,unused,unused)) signed int _X3ad3A0i_2[((unsigned long int )5)];
     682    __attribute__ ((unused,unused,unused,unused,unused)) signed int (*_X3ad4PA0i_2)[((unsigned long int )10)];
    683683    __attribute__ ((unused,unused,unused,unused,used)) signed int _X3ad5i_2;
    684684    __attribute__ ((unused,unused,unused,unused,unused)) signed int _X3ad6Fi___2();
  • tests/.expect/functions.nast.x86.txt

    r2b4daf2 r42f6e07  
    4646    __attribute__ ((unused)) signed int (*_X11_retval_f10PA0i_1)[];
    4747}
    48 signed int (*_X3f11FPA0A0i___1())[][((unsigned int )3)]{
    49     __attribute__ ((unused)) signed int (*_X11_retval_f11PA0A0i_1)[][((unsigned int )3)];
    50 }
    51 signed int (*_X3f12FPA0A0i___1())[][((unsigned int )3)]{
    52     __attribute__ ((unused)) signed int (*_X11_retval_f12PA0A0i_1)[][((unsigned int )3)];
     48signed int (*_X3f11FPA0A0i___1())[][((unsigned long int )3)]{
     49    __attribute__ ((unused)) signed int (*_X11_retval_f11PA0A0i_1)[][((unsigned long int )3)];
     50}
     51signed int (*_X3f12FPA0A0i___1())[][((unsigned long int )3)]{
     52    __attribute__ ((unused)) signed int (*_X11_retval_f12PA0A0i_1)[][((unsigned long int )3)];
    5353}
    5454signed int _X4fII1Fi_i__1(signed int _X1ii_1){
     
    250250signed int _X1fFi_Fi_ii_Fi_i___1(__attribute__ ((unused)) signed int (*__anonymous_object20)(signed int __param_0, signed int __param_1), __attribute__ ((unused)) signed int (*__anonymous_object21)(signed int __param_0)){
    251251    __attribute__ ((unused)) signed int _X9_retval_fi_1;
    252     signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned int )10)])[][((unsigned int )3)];
    253     signed int (*(*_X1pPA0A0PA0A0i_2)[][((unsigned int )10)])[][((unsigned int )3)];
     252    signed int (*(*_X2pcPA0A0PA0A0i_2)[][((unsigned long int )10)])[][((unsigned long int )3)];
     253    signed int (*(*_X1pPA0A0PA0A0i_2)[][((unsigned long int )10)])[][((unsigned long int )3)];
    254254    signed int (*(*_X1pPA0Fi_i__2)[])(signed int __param_0);
    255255}
  • tests/Makefile.am

    r2b4daf2 r42f6e07  
    103103
    104104mostlyclean-local :
    105         find ${builddir} -not -path './__pycache__/*' -path '*.o' -delete
    106         find ${builddir} -not -path './__pycache__/*' -path '*/.err/*.log' -delete
    107         find ${builddir} -not -path './__pycache__/*' -path '*/.out/*.log' -delete
    108105        rm -f ${EXTRA_PROGRAMS}
    109106        rm -rf __pycache__
     107        find ${builddir} -path '*.o' -delete
     108        find ${builddir} -path '*/.err/*.log' -delete
     109        find ${builddir} -path '*/.out/*.log' -delete
    110110
    111111distclean-local :
  • tests/concurrent/futures/.expect/basic.txt

    r2b4daf2 r42f6e07  
    1 start
    21done
  • tests/concurrent/futures/basic.cfa

    r2b4daf2 r42f6e07  
    11#include <thread.hfa>
    2 
    32enum {NFUTURES = 10};
    43
     
    8483
    8584int main() {
    86         printf( "start\n" );                            // non-empty .expect file
    8785        processor procs[2];
    8886        {
  • tests/errors/.expect/completeType.nast.x64.txt

    r2b4daf2 r42f6e07  
    1212      Application of
    1313        Variable Expression: *?: forall
    14           instance of type DT (not function type)
     14          DT: data type
    1515          function
    1616        ... with parameters
     
    2121        ... with resolved type:
    2222          pointer to forall
    23             instance of type [unbound] (not function type)
     23            [unbound]:data type
    2424            function
    2525          ... with parameters
     
    4141    void
    4242  )
    43   Environment:([unbound]DT) -> instance of struct A without body (no widening)
     43  Environment:([unbound]) -> instance of struct A without body (no widening)
    4444
    4545
     
    4747      Application of
    4848        Variable Expression: *?: forall
    49           instance of type DT (not function type)
     49          DT: data type
    5050          function
    5151        ... with parameters
     
    5656        ... with resolved type:
    5757          pointer to forall
    58             instance of type [unbound] (not function type)
     58            [unbound]:data type
    5959            function
    6060          ... with parameters
     
    7676    void
    7777  )
    78   Environment:([unbound]DT) -> instance of struct B with body (no widening)
     78  Environment:([unbound]) -> instance of struct B with body (no widening)
    7979
    8080
     
    113113Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
    114114            Variable Expression: baz: forall
    115               instance of type T (not function type)
    116               with assertions
    117               Variable Expression: ?=?: pointer to function
    118               ... with parameters
    119                 reference to instance of type T (not function type)
    120                 instance of type T (not function type)
    121               ... returning
    122                 instance of type T (not function type)
    123 
    124               ... with resolved type:
    125                 pointer to function
     115              T: sized data type
     116              ... with assertions
     117                ?=?: pointer to function
    126118                ... with parameters
    127119                  reference to instance of type T (not function type)
     
    130122                  instance of type T (not function type)
    131123
    132               Variable Expression: ?{}: pointer to function
    133               ... with parameters
    134                 reference to instance of type T (not function type)
    135               ... returning nothing
    136 
    137               ... with resolved type:
    138                 pointer to function
     124                ?{}: pointer to function
    139125                ... with parameters
    140126                  reference to instance of type T (not function type)
    141127                ... returning nothing
    142128
    143               Variable Expression: ?{}: pointer to function
    144               ... with parameters
    145                 reference to instance of type T (not function type)
    146                 instance of type T (not function type)
    147               ... returning nothing
    148 
    149               ... with resolved type:
    150                 pointer to function
     129                ?{}: pointer to function
    151130                ... with parameters
    152131                  reference to instance of type T (not function type)
     
    154133                ... returning nothing
    155134
    156               Variable Expression: ^?{}: pointer to function
    157               ... with parameters
    158                 reference to instance of type T (not function type)
    159               ... returning nothing
    160 
    161               ... with resolved type:
    162                 pointer to function
     135                ^?{}: pointer to function
    163136                ... with parameters
    164137                  reference to instance of type T (not function type)
    165138                ... returning nothing
     139
    166140
    167141              function
     
    172146            ... with resolved type:
    173147              pointer to forall
    174                 instance of type [unbound] (not function type)
    175                 with assertions
    176                 Variable Expression: ?=?: pointer to function
    177                 ... with parameters
    178                   reference to instance of type T (not function type)
    179                   instance of type T (not function type)
    180                 ... returning
    181                   instance of type T (not function type)
    182 
    183                 ... with resolved type:
    184                   pointer to function
     148                [unbound]:sized data type
     149                ... with assertions
     150                  ?=?: pointer to function
    185151                  ... with parameters
    186152                    reference to instance of type [unbound] (not function type)
     
    189155                    instance of type [unbound] (not function type)
    190156
    191                 Variable Expression: ?{}: pointer to function
    192                 ... with parameters
    193                   reference to instance of type T (not function type)
    194                 ... returning nothing
    195 
    196                 ... with resolved type:
    197                   pointer to function
     157                  ?{}: pointer to function
    198158                  ... with parameters
    199159                    reference to instance of type [unbound] (not function type)
    200160                  ... returning nothing
    201161
    202                 Variable Expression: ?{}: pointer to function
    203                 ... with parameters
    204                   reference to instance of type T (not function type)
    205                   instance of type T (not function type)
    206                 ... returning nothing
    207 
    208                 ... with resolved type:
    209                   pointer to function
     162                  ?{}: pointer to function
    210163                  ... with parameters
    211164                    reference to instance of type [unbound] (not function type)
     
    213166                  ... returning nothing
    214167
    215                 Variable Expression: ^?{}: pointer to function
    216                 ... with parameters
    217                   reference to instance of type T (not function type)
    218                 ... returning nothing
    219 
    220                 ... with resolved type:
    221                   pointer to function
     168                  ^?{}: pointer to function
    222169                  ... with parameters
    223170                    reference to instance of type [unbound] (not function type)
    224171                  ... returning nothing
     172
    225173
    226174                function
     
    240188          void
    241189        )
    242         Environment:([unbound]T) -> instance of type T (not function type) (no widening)
     190        Environment:([unbound]) -> instance of type T (not function type) (no widening)
    243191
    244192      Could not satisfy assertion:
    245 Variable Expression: ?=?: pointer to function
     193?=?: pointer to function
    246194        ... with parameters
    247           reference to instance of type T (not function type)
    248           instance of type T (not function type)
     195          reference to instance of type [unbound] (not function type)
     196          instance of type [unbound] (not function type)
    249197        ... returning
    250           instance of type T (not function type)
     198          instance of type [unbound] (not function type)
    251199
    252         ... with resolved type:
    253           pointer to function
    254           ... with parameters
    255             reference to instance of type [unbound] (not function type)
    256             instance of type [unbound] (not function type)
    257           ... returning
    258             instance of type [unbound] (not function type)
    259 
  • tests/errors/.expect/completeType.nast.x86.txt

    r2b4daf2 r42f6e07  
    1212      Application of
    1313        Variable Expression: *?: forall
    14           instance of type DT (not function type)
     14          DT: data type
    1515          function
    1616        ... with parameters
     
    2121        ... with resolved type:
    2222          pointer to forall
    23             instance of type [unbound] (not function type)
     23            [unbound]:data type
    2424            function
    2525          ... with parameters
     
    4141    void
    4242  )
    43   Environment:([unbound]DT) -> instance of struct A without body (no widening)
     43  Environment:([unbound]) -> instance of struct A without body (no widening)
    4444
    4545
     
    4747      Application of
    4848        Variable Expression: *?: forall
    49           instance of type DT (not function type)
     49          DT: data type
    5050          function
    5151        ... with parameters
     
    5656        ... with resolved type:
    5757          pointer to forall
    58             instance of type [unbound] (not function type)
     58            [unbound]:data type
    5959            function
    6060          ... with parameters
     
    7676    void
    7777  )
    78   Environment:([unbound]DT) -> instance of struct B with body (no widening)
     78  Environment:([unbound]) -> instance of struct B with body (no widening)
    7979
    8080
     
    113113Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
    114114            Variable Expression: baz: forall
    115               instance of type T (not function type)
    116               with assertions
    117               Variable Expression: ?=?: pointer to function
    118               ... with parameters
    119                 reference to instance of type T (not function type)
    120                 instance of type T (not function type)
    121               ... returning
    122                 instance of type T (not function type)
    123 
    124               ... with resolved type:
    125                 pointer to function
     115              T: sized data type
     116              ... with assertions
     117                ?=?: pointer to function
    126118                ... with parameters
    127119                  reference to instance of type T (not function type)
     
    130122                  instance of type T (not function type)
    131123
    132               Variable Expression: ?{}: pointer to function
    133               ... with parameters
    134                 reference to instance of type T (not function type)
    135               ... returning nothing
    136 
    137               ... with resolved type:
    138                 pointer to function
     124                ?{}: pointer to function
    139125                ... with parameters
    140126                  reference to instance of type T (not function type)
    141127                ... returning nothing
    142128
    143               Variable Expression: ?{}: pointer to function
    144               ... with parameters
    145                 reference to instance of type T (not function type)
    146                 instance of type T (not function type)
    147               ... returning nothing
    148 
    149               ... with resolved type:
    150                 pointer to function
     129                ?{}: pointer to function
    151130                ... with parameters
    152131                  reference to instance of type T (not function type)
     
    154133                ... returning nothing
    155134
    156               Variable Expression: ^?{}: pointer to function
    157               ... with parameters
    158                 reference to instance of type T (not function type)
    159               ... returning nothing
    160 
    161               ... with resolved type:
    162                 pointer to function
     135                ^?{}: pointer to function
    163136                ... with parameters
    164137                  reference to instance of type T (not function type)
    165138                ... returning nothing
     139
    166140
    167141              function
     
    172146            ... with resolved type:
    173147              pointer to forall
    174                 instance of type [unbound] (not function type)
    175                 with assertions
    176                 Variable Expression: ?=?: pointer to function
    177                 ... with parameters
    178                   reference to instance of type T (not function type)
    179                   instance of type T (not function type)
    180                 ... returning
    181                   instance of type T (not function type)
    182 
    183                 ... with resolved type:
    184                   pointer to function
     148                [unbound]:sized data type
     149                ... with assertions
     150                  ?=?: pointer to function
    185151                  ... with parameters
    186152                    reference to instance of type [unbound] (not function type)
     
    189155                    instance of type [unbound] (not function type)
    190156
    191                 Variable Expression: ?{}: pointer to function
    192                 ... with parameters
    193                   reference to instance of type T (not function type)
    194                 ... returning nothing
    195 
    196                 ... with resolved type:
    197                   pointer to function
     157                  ?{}: pointer to function
    198158                  ... with parameters
    199159                    reference to instance of type [unbound] (not function type)
    200160                  ... returning nothing
    201161
    202                 Variable Expression: ?{}: pointer to function
    203                 ... with parameters
    204                   reference to instance of type T (not function type)
    205                   instance of type T (not function type)
    206                 ... returning nothing
    207 
    208                 ... with resolved type:
    209                   pointer to function
     162                  ?{}: pointer to function
    210163                  ... with parameters
    211164                    reference to instance of type [unbound] (not function type)
     
    213166                  ... returning nothing
    214167
    215                 Variable Expression: ^?{}: pointer to function
    216                 ... with parameters
    217                   reference to instance of type T (not function type)
    218                 ... returning nothing
    219 
    220                 ... with resolved type:
    221                   pointer to function
     168                  ^?{}: pointer to function
    222169                  ... with parameters
    223170                    reference to instance of type [unbound] (not function type)
    224171                  ... returning nothing
     172
    225173
    226174                function
     
    240188          void
    241189        )
    242         Environment:([unbound]T) -> instance of type T (not function type) (no widening)
     190        Environment:([unbound]) -> instance of type T (not function type) (no widening)
    243191
    244192      Could not satisfy assertion:
    245 Variable Expression: ?=?: pointer to function
     193?=?: pointer to function
    246194        ... with parameters
    247           reference to instance of type T (not function type)
    248           instance of type T (not function type)
     195          reference to instance of type [unbound] (not function type)
     196          instance of type [unbound] (not function type)
    249197        ... returning
    250           instance of type T (not function type)
     198          instance of type [unbound] (not function type)
    251199
    252         ... with resolved type:
    253           pointer to function
    254           ... with parameters
    255             reference to instance of type [unbound] (not function type)
    256             instance of type [unbound] (not function type)
    257           ... returning
    258             instance of type [unbound] (not function type)
    259 
  • tests/raii/.expect/ctor-autogen-ERR1.nast.txt

    r2b4daf2 r42f6e07  
    7070            ... with environment:
    7171              Types:
     72              Non-types:
    7273
    7374
Note: See TracChangeset for help on using the changeset viewer.