Changes in / [eef8dfb:bdfc032]


Ignore:
Files:
191 added
547 deleted
392 edited

Legend:

Unmodified
Added
Removed
  • .gitignore

    reef8dfb rbdfc032  
    44
    55# generated by configure
    6 aclocal.m4
    7 automake
    86autom4te.cache
    97config.h
     
    119config.log
    1210config.py
    13 configure
     11stamp-h1
    1412libtool
    15 stamp-h1
    1613/Makefile
    17 /Makefile.in
    1814**/Makefile
    19 **/Makefile.in
    20 **/Makefile.dist.in
    2115/version
    2216
     
    4842libcfa/x64-debug/
    4943libcfa/x64-nodebug/
     44libcfa/x64-nolib/
    5045libcfa/x86-debug/
    5146libcfa/x86-nodebug/
    52 libcfa/arm64-debug/
    53 libcfa/arm64-nodebug/
     47libcfa/x86-nolib/
     48libcfa/arm-debug/
     49libcfa/arm-nodebug/
     50libcfa/arm-nolib/
    5451
    5552# generated by bison and lex from parser.yy and lex.ll
     
    7673doc/user/pointer2.tex
    7774doc/user/EHMHierarchy.tex
    78 
    79 # generated by npm
    80 package-lock.json
  • Jenkins/FullBuild

    reef8dfb rbdfc032  
    88        def err = null
    99
    10         final scmVars = checkout scm
    11         final commitId = scmVars.GIT_COMMIT
    12 
    1310        try {
    1411                //Wrap build to add timestamp to command line
     
    1714                        stage('Build') {
    1815
     16                                results = [null, null]
     17
    1918                                parallel (
    20                                         gcc_8_x86_old: { trigger_build( 'gcc-8',   'x86', false ) },
    21                                         gcc_7_x86_old: { trigger_build( 'gcc-7',   'x86', false ) },
    22                                         gcc_6_x86_old: { trigger_build( 'gcc-6',   'x86', false ) },
    23                                         gcc_9_x64_old: { trigger_build( 'gcc-9',   'x64', false ) },
    24                                         gcc_8_x64_old: { trigger_build( 'gcc-8',   'x64', false ) },
    25                                         gcc_7_x64_old: { trigger_build( 'gcc-7',   'x64', false ) },
    26                                         gcc_6_x64_old: { trigger_build( 'gcc-6',   'x64', false ) },
    27                                         gcc_5_x64_old: { trigger_build( 'gcc-5',   'x64', false ) },
    28                                         clang_x64_old: { trigger_build( 'clang',   'x64', false ) },
    29                                         clang_x64_new: { trigger_build( 'clang',   'x64', true  ) },
     19                                        clang_x86: { trigger_build( 'gcc-8',   'x86' ) },
     20                                        gcc_5_x86: { trigger_build( 'gcc-7',   'x86' ) },
     21                                        gcc_6_x86: { trigger_build( 'gcc-6',   'x86' ) },
     22                                        gcc_9_x64: { trigger_build( 'gcc-9',   'x64' ) },
     23                                        gcc_8_x64: { trigger_build( 'gcc-8',   'x64' ) },
     24                                        gcc_7_x64: { trigger_build( 'gcc-7',   'x64' ) },
     25                                        gcc_6_x64: { trigger_build( 'gcc-6',   'x64' ) },
     26                                        gcc_5_x64: { trigger_build( 'gcc-5',   'x64' ) },
     27                                        clang_x64: { trigger_build( 'clang',   'x64' ) },
    3028                                )
    31                         }
    32 
    33                         stage('Package') {
    34                                 trigger_dist( commitId, currentBuild.number.toString() )
    3529                        }
    3630                }
     
    6559//===========================================================================================================
    6660
    67 def trigger_build(String cc, String arch, boolean new_ast) {
     61def trigger_build(String cc, String arch) {
    6862        def result = build job: 'Cforall/master',               \
    6963                parameters: [                                           \
     
    7468                          name: 'Architecture',                         \
    7569                          value: arch],                                 \
    76                         [$class: 'BooleanParameterValue',               \
    77                           name: 'NewAST',                               \
    78                           value: new_ast],                              \
    7970                        [$class: 'BooleanParameterValue',               \
    8071                          name: 'RunAllTests',                          \
     
    8879                        [$class: 'BooleanParameterValue',               \
    8980                          name: 'Publish',                              \
    90                           value: true],                                         \
     81                          value: true],                                 \
    9182                        [$class: 'BooleanParameterValue',               \
    9283                          name: 'Silent',                               \
     
    10394}
    10495
    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
     96//Helper routine to collect information about the git history
     97def collect_git_info() {
    11298
    113         echo(result.result)
     99        //create the temporary output directory in case it doesn't already exist
     100        def out_dir = pwd tmp: true
     101        sh "mkdir -p ${out_dir}"
    114102
    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)
     103        //parse git logs to find what changed
     104        dir("../Cforall_Full_Build@script") {
     105                sh "git reflog > ${out_dir}/GIT_COMMIT"
    118106        }
     107        git_reflog = readFile("${out_dir}/GIT_COMMIT")
     108        gitRefOldValue = (git_reflog =~ /moving from (.+) to (.+)/)[0][1]
     109        gitRefNewValue = (git_reflog =~ /moving from (.+) to (.+)/)[0][2]
    119110}
    120111
  • Jenkinsfile

    reef8dfb rbdfc032  
    22
    33import groovy.transform.Field
     4
     5// For skipping stages
     6import org.jenkinsci.plugins.pipeline.modeldefinition.Utils
    47
    58//===========================================================================================================
     
    1215        SrcDir    = pwd tmp: false
    1316        Settings  = null
    14         Tools     = null
     17        StageName = ''
    1518
    1619        // Local variables
     
    3033                                SrcDir    = pwd tmp: false
    3134
    32                                 Tools.Clean()
    33 
    34                                 Tools.Checkout()
     35                                clean()
     36
     37                                checkout()
    3538
    3639                                build()
     
    5457        //attach the build log to the email
    5558        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
     59                //rethrow error later
     60                err = caughtError
     61
     62                echo err.toString()
     63
     64                //An error has occured, the build log is relevent
    6065                log_needed = true
    6166
    62                 // rethrow error later
    63                 err = caughtError
    64 
    65                 // print the error so it shows in the log
    66                 echo err.toString()
     67                //Store the result of the build log
     68                currentBuild.result = "${StageName} FAILURE".trim()
    6769        }
    6870
     
    8284// Main compilation routines
    8385//===========================================================================================================
     86def clean() {
     87        build_stage('Cleanup', true) {
     88                // clean the build by wipping the build directory
     89                dir(BuildDir) {
     90                        deleteDir()
     91                }
     92        }
     93}
     94
     95//Compilation script is done here but environnement set-up and error handling is done in main loop
     96def checkout() {
     97        build_stage('Checkout', true) {
     98                //checkout the source code and clean the repo
     99                final scmVars = checkout scm
     100                Settings.GitNewRef = scmVars.GIT_COMMIT
     101                Settings.GitOldRef = scmVars.GIT_PREVIOUS_COMMIT
     102
     103                echo GitLogMessage()
     104
     105                // This is a complete hack but it solves problems with automake thinking it needs to regenerate makefiles
     106                // We fudged automake/missing to handle that but automake stills bakes prints inside the makefiles
     107                // and these cause more problems.
     108                sh 'find . -name Makefile.in -exec touch {} +'
     109        }
     110}
     111
    84112def build() {
    85113        debug = true
    86114        release = Settings.RunAllTests || Settings.RunBenchmark
    87         Tools.BuildStage('Build : configure', true) {
    88                 // Configure must be run inside the tree
    89                 dir (SrcDir) {
    90                         // Generate the necessary build files
    91                         sh './autogen.sh'
    92                 }
    93 
     115        build_stage('Build : configure', true) {
    94116                // Build outside of the src tree to ease cleaning
    95117                dir (BuildDir) {
    96                         //Configure the compilation (Output is not relevant)
     118                        //Configure the conpilation (Output is not relevant)
    97119                        //Use the current directory as the installation target so nothing escapes the sandbox
    98120                        //Also specify the compiler by hand
     
    104126                        }
    105127
    106                         ast = Settings.NewAST ? "--enable-new-ast" : "--disable-new-ast"
    107 
    108                         sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} AR=gcc-ar RANLIB=gcc-ranlib ${targets} ${ast} --quiet --prefix=${BuildDir}"
     128                        sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} ${targets} --quiet"
    109129
    110130                        // Configure libcfa
     
    113133        }
    114134
    115         Tools.BuildStage('Build : cfa-cpp', true) {
     135        build_stage('Build : cfa-cpp', true) {
    116136                // Build outside of the src tree to ease cleaning
    117137                dir (BuildDir) {
     
    124144        }
    125145
    126         Tools.BuildStage('Build : libcfa(debug)', debug) {
     146        build_stage('Build : libcfa(debug)', debug) {
    127147                // Build outside of the src tree to ease cleaning
    128148                dir (BuildDir) {
     
    131151        }
    132152
    133         Tools.BuildStage('Build : libcfa(nodebug)', release) {
     153        build_stage('Build : libcfa(nodebug)', release) {
    134154                // Build outside of the src tree to ease cleaning
    135155                dir (BuildDir) {
     
    137157                }
    138158        }
    139 
    140         Tools.BuildStage('Build : install', true) {
    141                 // Build outside of the src tree to ease cleaning
    142                 dir (BuildDir) {
    143                         sh "make -j 8 --no-print-directory install"
    144                 }
    145         }
    146159}
    147160
    148161def test() {
    149162        try {
    150                 Tools.BuildStage('Test: short', !Settings.RunAllTests) {
     163                build_stage('Test: short', !Settings.RunAllTests) {
    151164                        dir (BuildDir) {
    152165                                //Run the tests from the tests directory
     
    155168                }
    156169
    157                 Tools.BuildStage('Test: full', Settings.RunAllTests) {
     170                build_stage('Test: full', Settings.RunAllTests) {
    158171                        dir (BuildDir) {
    159172                                        //Run the tests from the tests directory
     
    166179                echo "Archiving core dumps"
    167180                dir (BuildDir) {
    168                         archiveArtifacts artifacts: "tests/crashes/**/*,lib/**/lib*.so*", fingerprint: true
     181                        archiveArtifacts artifacts: "tests/crashes/**/*", fingerprint: true
    169182                }
    170183                throw err
     
    173186
    174187def benchmark() {
    175         Tools.BuildStage('Benchmark', Settings.RunBenchmark) {
     188        build_stage('Benchmark', Settings.RunBenchmark) {
    176189                dir (BuildDir) {
    177190                        //Append bench results
     
    182195
    183196def build_doc() {
    184         Tools.BuildStage('Documentation', Settings.BuildDocumentation) {
     197        build_stage('Documentation', Settings.BuildDocumentation) {
    185198                dir ('doc/user') {
    186199                        make_doc()
     
    194207
    195208def publish() {
    196         Tools.BuildStage('Publish', true) {
     209        build_stage('Publish', true) {
    197210
    198211                if( Settings.Publish && !Settings.RunBenchmark ) { echo 'No results to publish!!!' }
     
    202215
    203216                //Then publish the results
    204                 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile'        , groupCompile    , false, 'Compilation')
    205                 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile.diff'   , groupCompile    , true , 'Compilation (relative)')
    206                 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch'      , groupConcurrency, false, 'Context Switching')
    207                 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch.diff' , groupConcurrency, true , 'Context Switching (relative)')
    208                 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex'          , groupConcurrency, false, 'Mutual Exclusion')
    209                 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex.diff'     , groupConcurrency, true , 'Mutual Exclusion (relative)')
    210                 do_plot(Settings.RunBenchmark && Settings.Publish, 'scheduling'     , groupConcurrency, false, 'Internal and External Scheduling')
    211                 do_plot(Settings.RunBenchmark && Settings.Publish, 'scheduling.diff', groupConcurrency, true , 'Internal and External Scheduling (relative)')
     217                do_plot(Settings.RunBenchmark && Settings.Publish, 'compile'       , groupCompile    , false, 'Compilation')
     218                do_plot(Settings.RunBenchmark && Settings.Publish, 'compile.diff'  , groupCompile    , true , 'Compilation (relative)')
     219                do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch'     , groupConcurrency, false, 'Context Switching')
     220                do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch.diff', groupConcurrency, true , 'Context Switching (relative)')
     221                do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex'         , groupConcurrency, false, 'Mutual Exclusion')
     222                do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex.diff'    , groupConcurrency, true , 'Mutual Exclusion (relative)')
     223                do_plot(Settings.RunBenchmark && Settings.Publish, 'signal'        , groupConcurrency, false, 'Internal and External Scheduling')
     224                do_plot(Settings.RunBenchmark && Settings.Publish, 'signal.diff'   , groupConcurrency, true , 'Internal and External Scheduling (relative)')
    212225        }
    213226}
     
    216229//Routine responsible of sending the email notification once the build is completed
    217230//===========================================================================================================
     231@NonCPS
     232def SplitLines(String text) {
     233        def list = []
     234
     235        text.eachLine {
     236                list += it
     237        }
     238
     239        return list
     240}
     241
     242def GitLogMessage() {
     243        if (!Settings || !Settings.GitOldRef || !Settings.GitNewRef) return "\nERROR retrieveing git information!\n"
     244
     245        def oldRef = Settings.GitOldRef
     246        def newRef = Settings.GitNewRef
     247
     248        def revText = sh(returnStdout: true, script: "git rev-list ${oldRef}..${newRef}").trim()
     249        def revList = SplitLines( revText )
     250
     251        def gitUpdate = ""
     252        revList.each { rev ->
     253                def type = sh(returnStdout: true, script: "git cat-file -t ${rev}").trim()
     254                gitUpdate = gitUpdate + "       via  ${rev} (${type})"
     255        }
     256
     257        def rev = oldRef
     258        def type = sh(returnStdout: true, script: "git cat-file -t ${rev}").trim()
     259        gitUpdate = gitUpdate + "      from  ${rev} (${type})"
     260
     261        def gitLog    = sh(returnStdout: true, script: "git rev-list --format=short ${oldRef}...${newRef}").trim()
     262
     263        def gitDiff   = sh(returnStdout: true, script: "git diff --stat --color ${newRef} ${oldRef}").trim()
     264        gitDiff = gitDiff.replace('[32m', '<span style="color: #00AA00;">')
     265        gitDiff = gitDiff.replace('[31m', '<span style="color: #AA0000;">')
     266        gitDiff = gitDiff.replace('[m', '</span>')
     267
     268        return """
     269<pre>
     270The branch ${env.BRANCH_NAME} has been updated.
     271${gitUpdate}
     272</pre>
     273
     274<p>Check console output at ${env.BUILD_URL} to view the results.</p>
     275
     276<p>- Status --------------------------------------------------------------</p>
     277
     278<p>BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}</p>
     279
     280<p>- Log -----------------------------------------------------------------</p>
     281
     282<pre>
     283${gitLog}
     284</pre>
     285
     286<p>-----------------------------------------------------------------------</p>
     287<pre>
     288Summary of changes:
     289${gitDiff}
     290</pre>
     291"""
     292}
     293
    218294//Standard build email notification
    219295def email(boolean log) {
     
    227303generated because of a git hooks/post-receive script following
    228304a ref change which was pushed to the C\u2200 repository.</p>
    229 """ + Tools.GitLogMessage()
     305""" + GitLogMessage()
    230306
    231307        def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca"
     
    249325        public String CXX
    250326        public String CC
    251         public String lto
    252 
    253         CC_Desc(String name, String CXX, String CC, String lto) {
     327
     328        CC_Desc(String name, String CXX, String CC) {
    254329                this.name = name
    255330                this.CXX = CXX
    256                 this.CC  = CC
    257                 this.lto = lto
     331                this.CC = CC
    258332        }
    259333}
     
    275349        public final CC_Desc Compiler
    276350        public final Arch_Desc Architecture
    277         public final Boolean NewAST
    278351        public final Boolean RunAllTests
    279352        public final Boolean RunBenchmark
     
    291364                switch( param.Compiler ) {
    292365                        case 'gcc-9':
    293                                 this.Compiler = new CC_Desc('gcc-9', 'g++-9', 'gcc-9', '-flto=auto')
     366                                this.Compiler = new CC_Desc('gcc-9', 'g++-9', 'gcc-9')
    294367                        break
    295368                        case 'gcc-8':
    296                                 this.Compiler = new CC_Desc('gcc-8', 'g++-8', 'gcc-8', '-flto=auto')
     369                                this.Compiler = new CC_Desc('gcc-8', 'g++-8', 'gcc-8')
    297370                        break
    298371                        case 'gcc-7':
    299                                 this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7', '-flto=auto')
     372                                this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7')
    300373                        break
    301374                        case 'gcc-6':
    302                                 this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6', '-flto=auto')
     375                                this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6')
    303376                        break
    304377                        case 'gcc-5':
    305                                 this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5', '-flto=auto')
     378                                this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5')
    306379                        break
    307380                        case 'gcc-4.9':
    308                                 this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9', '-flto=auto')
     381                                this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9')
    309382                        break
    310383                        case 'clang':
    311                                 this.Compiler = new CC_Desc('clang', 'clang++-10', 'gcc-9', '-flto=thin -flto-jobs=0')
     384                                this.Compiler = new CC_Desc('clang', 'clang++-6.0', 'gcc-6')
    312385                        break
    313386                        default :
     
    327400
    328401                this.IsSandbox          = (branch == "jenkins-sandbox")
    329                 this.NewAST             = param.NewAST
    330402                this.RunAllTests        = param.RunAllTests
    331403                this.RunBenchmark       = param.RunBenchmark
     
    337409                this.DescShort = "${ this.Compiler.name }:${ this.Architecture.name }${full}"
    338410
    339                 final ast = this.NewAST ? "New AST" : "Old AST"
    340411                this.DescLong = """Compiler              : ${ this.Compiler.name } (${ this.Compiler.CXX }/${ this.Compiler.CC })
    341 AST Version             : ${ ast.toString() }
    342412Architecture            : ${ this.Architecture.name }
    343413Arc Flags               : ${ this.Architecture.flags }
     
    369439        // prepare the properties
    370440        properties ([                                                                                                   \
    371                 buildDiscarder(logRotator(                                                                              \
    372                         artifactDaysToKeepStr: '',                                                                      \
    373                         artifactNumToKeepStr: '',                                                                       \
    374                         daysToKeepStr: '730',                                                                           \
    375                         numToKeepStr: '1000'                                                                            \
    376                 )),                                                                                                             \
    377441                [$class: 'ParametersDefinitionProperty',                                                                \
    378442                        parameterDefinitions: [                                                                         \
     
    380444                                        description: 'Which compiler to use',                                   \
    381445                                        name: 'Compiler',                                                                       \
    382                                         choices: 'gcc-9\ngcc-8\ngcc-7\ngcc-6\ngcc-5\ngcc-4.9\nclang',   \
     446                                        choices: 'gcc-9\ngcc-8\ngcc-7\ngcc-6\ngcc-5\ngcc-4.9\nclang',                                   \
    383447                                        defaultValue: 'gcc-8',                                                          \
    384448                                ],                                                                                              \
     
    389453                                        defaultValue: 'x64',                                                            \
    390454                                ],                                                                                              \
    391                                 [$class: 'BooleanParameterDefinition',                                                  \
    392                                         description: 'If true, build compiler using new AST',           \
    393                                         name: 'NewAST',                                                                         \
    394                                         defaultValue: true,                                                             \
    395                                 ],                                                                                              \
    396455                                [$class: 'BooleanParameterDefinition',                                                  \
    397456                                        description: 'If false, only the quick test suite is ran',              \
     
    422481                ]])
    423482
    424         // It's unfortunate but it looks like we need to checkout the entire repo just to get
    425         // - the pretty git printer
    426         // - Jenkins.tools
     483        // It's unfortunate but it looks like we need to checkout the entire repo just to get the pretty git printer
    427484        checkout scm
    428 
    429         Tools = load "Jenkins/tools.groovy"
    430485
    431486        final settings = new BuildSettings(params, env.BRANCH_NAME)
     
    435490
    436491        return settings
     492}
     493
     494def build_stage(String name, boolean run, Closure block ) {
     495        StageName = name
     496        echo " -------- ${StageName} -------- "
     497        if(run) {
     498                stage(name, block)
     499        } else {
     500                stage(name) { Utils.markStageSkippedForConditional(STAGE_NAME) }
     501        }
    437502}
    438503
  • Makefile.am

    reef8dfb rbdfc032  
    1919
    2020MAINTAINERCLEANFILES = lib/* bin/* tests/.deps/* tests/.out/* # order important
    21 DISTCLEANFILES = version
    2221
    2322SUBDIRS = driver src . @LIBCFA_TARGET_DIRS@
    24 DIST_SUBDIRS = driver src . libcfa tests
    2523
    2624@LIBCFA_TARGET_MAKEFILES@ : Makefile $(srcdir)/libcfa/configure
     
    2826        @ls $(config_file) || (echo "Missing config.data, re-run configure script again" && false)
    2927        @$(eval config_data = $(shell cat $(config_file)))
    30         @echo "Configuring libcfa ($(abs_top_srcdir)/libcfa/configure) with '$(config_data)' from $(shell pwd) / $(dir $@)"
     28        @echo "Configuring libcfa with '$(config_data)''"
    3129        @cd $(dir $@) && $(abs_top_srcdir)/libcfa/configure $(config_data)
    3230
     
    3432
    3533man1_MANS = doc/man/cfa.1
    36 
    37 EXTRA_DIST = LICENSE doc/man/cfa.1 libcfa/configure libcfa/Makefile.dist.am libcfa/Makefile.dist.in tools/build/distcc_hash tools/build/push2dist.sh
    3834
    3935debug=yes
     
    5147        @./config.status --config | sed "s/ /\n\t/g; s/\t'/\t/g; s/'\n/\n/g; s/^'//g; s/'$$//g"
    5248        @find libcfa -name config.status -printf "\n%h\n\t" -exec {} --config \; | sed "s/ /\n\t/g; s/\t'/\t/g; s/'\n/\n/g; s/^'//g; s/'$$//g"
    53 
    54 mostlyclean-local: @LIBCFA_TARGET_MAKEFILES@
    55         for dir in @LIBCFA_TARGET_DIRS@; do \
    56                 $(MAKE) -C $${dir} mostlyclean; \
    57         done
    58 
    59 clean-local: @LIBCFA_TARGET_MAKEFILES@
    60         for dir in @LIBCFA_TARGET_DIRS@; do \
    61                 $(MAKE) -C $${dir} clean; \
    62         done
    63 
    64 distclean-local: @LIBCFA_TARGET_MAKEFILES@
    65         for dir in @LIBCFA_TARGET_DIRS@; do \
    66                 $(MAKE) -C $${dir} distclean; \
    67                 rm $${dir}/config.data; \
    68         done
  • benchmark/Makefile.am

    reef8dfb rbdfc032  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Tue Mar 10 11:41:18 2020
    14 ## Update Count     : 258
     13## Last Modified On : Sat Jan 25 09:20:44 2020
     14## Update Count     : 255
    1515###############################################################################
    1616
     
    1919
    2020# applies to both programs
    21 include $(top_srcdir)/tools/build/cfa.make
     21include $(top_srcdir)/src/cfa.make
    2222
    2323AM_CFLAGS = -O2 -Wall -Wextra -I$(srcdir) -lrt -pthread # -Werror
     
    3030BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
    3131BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
    32 BENCH_V_PY = $(__bench_v_PY_$(__quiet))
    3332BENCH_V_RUSTC = $(__bench_v_RUSTC_$(__quiet))
    3433BENCH_V_NODEJS = $(__bench_v_NODEJS_$(__quiet))
     
    4847__bench_v_UPP_verbose = $(AM_V_UPP)
    4948__bench_v_GOC_verbose = $(AM_V_GOC)
    50 __bench_v_PY_verbose = $(AM_V_PY)
    51 __bench_v_RUSTC_verbose = $(AM_V_RUST)
     49__bench_v_RUSTC_verbose = $(AM_V_RUSTC)
    5250__bench_v_NODEJS_verbose = $(AM_V_NODEJS)
    5351__bench_v_JAVAC_verbose = $(AM_V_JAVAC)
     
    6664# Dummy hack tricks
    6765EXTRA_PROGRAMS = dummy # build but do not install
    68 nodist_dummy_SOURCES = dummyC.c dummyCXX.cpp
     66dummy_SOURCES = dummyC.c dummyCXX.cpp
    6967
    7068dummyC.c:
     
    7472        echo "int main() { return 0; }" > ${@}
    7573
    76 .SILENT:                # do not print recipe
     74#.SILENT:               # do not print recipe
     75.ONESHELL:              # use one shell to execute recipe
    7776.NOTPARALLEL:
    78 .PHONY: jenkins cleancsv
    79 
    80 ## =========================================================================================================
    81 
    82 # all is used by make dist so ignore it
    83 all:
    84 
    85 all-bench : basic$(EXEEXT) ctxswitch$(EXEEXT) mutex$(EXEEXT) schedint$(EXEEXT) schedext$(EXEEXT) creation$(EXEEXT)
     77.PHONY: compile.csv basic.csv ctxswitch.csv mutex.csv schedint.csv
     78
     79## =========================================================================================================
     80
     81all : basic$(EXEEXT) ctxswitch$(EXEEXT) mutex$(EXEEXT) schedint$(EXEEXT) schedext$(EXEEXT) creation$(EXEEXT)
    8682
    8783basic_loop_DURATION = 15000000000
     
    111107creation_cfa_coroutine_DURATION = 100000000
    112108creation_cfa_coroutine_eager_DURATION = 10000000
    113 creation_cfa_generator_DURATION = 1000000000
    114109creation_upp_coroutine_DURATION = ${creation_cfa_coroutine_eager_DURATION}
     110creation_cfa_thread_DURATION = 10000000
     111creation_upp_thread_DURATION = ${creation_cfa_thread_DURATION}
    115112creation_DURATION = 10000000
    116113
     
    145142FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@
    146143
    147 cleancsv:
    148         rm -f compile.csv basic.csv ctxswitch.csv mutex.csv schedint.csv
    149 
    150 jenkins$(EXEEXT): cleancsv
     144jenkins$(EXEEXT):
    151145@DOifskipcompile@
    152146        +make compile.csv
    153147        -+make compile.diff.csv
    154148@DOendif@
     149        +make basic.csv
     150        -+make basic.diff.csv
    155151        +make ctxswitch.csv
    156152        -+make ctxswitch.diff.csv
     
    163159        -cat compile.diff.csv
    164160@DOendif@
     161        cat basic.csv
     162        -cat basic.diff.csv
    165163        cat ctxswitch.csv
    166164        -cat ctxswitch.diff.csv
     
    171169
    172170compile.csv:
    173         echo "building $@"
    174171        echo "array,attributes,empty,expression,io,monitor,operators,typeof" > $@
    175172        +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-array.make >> $@
     
    183180        $(srcdir)/fixcsv.sh $@
    184181
     182basic.csv:
     183        echo "generator,coroutine,thread" > $@
     184        +make basic-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
     185        +make basic-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
     186        +make basic-cfa_thread.runquiet >> $@
     187        $(srcdir)/fixcsv.sh $@
     188
    185189ctxswitch.csv:
    186         echo "building $@"
    187190        echo "generator,coroutine,thread" > $@
    188191        +make ctxswitch-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
     
    192195
    193196mutex.csv:
    194         echo "building $@"
    195197        echo "1-monitor,2-monitor" > $@
    196198        +make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
     
    199201
    200202schedint.csv:
    201         echo "building $@"
    202203        echo "schedint-1,schedint-2,schedext-1,schedext-2" > $@
    203204        +make schedint-cfa1.runquiet >> $@ && echo -n ',' >> $@
     
    288289
    289290ctxswitch-python_coroutine$(EXEEXT):
    290         $(BENCH_V_PY)echo "#!/bin/sh" > a.out
    291         echo "python3 $(srcdir)/ctxswitch/python_cor.py \"$$""@\"" >> a.out
     291        echo "#!/bin/sh" > a.out
     292        echo "python3.7 $(srcdir)/ctxswitch/python_cor.py" >> a.out
    292293        chmod a+x a.out
    293294
    294295ctxswitch-nodejs_coroutine$(EXEEXT):
    295         $(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
    296         echo "nodejs $(srcdir)/ctxswitch/node_cor.js \"$$""@\"" >> a.out
     296        echo "#!/bin/sh" > a.out
     297        echo "nodejs $(srcdir)/ctxswitch/node_cor.js" >> a.out
    297298        chmod a+x a.out
    298299
    299300ctxswitch-nodejs_await$(EXEEXT):
    300         $(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
    301         echo "nodejs $(srcdir)/ctxswitch/node_await.js \"$$""@\"" >> a.out
     301        echo "#!/bin/sh" > a.out
     302        echo "nodejs $(srcdir)/ctxswitch/node_await.js" >> a.out
    302303        chmod a+x a.out
    303304
     
    311312        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
    312313        echo "#!/bin/sh" > a.out
    313         echo "java JavaThread \"$$""@\"" >> a.out
     314        echo "java JavaThread" >> a.out
    314315        chmod a+x a.out
    315316
     
    353354        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
    354355        echo "#!/bin/sh" > a.out
    355         echo "java JavaThread \"$$""@\"" >> a.out
     356        echo "java JavaThread" >> a.out
    356357        chmod a+x a.out
    357358
     
    385386        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
    386387        echo "#!/bin/sh" > a.out
    387         echo "java JavaThread \"$$""@\"" >> a.out
     388        echo "java JavaThread" >> a.out
    388389        chmod a+x a.out
    389390
     
    451452
    452453creation-python_coroutine$(EXEEXT):
    453         $(BENCH_V_PY)echo "#!/bin/sh" > a.out
    454         echo "python3 $(srcdir)/creation/python_cor.py \"$$""@\"" >> a.out
     454        echo "#!/bin/sh" > a.out
     455        echo "python3.7 $(srcdir)/creation/python_cor.py" >> a.out
    455456        chmod a+x a.out
    456457
    457458creation-nodejs_coroutine$(EXEEXT):
    458         $(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
    459         echo "nodejs $(srcdir)/creation/node_cor.js \"$$""@\"" >> a.out
     459        echo "#!/bin/sh" > a.out
     460        echo "nodejs $(srcdir)/creation/node_cor.js" >> a.out
    460461        chmod a+x a.out
    461462
     
    469470        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
    470471        echo "#!/bin/sh" > a.out
    471         echo "java JavaThread \"$$""@\"" >> a.out
     472        echo "java JavaThread" >> a.out
    472473        chmod a+x a.out
    473474
     
    477478## =========================================================================================================
    478479
    479 bcompile$(EXEEXT) :             \
     480compile$(EXEEXT) :              \
    480481        compile-array.make      \
    481482        compile-attributes.make \
     
    490491
    491492compile-array$(EXEEXT):
    492         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/array.cfa
     493        $(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
    493494
    494495compile-attributes$(EXEEXT):
    495         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/attributes.cfa
     496        $(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
    496497
    497498compile-empty$(EXEEXT):
    498         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(srcdir)/compile/empty.cfa
     499        $(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
    499500
    500501compile-expression$(EXEEXT):
    501         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/expression.cfa
     502        $(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
    502503
    503504compile-io$(EXEEXT):
    504         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/io1.cfa
     505        $(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
    505506
    506507compile-monitor$(EXEEXT):
    507         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
     508        $(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
    508509
    509510compile-operators$(EXEEXT):
    510         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/operators.cfa
     511        $(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
    511512
    512513compile-thread$(EXEEXT):
    513         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/concurrent/thread.cfa
     514        $(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
    514515
    515516compile-typeof$(EXEEXT):
    516         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/typeof.cfa
    517 
    518 ## =========================================================================================================
    519 
    520 size$(EXEEXT) : size-cfa.runquiet
    521 
    522 size-cfa$(EXEEXT):
    523         $(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 $@) $@
     517        $(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
  • benchmark/creation/JavaThread.java

    reef8dfb rbdfc032  
    11public class JavaThread {
    22        // Simplistic low-quality Marsaglia Shift-XOR pseudo-random number generator.
    3         // Bijective
     3        // Bijective   
    44        // Cycle length for non-zero values is 4G-1.
    55        // 0 is absorbing and should be avoided -- fixed point.
    66        // The returned value is typically masked to produce a positive value.
    7         static volatile int Ticket = 0 ;
     7        static volatile int Ticket = 0 ; 
    88
    99        private static int nextRandom (int x) {
    10                 if (x == 0) {
     10                if (x == 0) { 
    1111                        // reseed the PRNG
    12                         // Ticket is accessed infrequently and does not constitute a coherence hot-spot.
    13                         // Note that we use a non-atomic racy increment -- the race is rare and benign.
    14                         // If the race is a concern switch to an AtomicInteger.
    15                         // In addition accesses to the RW volatile global "Ticket"  variable are not
    16                         // (readily) predictable at compile-time so the JIT will not be able to elide
    17                         // nextRandom() invocations.
    18                         x = ++Ticket ;
    19                         if (x == 0) x = 1 ;
     12                        // Ticket is accessed infrequently and does not constitute a coherence hot-spot. 
     13                        // Note that we use a non-atomic racy increment -- the race is rare and benign. 
     14                        // If the race is a concern switch to an AtomicInteger. 
     15                        // In addition accesses to the RW volatile global "Ticket"  variable are not 
     16                        // (readily) predictable at compile-time so the JIT will not be able to elide 
     17                        // nextRandom() invocations. 
     18                        x = ++Ticket ; 
     19                        if (x == 0) x = 1 ; 
    2020                }
    2121                x ^= x << 6;
    2222                x ^= x >>> 21;
    2323                x ^= x << 7;
    24                 return x ;
     24                return x ;   
    2525        }
    2626        static int x = 2;
    2727
    28         static private long times = Long.parseLong("10000") ;
     28        static private int times = Integer.parseInt("10000") ;
    2929
    3030        public static class MyThread extends Thread {
     
    3333        }
    3434        public static void helper() throws InterruptedException {
    35                 for(long i = 1; i <= times; i += 1) {
     35                for(int i = 1; i <= times; i += 1) {
    3636                        MyThread m = new MyThread();
    3737                        x = nextRandom( x );
     
    4747        }
    4848        public static void main(String[] args) throws InterruptedException {
    49                 if ( args.length > 1 ) System.exit( 1 );
    50                 if ( args.length == 1 ) { times = Long.parseLong(args[0]); }
     49                if ( args.length > 2 ) System.exit( 1 );
     50                if ( args.length == 2 ) { times = Integer.parseInt(args[1]); }
    5151
    52                 for (int i = Integer.parseInt("5"); --i >= 0 ; ) {
     52                for (int i = Integer.parseInt("5"); --i >= 0 ; ) { 
    5353                        InnerMain();
    5454                        Thread.sleep(2000);             // 2 seconds
  • benchmark/creation/cfa_gen.cfa

    reef8dfb rbdfc032  
    1 #include "../bench.h"
     1#include "bench.h"
    22
    3 generator G {
     3struct C {
    44        volatile int restart; // ensure compiler does not optimize away all the code
    55};
    6 void ?{}( G & g ) { g.restart = 0; }
    7 void main( G & ) {}
     6void ?{}( C & c ) { c.restart = 0; }
     7void main( C & ) {}
    88
    99int main( int argc, char * argv[] ) {
     
    1111        BENCH(
    1212                for ( times ) {
    13                          G g;
     13                         C c;
    1414                },
    1515                result
  • benchmark/creation/node_cor.js

    reef8dfb rbdfc032  
    55
    66function * coroutine() { yield }
    7 
    8 for ( var i = 0; i < times; i += 1 ) { // warm jit
    9         cor = coroutine()
    10 }
    11 
    127var hrstart = process.hrtime()
    138for ( var i = 0; i < times; i += 1 ) {
  • benchmark/ctxswitch/JavaThread.java

    reef8dfb rbdfc032  
    11public class JavaThread {
    22        // Simplistic low-quality Marsaglia Shift-XOR pseudo-random number generator.
    3         // Bijective
     3        // Bijective   
    44        // Cycle length for non-zero values is 4G-1.
    55        // 0 is absorbing and should be avoided -- fixed point.
    66        // The returned value is typically masked to produce a positive value.
    7         static volatile int Ticket = 0 ;
     7        static volatile int Ticket = 0 ; 
    88
    99        private static int nextRandom (int x) {
    10                 if (x == 0) {
     10                if (x == 0) { 
    1111                        // reseed the PRNG
    12                         // Ticket is accessed infrequently and does not constitute a coherence hot-spot.
    13                         // Note that we use a non-atomic racy increment -- the race is rare and benign.
    14                         // If the race is a concern switch to an AtomicInteger.
    15                         // In addition accesses to the RW volatile global "Ticket"  variable are not
    16                         // (readily) predictable at compile-time so the JIT will not be able to elide
    17                         // nextRandom() invocations.
    18                         x = ++Ticket ;
    19                         if (x == 0) x = 1 ;
     12                        // Ticket is accessed infrequently and does not constitute a coherence hot-spot. 
     13                        // Note that we use a non-atomic racy increment -- the race is rare and benign. 
     14                        // If the race is a concern switch to an AtomicInteger. 
     15                        // In addition accesses to the RW volatile global "Ticket"  variable are not 
     16                        // (readily) predictable at compile-time so the JIT will not be able to elide 
     17                        // nextRandom() invocations. 
     18                        x = ++Ticket ; 
     19                        if (x == 0) x = 1 ; 
    2020                }
    2121                x ^= x << 6;
    2222                x ^= x >>> 21;
    2323                x ^= x << 7;
    24                 return x ;
     24                return x ;   
    2525        }
    2626        static int x = 2;
    2727
    28         static private long times = Long.parseLong("100000");
     28        static private int times = Integer.parseInt("100000");
    2929
    3030        public static void helper() {
    31                 for(long i = 1; i <= times; i += 1) {
     31                for(int i = 1; i <= times; i += 1) {
    3232                        Thread.yield();
    3333                }
     
    4040        }
    4141        public static void main(String[] args) throws InterruptedException {
    42                 if ( args.length > 1 ) System.exit( 1 );
    43                 if ( args.length == 1 ) { times = Long.parseLong(args[0]); }
     42                if ( args.length > 2 ) System.exit( 1 );
     43                if ( args.length == 2 ) { times = Integer.parseInt(args[1]); }
    4444
    4545                for (int i = Integer.parseInt("5"); --i >= 0 ; ) {
  • benchmark/ctxswitch/cfa_cor.cfa

    reef8dfb rbdfc032  
    22#include <thread.hfa>
    33
    4 #include "../bench.h"
     4#include "bench.h"
    55
    6 coroutine C {};
     6coroutine C {} c;
    77void main( __attribute__((unused)) C & ) {
    8         for () {
    9                 suspend;
     8        while () {
     9                suspend();
    1010        }
    1111}
    1212int main( int argc, char * argv[] ) {
    13         C c;
    1413        BENCH_START()
    1514        BENCH(
  • benchmark/ctxswitch/cfa_gen.cfa

    reef8dfb rbdfc032  
    11#include "../bench.h"
    22
    3 generator G {};
    4 void main( G & ) {
     3typedef struct {
     4        void * next;
     5} C;
     6
     7void comain( C * c ) {
     8        if ( __builtin_expect(c->next != 0, 1) ) goto *(c->next);
     9        c->next = &&s1;
    510        for () {
    6                 suspend;
     11                return;
     12          s1: ;
    713        }
    814}
    915
    1016int main( int argc, char * argv[] ) {
    11         G g;
    1217        BENCH_START()
     18        C c = { 0 };
    1319        BENCH(
    1420                for ( times ) {
    15                         resume( g );
     21                        comain( &c );
    1622                },
    1723                result
  • benchmark/ctxswitch/node_cor.js

    reef8dfb rbdfc032  
    1010}
    1111cor = coroutine()
    12 
    13 for ( var i = 0; i < times; i += 1 ) { // warm git
    14         cor.next();
    15 }
    1612
    1713var hrstart = process.hrtime()
  • benchmark/exclude

    reef8dfb rbdfc032  
    1010interrupt_linux.c
    1111exclude
    12 io
    1312Monitor.c
  • benchmark/mutex/JavaThread.java

    reef8dfb rbdfc032  
    11public class JavaThread {
    22        // Simplistic low-quality Marsaglia Shift-XOR pseudo-random number generator.
    3         // Bijective
     3        // Bijective   
    44        // Cycle length for non-zero values is 4G-1.
    55        // 0 is absorbing and should be avoided -- fixed point.
    66        // The returned value is typically masked to produce a positive value.
    7         static volatile int Ticket = 0 ;
     7        static volatile int Ticket = 0 ; 
    88
    99        private static int nextRandom (int x) {
    10                 if (x == 0) {
     10                if (x == 0) { 
    1111                        // reseed the PRNG
    12                         // Ticket is accessed infrequently and does not constitute a coherence hot-spot.
    13                         // Note that we use a non-atomic racy increment -- the race is rare and benign.
    14                         // If the race is a concern switch to an AtomicInteger.
    15                         // In addition accesses to the RW volatile global "Ticket"  variable are not
    16                         // (readily) predictable at compile-time so the JIT will not be able to elide
    17                         // nextRandom() invocations.
    18                         x = ++Ticket ;
    19                         if (x == 0) x = 1 ;
     12                        // Ticket is accessed infrequently and does not constitute a coherence hot-spot. 
     13                        // Note that we use a non-atomic racy increment -- the race is rare and benign. 
     14                        // If the race is a concern switch to an AtomicInteger. 
     15                        // In addition accesses to the RW volatile global "Ticket"  variable are not 
     16                        // (readily) predictable at compile-time so the JIT will not be able to elide 
     17                        // nextRandom() invocations. 
     18                        x = ++Ticket ; 
     19                        if (x == 0) x = 1 ; 
    2020                }
    2121                x ^= x << 6;
    2222                x ^= x >>> 21;
    2323                x ^= x << 7;
    24                 return x ;
     24                return x ;   
    2525        }
    2626        static int x = 2;
    2727
    28         static private long times = Long.parseLong("100000000");
     28        static private int times = Integer.parseInt("100000000");
    2929
    3030        public synchronized void noop() {
     
    3434                JavaThread j = new JavaThread();
    3535                // Inhibit biased locking ...
    36                 x = (j.hashCode() ^ System.identityHashCode(j)) | 1 ;
    37                 for(long i = 1; i <= times; i += 1) {
     36                x = (j.hashCode() ^ System.identityHashCode(j)) | 1 ;     
     37                for(int i = 1; i <= times; i += 1) {
    3838                        x = nextRandom(x);
    3939                        j.noop();
     
    4747        }
    4848        public static void main(String[] args) throws InterruptedException {
    49                 if ( args.length > 1 ) System.exit( 1 );
    50                 if ( args.length == 1 ) { times = Long.parseLong(args[0]); }
     49                if ( args.length > 2 ) System.exit( 1 );
     50                if ( args.length == 2 ) { times = Integer.parseInt(args[1]); }
    5151
    52                 for (int n = Integer.parseInt("5"); --n >= 0 ; ) {
     52                for (int n = Integer.parseInt("5"); --n >= 0 ; ) { 
    5353                        InnerMain();
    5454                        Thread.sleep(2000);     // 2 seconds
  • benchmark/mutexC/JavaThread.java

    reef8dfb rbdfc032  
    11class Noop {
    22        // Simplistic low-quality Marsaglia Shift-XOR pseudo-random number generator.
    3         // Bijective
     3        // Bijective   
    44        // Cycle length for non-zero values is 4G-1.
    55        // 0 is absorbing and should be avoided -- fixed point.
    66        // The returned value is typically masked to produce a positive value.
    7         static volatile int Ticket = 0 ;
     7        static volatile int Ticket = 0 ; 
    88
    99        public static int nextRandom( int x ) {
    10                 if (x == 0) {
     10                if (x == 0) { 
    1111                        // reseed the PRNG
    12                         // Ticket is accessed infrequently and does not constitute a coherence hot-spot.
    13                         // Note that we use a non-atomic racy increment -- the race is rare and benign.
    14                         // If the race is a concern switch to an AtomicInteger.
    15                         // In addition accesses to the RW volatile global "Ticket"  variable are not
    16                         // (readily) predictable at compile-time so the JIT will not be able to elide
    17                         // nextRandom() invocations.
    18                         x = ++Ticket ;
    19                         if (x == 0) x = 1 ;
     12                        // Ticket is accessed infrequently and does not constitute a coherence hot-spot. 
     13                        // Note that we use a non-atomic racy increment -- the race is rare and benign. 
     14                        // If the race is a concern switch to an AtomicInteger. 
     15                        // In addition accesses to the RW volatile global "Ticket"  variable are not 
     16                        // (readily) predictable at compile-time so the JIT will not be able to elide 
     17                        // nextRandom() invocations. 
     18                        x = ++Ticket ; 
     19                        if (x == 0) x = 1 ; 
    2020                }
    2121                x ^= x << 6;
    2222                x ^= x >>> 21;
    2323                x ^= x << 7;
    24                 return x ;
     24                return x ;   
    2525        }
    2626}
     
    4747        static int x = 2;
    4848
    49         static private long times = Long.parseLong("10000000");
     49        static private int times = Integer.parseInt("10000000");
    5050
    5151        public static void call( Monitor m ) throws InterruptedException {
     
    5353                m.go = true;
    5454                //while ( ! m.go2 );
    55                 for ( long i = 0; i < times; i += 1 ) {
     55                for ( int i = 0; i < times; i += 1 ) {
    5656                        m.call();
    5757                        x = Noop.nextRandom( x );
     
    7171        public static void main( String[] args ) throws InterruptedException {
    7272                if ( args.length > 2 ) System.exit( 1 );
    73                 if ( args.length == 2 ) { times = Long.parseLong(args[1]); }
     73                if ( args.length == 2 ) { times = Integer.parseInt(args[1]); }
    7474
    75                 for ( int i = Integer.parseInt("5"); --i >= 0 ; ) {
     75                if ( args.length > 2 ) System.exit( 1 );
     76                if ( args.length == 2 ) { times = Integer.parseInt(args[1]); }
     77
     78                for ( int i = Integer.parseInt("5"); --i >= 0 ; ) {
    7679                        InnerMain();
    7780                        // Thread.sleep(2000);  // 2 seconds
  • benchmark/schedint/JavaThread.java

    reef8dfb rbdfc032  
    2424public class JavaThread {
    2525        // Simplistic low-quality Marsaglia Shift-XOR pseudo-random number generator.
    26         // Bijective
     26        // Bijective   
    2727        // Cycle length for non-zero values is 4G-1.
    2828        // 0 is absorbing and should be avoided -- fixed point.
    2929        // The returned value is typically masked to produce a positive value.
    30         static volatile int Ticket = 0 ;
     30        static volatile int Ticket = 0 ; 
    3131
    3232        private static int nextRandom (int x) {
    33                 if (x == 0) {
     33                if (x == 0) { 
    3434                        // reseed the PRNG
    35                         // Ticket is accessed infrequently and does not constitute a coherence hot-spot.
    36                         // Note that we use a non-atomic racy increment -- the race is rare and benign.
    37                         // If the race is a concern switch to an AtomicInteger.
    38                         // In addition accesses to the RW volatile global "Ticket"  variable are not
    39                         // (readily) predictable at compile-time so the JIT will not be able to elide
    40                         // nextRandom() invocations.
    41                         x = ++Ticket ;
    42                         if (x == 0) x = 1 ;
     35                        // Ticket is accessed infrequently and does not constitute a coherence hot-spot. 
     36                        // Note that we use a non-atomic racy increment -- the race is rare and benign. 
     37                        // If the race is a concern switch to an AtomicInteger. 
     38                        // In addition accesses to the RW volatile global "Ticket"  variable are not 
     39                        // (readily) predictable at compile-time so the JIT will not be able to elide 
     40                        // nextRandom() invocations. 
     41                        x = ++Ticket ; 
     42                        if (x == 0) x = 1 ; 
    4343                }
    4444                x ^= x << 6;
    4545                x ^= x >>> 21;
    4646                x ^= x << 7;
    47                 return x ;
     47                return x ;   
    4848        }
    4949        static int x = 2;
    5050
    51         static private long times = Long.parseLong("1000000");
     51        static private int times = Integer.parseInt("1000000");
    5252
    5353        public static void helper( Monitor m ) throws InterruptedException {
    54                 for(long i = 1; i <= times; i += 1) {
     54                for(int i = 1; i <= times; i += 1) {
    5555                        m.wait();               // relase monitor lock
    5656                        m.next = true;
     
    7575        }
    7676        public static void main(String[] args) throws InterruptedException {
    77                 if ( args.length > 1 ) System.exit( 1 );
    78                 if ( args.length == 1 ) { times = Long.parseLong(args[0]); }
     77                if ( args.length > 2 ) System.exit( 1 );
     78                if ( args.length == 2 ) { times = Integer.parseInt(args[1]); }
    7979
    80                 for (int n = Integer.parseInt("5"); --n >= 0 ; ) {
     80                for (int n = Integer.parseInt("5"); --n >= 0 ; ) { 
    8181                        InnerMain();
    8282                        Thread.sleep(2000);     // 2 seconds
  • configure.ac

    reef8dfb rbdfc032  
    33
    44AC_PREREQ([2.68])
    5 AC_INIT([cfa-cc],[1.0.0],[cforall@plg.uwaterloo.ca])
     5AC_INIT([cfa-cc],[1.0.0.0],[cforall@plg.uwaterloo.ca])
    66AC_CONFIG_AUX_DIR([automake])
    77AC_CONFIG_MACRO_DIRS([automake])
     8#AC_CONFIG_SRCDIR([src/main.cc])
    89AC_CONFIG_HEADERS([config.h:src/config.h.in])
    910AM_SILENT_RULES([yes])
    1011
    11 m4_include([tools/build/cfa.m4])
     12m4_include([automake/cfa.m4])
    1213
    1314# don't use the default CFLAGS as they unconditonnaly add -O2
    1415: ${CFLAGS=""}
    15 : ${CXXFLAGS=""}
    1616
    1717AM_INIT_AUTOMAKE([subdir-objects])
     
    2424#Trasforming cc1 will break compilation
    2525M4CFA_PROGRAM_NAME
    26 
    27 #==============================================================================
    28 # New AST toggling support
    29 AH_TEMPLATE([CFA_USE_NEW_AST],[Sets whether or not to use the new-ast, this is adefault value and can be overrided by --old-ast and --new-ast])
    30 DEFAULT_NEW_AST="True"
    31 AC_ARG_ENABLE(new-ast,
    32         [  --enable-new-ast     whether or not to use new ast as the default AST algorithm],
    33         [case "${enableval}" in
    34                 yes) newast=true ; DEFAULT_NEW_AST="True"  ;;
    35                 no)  newast=false; DEFAULT_NEW_AST="False" ;;
    36                 *) AC_MSG_ERROR([bad value ${enableval} for --enable-new-ast]) ;;
    37         esac],[newast=true])
    38 AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast)
    39 AC_SUBST(DEFAULT_NEW_AST)
    4026
    4127#==============================================================================
     
    7864        enable_distcc=$enableval, enable_distcc=no)
    7965
    80 AC_ARG_WITH(bwlimit,
    81         [  --with-bwlimit=RATE     RATE the maximum rate at which rsync will be limited when using distributed builds],
    82         [], [])
    83 
    8466AM_CONDITIONAL([ENABLE_DISTCC], [test x$enable_distcc = xyes])
    8567HAS_DISTCC="False"
     
    10385# Create variables for commonly used targets
    10486
    105 TOP_SRCDIR="$(readlink -e $ac_abs_confdir/)/"
    106 TOP_BUILDDIR="$(readlink -e $ac_pwd/)/"
     87TOP_SRCDIR="$(readlink -m $ac_confdir/)/"
     88TOP_BUILDDIR="$(readlink -m $ac_pwd/)/"
    10789
    10890AC_DEFINE_UNQUOTED(TOP_SRCDIR, "$TOP_SRCDIR", [Top src directory])
     
    139121                \'--enable-gprofiler=*) ;;
    140122                \'--disable-gprofiler) ;;
    141 
    142                 # skip the target hosts
    143                 \'--enable-new-ast=*) ;;
    144                 \'--disable-new-ast) ;;
    145 
    146                 # skip this, it only causes problems
    147                 \'--srcdir=*) ;;
    148123
    149124                # append all other arguments to the sub configure arguments
     
    211186
    212187        LIBCFA_TARGET_DIRS="${LIBCFA_TARGET_DIRS} ${lib_dir}"
    213         LIBCFA_1TARGET_DIR="${lib_dir}"
    214188        LIBCFA_TARGET_MAKEFILES="${LIBCFA_TARGET_MAKEFILES} ${lib_dir}/Makefile"
    215189
     
    223197
    224198AC_SUBST(LIBCFA_TARGET_DIRS)
    225 AC_SUBST(LIBCFA_1TARGET_DIR)
    226199AC_SUBST(LIBCFA_TARGET_MAKEFILES)
    227200
     
    289262        driver/Makefile
    290263        src/Makefile
    291         libcfa/Makefile:libcfa/Makefile.dist.in
     264        benchmark/Makefile
    292265        tests/Makefile
     266        longrun_tests/Makefile
     267        tools/Makefile
     268        tools/prettyprinter/Makefile
    293269        ])
    294 
    295 # Some of our makefile don't need to be distributed
    296 AM_CONDITIONAL([CFORALL_DISTRIBUTE], [test -e $TOP_SRCDIR/autogen.sh])
    297 AM_COND_IF([CFORALL_DISTRIBUTE], [
    298         AC_CONFIG_FILES([
    299                 longrun_tests/Makefile
    300                 benchmark/Makefile
    301                 benchmark/io/http/Makefile
    302                 tools/Makefile
    303                 tools/prettyprinter/Makefile
    304         ])
    305 
    306         AC_OUTPUT(benchmark/Cargo.toml)
    307 ])
    308270
    309271AC_CONFIG_LINKS([tests/test.py:tests/test.py])
  • doc/LaTeXmacros/common.tex

    reef8dfb rbdfc032  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon Oct  5 09:34:46 2020
    14 %% Update Count     : 464
     13%% Last Modified On : Fri May 24 07:59:54 2019
     14%% Update Count     : 382
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    3636% Names used in the document.
    3737
    38 \usepackage{xspace}
    3938\newcommand{\CFAIcon}{\textsf{C}\raisebox{\depth}{\rotatebox{180}{\textsf{A}}}\xspace} % Cforall symbolic name
    4039\newcommand{\CFA}{\protect\CFAIcon}             % safe for section/caption
     
    5554\newlength{\parindentlnth}
    5655\setlength{\parindentlnth}{\parindent}
     56
     57\newcommand{\LstBasicStyle}[1]{{\lst@basicstyle{#1}}}
     58\newcommand{\LstKeywordStyle}[1]{{\lst@basicstyle{\lst@keywordstyle{#1}}}}
     59\newcommand{\LstCommentStyle}[1]{{\lst@basicstyle{\lst@commentstyle{#1}}}}
     60
     61\newlength{\gcolumnposn}                                % temporary hack because lstlisting does not handle tabs correctly
     62\newlength{\columnposn}
     63\setlength{\gcolumnposn}{2.75in}
     64\setlength{\columnposn}{\gcolumnposn}
     65\newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\lst@basicstyle{\LstCommentStyle{#2}}}}
     66\newcommand{\CRT}{\global\columnposn=\gcolumnposn}
     67
     68% allow escape sequence in lstinline
     69%\usepackage{etoolbox}
     70%\patchcmd{\lsthk@TextStyle}{\let\lst@DefEsc\@empty}{}{}{\errmessage{failed to patch}}
    5771
    5872\usepackage{pslatex}                                    % reduce size of san serif font
     
    227241}%
    228242
    229 \usepackage{listings}                                                                   % format program code
    230243\usepackage{lstlang}
    231 \makeatletter
    232 
    233 \newcommand{\LstBasicStyle}[1]{{\lst@basicstyle{#1}}}
    234 \newcommand{\LstKeywordStyle}[1]{{\lst@basicstyle{\lst@keywordstyle{#1}}}}
    235 \newcommand{\LstCommentStyle}[1]{{\lst@basicstyle{\lst@commentstyle{#1}}}}
    236 
    237 \newlength{\gcolumnposn}                                % temporary hack because lstlisting does not handle tabs correctly
    238 \newlength{\columnposn}
    239 \setlength{\gcolumnposn}{2.75in}
    240 \setlength{\columnposn}{\gcolumnposn}
    241 \newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\lst@basicstyle{\LstCommentStyle{#2}}}}
    242 \newcommand{\CRT}{\global\columnposn=\gcolumnposn}
    243 
    244 % allow escape sequence in lstinline
    245 %\usepackage{etoolbox}
    246 %\patchcmd{\lsthk@TextStyle}{\let\lst@DefEsc\@empty}{}{}{\errmessage{failed to patch}}
    247 
    248 % allow adding to lst literate
    249 \def\addToLiterate#1{\protect\edef\lst@literate{\unexpanded\expandafter{\lst@literate}\unexpanded{#1}}}
    250 \lst@Key{add to literate}{}{\addToLiterate{#1}}
    251 \makeatother
    252 
    253 \newcommand{\CFAStyle}{%
     244
     245\newcommand{\CFADefaults}{%
    254246\lstset{
     247language=CFA,
    255248columns=fullflexible,
    256249basicstyle=\linespread{0.9}\sf,                 % reduce line spacing and use sanserif font
     
    267260belowskip=3pt,
    268261% replace/adjust listing characters that look bad in sanserif
    269 literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1
     262literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1
    270263        {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1
    271264        {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex\textgreater}2,
    272 }% lstset
    273 }% CFAStyle
    274 
    275 \ifdefined\CFALatin% extra Latin-1 escape characters
    276 \lstnewenvironment{cfa}[1][]{
    277 \lstset{
    278 language=CFA,
    279265moredelim=**[is][\color{red}]{Ā®}{Ā®},    % red highlighting Ā®...Ā® (registered trademark symbol) emacs: C-q M-.
    280266moredelim=**[is][\color{blue}]{ß}{ß},   % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_
    281267moredelim=**[is][\color{OliveGreen}]{¢}{¢}, % green highlighting ¢...¢ (cent symbol) emacs: C-q M-"
    282268moredelim=[is][\lstset{keywords={}}]{¶}{¶}, % keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^
    283 % replace/adjust listing characters that look bad in sanserif
    284 add to literate={`}{\ttfamily\upshape\hspace*{-0.1ex}`}1
    285269}% lstset
    286 \lstset{#1}
    287 }{}
     270}% CFADefaults
     271\newcommand{\CFAStyle}{%
     272\CFADefaults
    288273% inline code Ā©...Ā© (copyright symbol) emacs: C-q M-)
    289274\lstMakeShortInlineĀ©                                    % single-character for \lstinline
    290 \else% regular ASCI characters
    291 \lstnewenvironment{cfa}[1][]{
    292 \lstset{
    293 language=CFA,
    294 escapechar=\$,                                                  % LaTeX escape in CFA code
    295 moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
    296 }% lstset
    297 \lstset{#1}
    298 }{}
    299 % inline code @...@ (at symbol)
    300 \lstMakeShortInline@                                    % single-character for \lstinline
    301 \fi%
     275}% CFAStyle
     276
     277\lstnewenvironment{cfa}[1][]
     278{\CFADefaults\lstset{#1}}
     279{}
    302280
    303281% Local Variables: %
  • doc/LaTeXmacros/lstlang.sty

    reef8dfb rbdfc032  
    88%% Created On       : Sat May 13 16:34:42 2017
    99%% Last Modified By : Peter A. Buhr
    10 %% Last Modified On : Wed Sep 23 22:40:04 2020
    11 %% Update Count     : 24
     10%% Last Modified On : Tue Jan  8 14:40:33 2019
     11%% Update Count     : 21
    1212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1313
     
    115115                auto, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__,
    116116                coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally,
    117                 __float80, float80, __float128, float128, forall, ftype, generator, _Generic, _Imaginary, __imag, __imag__,
     117                __float80, float80, __float128, float128, forall, ftype, _Generic, _Imaginary, __imag, __imag__,
    118118                inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or,
    119                 otype, restrict, __restrict, __restrict__, __signed, __signed__, _Static_assert, suspend, thread,
     119                otype, restrict, __restrict, __restrict__, __signed, __signed__, _Static_assert, thread,
    120120                _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,
    121121                virtual, __volatile, __volatile__, waitfor, when, with, zero_t,
     
    125125
    126126% C++ programming language
    127 \lstdefinelanguage{C++}[ANSI]{C++}{
    128         morekeywords={nullptr,}
    129 }
     127\lstdefinelanguage{C++}[ANSI]{C++}{}
    130128
    131129% uC++ programming language, based on ANSI C++
  • doc/bibliography/pl.bib

    reef8dfb rbdfc032  
    99%    Predefined journal names:
    1010%  acmcs: Computing Surveys             acta: Acta Infomatica
     11@string{acta="Acta Infomatica"}
    1112%  cacm: Communications of the ACM
    1213%  ibmjrd: IBM J. Research & Development ibmsj: IBM Systems Journal
     
    2122%  tcs: Theoretical Computer Science
    2223
    23 @string{acta="Acta Infomatica"}
    2424string{ieeepds="IEEE Transactions on Parallel and Distributed Systems"}
    2525@string{ieeepds="IEEE Trans. Parallel Distrib. Syst."}
     
    124124    series      = {ACM Distinguished Dissertations},
    125125    year        = 1983,
    126 }
    127 
    128 @article{Zhang19,
    129     keywords    = {Algebraic effects, dynamic scoping, exceptions, parametricity, type systems},
    130     author      = {Zhang, Yizhou and Myers, Andrew C.},
    131     title       = {Abstraction-safe Effect Handlers via Tunneling},
    132     journal     = {Proc. ACM Program. Lang.},
    133     issue_date  = {January 2019},
    134     volume      = {3},
    135     number      = {POPL},
    136     month       = jan,
    137     year        = {2019},
    138     issn        = {2475-1421},
    139     pages       = {5:1--5:29},
    140     articleno   = {5},
    141     publisher   = {ACM},
    142     address     = {New York, NY, USA},
    143 }
    144 
    145 @inproceedings{Zhang16,
    146     keywords    = {Exception tunneling, Genus, exception handling},
    147     author      = {Zhang, Yizhou and Salvaneschi, Guido and Beightol, Quinn and Liskov, Barbara and Myers, Andrew C.},
    148     title       = {Accepting Blame for Safe Tunneled Exceptions},
    149     booktitle   = {Proceedings of the 37th ACM SIGPLAN Conference on Programming Language Design and Implementation},
    150     series      = {PLDI'16},
    151     year        = {2016},
    152     location    = {Santa Barbara, CA, USA},
    153     pages       = {281--295},
    154     publisher   = {ACM},
    155     address     = {New York, NY, USA},
    156126}
    157127
     
    428398    journal     = sigplan,
    429399    year        = 1981,
    430     month       = feb,
    431     volume      = 16,
    432     number      = 2,
    433     pages       = {48-52},
     400    month       = feb, volume = 16, number = 2, pages = {48-52},
    434401    comment     = {
    435402        A one-pass, top-down algorithm for overload resolution.  Input is a
     
    510477    title       = {An Alternative to Subclassing},
    511478    journal     = sigplan,
    512     volume      = {21},
    513     number      = {11},
     479    volume      = {21},    number = {11},
    514480    pages       = {424-428},
    515     month       = nov,
    516     year        = 1986,
     481    month       = nov, year = 1986,
    517482    comment     = {
    518483        The Smalltalk class hierarchy has three uses: factoring out code;
     
    568533    isbn        = {3-540-66538-2},
    569534    location    = {Toulouse, France},
     535    doi         = {http://doi.acm.org/10.1145/318773.319251},
    570536    publisher   = {Springer},
    571537    address     = {London, UK},
     
    665631    year        = 2010,
    666632    pages       = {39--50},
     633    numpages    = {12},
    667634    publisher   = {IEEE Computer Society},
    668635    address     = {Washington, DC, USA},
     
    955922}
    956923
    957 @manual{C99,
    958     keywords    = {ISO/IEC C 9899},
    959     contributer = {pabuhr@plg},
    960     key         = {C99},
    961     title       = {C Programming Language {ISO/IEC} 9899:1999(E)},
    962     edition     = {2nd},
    963     organization= {International Standard Organization},
    964     address     = {Geneva, Switzerland},
    965     year        = 1999,
    966     note        = {\href{https://webstore.ansi.org/Standards/INCITS/INCITSISOIEC98991999R2005}{https://webstore.ansi.org/\-Standards/\-INCITS/\-INCITSISOIEC98991999R2005}},
    967 }
    968 
    969924@manual{C11,
    970925    keywords    = {ISO/IEC C 11},
     
    973928    title       = {C Programming Language {ISO/IEC} 9889:2011-12},
    974929    edition     = {3rd},
    975     organization= {International Standard Organization},
    976     address     = {Geneva, Switzerland},
     930    publisher   = {International Standard Organization},
     931    address     = {\href{https://www.iso.org/standard/57853.html}{https://\-www.iso.org/\-standard/\-57853.html}},
    977932    year        = 2012,
    978     note        = {\href{https://www.iso.org/standard/57853.html}{https://\-www.iso.org/\-standard/\-57853.html}},
    979933}
    980934
     
    984938    key         = {Concepts},
    985939    title       = {{C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Programming language -- Extensions for concepts {ISO/IEC} {TS} 19217:2015},
    986     organization= {International Standard Organization},
    987     address     = {Geneva, Switzerland},
     940    publisher   = {International Standard Organization},
     941    address     = {\href{https://www.iso.org/standard/64031.html}{https://\-www.iso.org/\-standard/\-64031.html}},
    988942    year        = 2015,
    989     note        = {\href{https://www.iso.org/standard/64031.html}{https://\-www.iso.org/\-standard/\-64031.html}},
    990943}
    991944
     
    1004957}
    1005958
    1006 @misc{CforallConcurrentBenchmarks,
     959@misc{CforallBenchMarks,
    1007960    contributer = {pabuhr@plg},
    1008961    key         = {Cforall Benchmarks},
    1009962    author      = {{\textsf{C}{$\mathbf{\forall}$} Benchmarks}},
    1010     howpublished= {\href{https://github.com/cforall/ConcurrentBenchmarks_SPE20}{https://\-github.com/\-cforall/\-ConcurrentBenchmarks\_SPE20}},
     963    howpublished= {\href{https://plg.uwaterloo.ca/~cforall/benchmark.tar}{https://\-plg.uwaterloo.ca/\-$\sim$cforall/\-benchmark.tar}},
    1011964}
    1012965
     
    11521105    title       = {C\# Language Specification, Standard ECMA-334},
    11531106    organization= {ECMA International Standardizing Information and Communication Systems},
    1154     address     = {Geneva, Switzerland},
    11551107    month       = jun,
    11561108    year        = 2006,
     
    13021254    title       = {Programming Languages -- {Cobol} ISO/IEC 1989:2014},
    13031255    edition     = {2nd},
    1304     organization= {International Standard Organization},
    1305     address     = {Geneva, Switzerland},
     1256    institution = {International Standard Organization},
     1257    address     = {\href{https://www.iso.org/standard/51416.html}{https://\-www.iso.org/\-standard/\-51416.html}},
    13061258    year        = 2014,
    1307     note        = {\href{https://www.iso.org/standard/51416.html}{https://\-www.iso.org/\-standard/\-51416.html}},
    13081259}
    13091260
     
    13541305    location    = {London, United Kingdom},
    13551306    pages       = {41--53},
     1307    numpages    = {13},
     1308    url         = {http://doi.acm.org/10.1145/360204.360207},
     1309    doi         = {10.1145/360204.360207},
     1310    acmid       = {360207},
    13561311    publisher   = {ACM},
    13571312    address     = {New York, NY, USA},
     
    16591614    title       = {$\mu${C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Annotated Reference Manual, Version 7.0.0},
    16601615    organization= {University of Waterloo},
    1661     address     = {Waterloo Ontario, Canada},
    16621616    month       = sep,
    16631617    year        = 2018,
     
    19791933    title       = {Cooperating Sequential Processes},
    19801934    institution = {Technological University},
    1981     address     = {Eindhoven, Neth.},
     1935    address     = {Eindhoven, Netherlands},
    19821936    year        = 1965,
    19831937    note        = {Reprinted in \cite{Genuys68} pp. 43--112.}
     
    19881942    author      = {Adya, Atul and Howell, Jon and Theimer, Marvin and Bolosky, William J. and Douceur, John R.},
    19891943    title       = {Cooperative Task Management Without Manual Stack Management},
    1990     booktitle   = {Proc. of the General Track USENIX Tech. Conf.},
     1944    booktitle   = {Proceedings of the General Track of the Annual Conference on USENIX Annual Technical Conference},
    19911945    series      = {ATEC '02},
    19921946    year        = {2002},
     
    20922046    author      = {Walter Bright and Andrei Alexandrescu},
    20932047    organization= {Digital Mars},
    2094     address     = {Vienna Virginia, U.S.A.},
    20952048    year        = 2016,
    20962049    note        = {\href{http://dlang.org/spec/spec.html}{http://\-dlang.org/\-spec/\-spec.html}},
     
    24552408    year        = 1993,
    24562409    pages       = {201--208},
     2410    url         = {http://doi.acm.org/10.1145/155360.155580},
    24572411    publisher   = {ACM},
    24582412    address     = {New York, NY, USA},
     
    26522606    location    = {Boulder, Colorado, USA},
    26532607    pages       = {91--97},
     2608    numpages    = {7},
    26542609    publisher   = {ACM},
    26552610    address     = {New York, NY, USA},
     
    26822637    issn        = {0004-5411},
    26832638    pages       = {215--225},
     2639    numpages    = {11},
     2640    url         = {http://doi.acm.org/10.1145/321879.321884},
     2641    doi         = {10.1145/321879.321884},
     2642    acmid       = {321884},
    26842643    publisher   = {ACM},
    26852644    address     = {New York, NY, USA},
     
    27492708}
    27502709
    2751 @misc{Drepper13,
    2752     keywords    = {thread-local storage},
    2753     contributer = {pabuhr@plg},
    2754     author      = {Ulrich Drepper},
    2755     title       = {{ELF} Handling For Thread-Local Storage},
    2756     year        = 2013,
    2757     month       = aug,
    2758     note        = {WikipediA},
    2759     howpublished= {\href{http://www.akkadia.org/drepper/tls.pdf}
    2760                   {http://\-www.akkadia.org/\-drepper/\-tls.pdf}},
    2761 }
    2762 
    27632710@misc{Turley99,
    27642711    keywords    = {embedded system, micrprocessor},
     
    27712718    howpublished= {\href{https://www.eetimes.com/author.asp?sectionid=36&doc_id=1287712}
    27722719                  {https://\-www.eetimes.com/\-author.asp?sectionid=\-36&doc_id=1287712}},
    2773 }
    2774 
    2775 @article{Xiao19,
    2776     keywords    = {bug classification, fault trigger, Linux operating system, regression bug},
    2777     contributer = {pabuhr@plg},
    2778     author      = {Guanping Xiao and Zheng Zheng and Beibei Yin and Kishor S. Trivedi and Xiaoting Du and Kai-Yuan Cai},
    2779     title       = {An Empirical Study of Fault Triggers in the Linux Operating System: An Evolutionary Perspective},
    2780     journal     = {IEEE Transactions on Reliability},
    2781     month       = dec,
    2782     year        = 2019,
    2783     volume      = 68,
    2784     number      = 4,
    2785     pages       = {1356-1383},
    27862720}
    27872721
     
    32033137}
    32043138
    3205 @inproceedings{Palix11,
    3206     keywords    = {Linux, fault-finding tools},
    3207     contributer = {pabuhr@plg},
    3208     author      = {Nicolas Palix and Ga\"el Thomas and Suman Saha and Christophe Calv\`es and Julia Lawall and Gilles Muller},
    3209     title       = {Faults in Linux: Ten Years Later},
    3210     booktitle   = {Proc. of the 16 International Conf. on Arch. Support for Prog. Lang. and Oper. Sys.},
    3211     series      = {ASPLOS'11},
    3212     month       = mar,
    3213     year        = 2011,
    3214     location    = {Newport Beach, California, USA},
    3215     pages       = {305-318},
    3216     publisher   = {ACM},
    3217     address     = {New York, NY, USA},
    3218 }
    3219 
    32203139@article{Lamport87,
    32213140    keywords    = {software solutions, mutual exclusion, fast},
     
    33393258    issn        = {0001-0782},
    33403259    pages       = {107--115},
     3260    numpages    = {9},
     3261    url         = {http://doi.acm.org/10.1145/1538788.1538814},
     3262    doi         = {10.1145/1538788.1538814},
     3263    acmid       = {1538814},
    33413264    publisher   = {ACM},
    33423265    address     = {New York, NY, USA},
     
    33603283    title       = {Programming Languages -- {Fortran} Part 1:Base Language ISO/IEC 1539-1:2010},
    33613284    edition     = {3rd},
    3362     organization= {International Standard Organization},
    3363     address     = {Geneva, Switzerland},
     3285    publisher   = {International Standard Organization},
     3286    address     = {\href{https://www.iso.org/standard/50459.html}{https://\-www.iso.org/\-standard/\-50459.html}},
    33643287    year        = 2010,
    3365     note        = {\href{https://www.iso.org/standard/50459.html}{https://\-www.iso.org/\-standard/\-50459.html}},
    33663288}
    33673289
     
    33723294    title       = {Programming Languages -- {Fortran} Part 1:Base Language ISO/IEC 1539-1:2018},
    33733295    edition     = {4rd},
    3374     organization= {International Standard Organization},
    3375     address     = {Geneva, Switzerland},
     3296    publisher   = {International Standard Organization},
     3297    address     = {\href{https://www.iso.org/standard/72320.html}{https://\-www.iso.org/\-standard/\-72320.html}},
    33763298    year        = 2018,
    3377     note        = {\href{https://www.iso.org/standard/72320.html}{https://\-www.iso.org/\-standard/\-72320.html}},
    33783299}
    33793300
     
    37433664}
    37443665
    3745 @mastersthesis{Radhakrishnan19,
    3746     author      = {Srihari Radhakrishnan},
    3747     title       = {High Performance Web Servers: A Study In Concurrent Programming Models},
    3748     school      = {School of Computer Sc., University of Waterloo},
    3749     year        = 2019,
    3750     optaddress  = {Waterloo, Ontario, Canada, N2L 3G1},
    3751     note        = {\href{https://uwspace.uwaterloo.ca/handle/10012/14706}{https://\-uwspace.uwaterloo.ca/\-handle/\-10012/\-14706}},
    3752 }
    3753 
    37543666@article{katzenelson83b,
    37553667    contributer = {gjditchfield@plg},
     
    37853697    pages       = {115-138},
    37863698    year        = 1971,
    3787 }
    3788 
    3789 @inproceedings{Hagersten03,
    3790     keywords    = {cache storage, parallel architectures, performance evaluation, shared memory systems},
    3791     author      = {Zoran Radovi\'{c} and Erik Hagersten},
    3792     title       = {Hierarchical backoff locks for nonuniform communication architectures},
    3793     booktitle   = {Proceedings of the Ninth International Symposium on High-Performance Computer Architecture},
    3794     year        = {2003},
    3795     location    = {Anaheim, CA, USA},
    3796     pages       = {241-252},
    3797     publisher   = {IEEE},
    37983699}
    37993700
     
    44644365}
    44654366
    4466 @misc{gccValueLabels,
    4467     keywords    = {gcc extension, value labels},
    4468     contributer = {pabuhr@plg},
    4469     key         = {Labels as Values},
    4470     author      = {{gcc Extension}},
    4471     title       = {Labels as Values},
    4472     year        = {since gcc-3},
    4473     howpublished= {\href{https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html}
    4474                   {https:\-//gcc.gnu.org/\-onlinedocs/\-gcc/\-Labels-as-Values.html}},
    4475 }
    4476 
    44774367@mastersthesis{Clarke90,
    44784368    keywords    = {concurrency, postponing requests},
     
    45334423}
    45344424
    4535 @misc{libfibre,
    4536     key         = {libfibre},
    4537     author      = {Martin Karsten},
    4538     title       = {{libfibre:~User-Level Threading Runtime}},
    4539     howpublished= {\href{https://git.uwaterloo.ca/mkarsten/libfibre}
    4540                   {https://\-git.uwaterloo.ca/\-mkarsten/\-libfibre}},
    4541     note        = {[Online; accessed 2020-04-15]},
    4542 }
    4543 
    45444425@article{Linda,
    45454426    keywords    = {Linda, concurrency},
     
    45754456}
    45764457
    4577 @inproceedings{Fang06,
    4578     author      = {Fang, Yi and McMillan, Kenneth L. and Pnueli, Amir and Zuck, Lenore D.},
    4579     editor      = {Najm, Elie and Pradat-Peyre, Jean-Fran{\c{c}}ois and Donzeau-Gouge, V{\'e}ronique Vigui{\'e}},
    4580     title       = {Liveness by Invisible Invariants},
    4581     booktitle   = {Formal Techniques for Networked and Distributed Systems - FORTE 2006},
    4582     year        = 2006,
    4583     publisher   = {Springer Berlin Heidelberg},
    4584     address     = {Berlin, Heidelberg},
    4585     pages       = {356--371},
    4586 }
    4587 
    45884458@article{Pierce00,
    4589     keywords    = {Scala, polymorphism, subtyping, type inference},
     4459    keywords    = {Scala},
    45904460    contributer = {a3moss@uwaterloo.ca},
    45914461    author      = {Pierce, Benjamin C. and Turner, David N.},
     
    45994469    issn        = {0164-0925},
    46004470    pages       = {1--44},
     4471    numpages    = {44},
     4472    url         = {http://doi.acm.org/10.1145/345099.345100},
     4473    doi         = {10.1145/345099.345100},
     4474    acmid       = {345100},
    46014475    publisher   = {ACM},
    46024476    address     = {New York, NY, USA},
     4477    keywords    = {polymorphism, subtyping, type inference},
    46034478}
    4604 
    4605 @article{Dice15,
    4606     keywords    = {Concurrency, NUMA, hierarchical locks, locks, multicore, mutex, mutual exclusion, spin locks},
    4607     author      = {Dice, David and Marathe, Virendra J. and Shavit, Nir},
    4608     title       = {Lock Cohorting: A General Technique for Designing NUMA Locks},
    4609     journal     = {ACM Trans. Parallel Comput.},
    4610     issue_date  = {January 2015},
    4611     volume      = 1,
    4612     number      = 2,
    4613     month       = feb,
    4614     year        = 2015,
    4615     pages       = {13:1--13:42},
    4616     publisher   = {ACM},
    4617     address     = {New York, NY, USA},
    4618 }
    46194479
    46204480@article{Sundell08,
     
    46944554    journal     = sigplan,
    46954555    year        = 1989,
    4696     month       = jun,
    4697     volume      = 24,
    4698     number      = 6,
    4699     pages       = {37-48},
     4556    month       = jun, volume = 24, number = 6, pages = {37-48},
    47004557    abstract    = {
    47014558        This paper describes a scheme we have used to manage a large
     
    47534610    address     = {New York, NY, USA},
    47544611}
    4755 
    47564612@techreport{Mesa,
    47574613    keywords    = {monitors, packages},
     
    47604616    title       = {Mesa Language Manual},
    47614617    institution = {Xerox Palo Alto Research Center},
    4762     address     = {Palo Alto, California, U.S.A.},
    47634618    number      = {CSL--79--3},
    47644619    month       = apr,
     
    47704625    contributer = {pabuhr@plg},
    47714626    author      = {Gregory R. Andrews},
    4772     title       = {A Method for Solving Synchronization Problems},
     4627    title       = {A Method for Solving Synronization Problems},
    47734628    journal     = scp,
    47744629    volume      = 13,
     
    50954950    title       = {Multiple Inheritance for {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}}},
    50964951    booktitle   = {Proceedings of the Spring '87 EUUG Conference},
    5097     month       = may,
    5098     year        = 1987,
     4952    month       = may, year = 1987
    50994953}
    51004954
     
    51414995    year        = 1986,
    51424996    pages       = {313--326},
     4997    numpages    = {14},
    51434998    publisher   = {ACM},
    51444999    address     = {New York, NY, USA},
     
    51565011    year        = 1986,
    51575012    pages       = {327--348},
     5013    numpages    = {22},
    51585014    publisher   = {ACM},
    51595015    address     = {New York, NY, USA},
     
    53525208    year        = 2005,
    53535209    pages       = {146-196},
     5210    numpages    = {51},
    53545211    publisher   = {ACM},
    53555212    address     = {New York, NY, USA},
     
    54975354    year        = 2000,
    54985355    pages       = {29-46},
    5499     note        = {OOPSLA'00, Oct. 15--19, 2000, Minneapolis, Minn., U.S.A.},
     5356    note        = {OOPSLA'00, Oct. 15--19, 2000, Minneapolis, Minnesota, U.S.A.},
    55005357}
    55015358
     
    56115468    location    = {San Diego, California, USA},
    56125469    pages       = {101--112},
     5470    numpages    = {12},
     5471    url         = {http://doi.acm.org/10.1145/2535838.2535878},
     5472    doi         = {10.1145/2535838.2535878},
     5473    acmid       = {2535878},
    56135474    publisher   = {ACM},
    56145475    address     = {New York, NY, USA},
     
    57145575    issn        = {0362-1340},
    57155576    pages       = {30--42},
     5577    numpages    = {13},
     5578    url         = {http://doi.acm.org/10.1145/947586.947589},
     5579    doi         = {10.1145/947586.947589},
    57165580    publisher   = {ACM},
    57175581    address     = {New York, NY, USA}
     
    62506114}
    62516115
    6252 @article{Bauer15,
    6253     keywords    = {resumption exceptions, theory},
    6254     contributer = {pabuhr@plg},
    6255     author      = {Andrej Bauer and Matija Pretnar},
    6256     title       = {Programming with Algebraic Effects and Handlers},
    6257     journal     = {Journal of Logical and Algebraic Methods in Programming},
    6258     publisher   = {Elsevier BV},
    6259     volume      = 84,
    6260     number      = 1,
    6261     month       = jan,
    6262     year        = 2015,
    6263     pages       = {108-123},
    6264 }
    6265 
    62666116@book{Butenhof97,
    62676117    keywords    = {PThreads, concurrency},
     
    63126162    title       = {{C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Programming Language ISO/IEC 14882:1998},
    63136163    edition     = {1st},
    6314     organization  = {International Standard Organization},
    6315     address     = {Geneva, Switzerland},
     6164    publisher   = {International Standard Organization},
     6165    address     = {\href{https://www.iso.org/standard/25845.html}{https://\-www.iso.org/\-standard/\-25845.html}},
    63166166    year        = 1998,
    6317     note        = {\href{https://www.iso.org/standard/25845.html}{https://\-www.iso.org/\-standard/\-25845.html}},
    63186167}
    63196168
     
    63246173    title       = {{C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Programming Language ISO/IEC 14882:2014},
    63256174    edition     = {4th},
    6326     organization= {International Standard Organization},
    6327     address     = {Geneva, Switzerland},
     6175    publisher   = {International Standard Organization},
     6176    address     = {\href{https://www.iso.org/standard/64029.html}{https://\-www.iso.org/\-standard/\-64029.html}},
    63286177    year        = 2014,
    6329     note        = {\href{https://www.iso.org/standard/64029.html}{https://\-www.iso.org/\-standard/\-64029.html}},
    63306178}
    63316179
     
    63366184    title       = {{C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Programming Language ISO/IEC 14882:2017},
    63376185    edition     = {5th},
    6338     organization= {International Standard Organization},
    6339     address     = {Geneva, Switzerland},
     6186    publisher   = {International Standard Organization},
     6187    address     = {\href{https://www.iso.org/standard/68564.html}{https://\-www.iso.org/\-standard/\-68564.html}},
    63406188    year        = 2017,
    6341     note        = {\href{https://www.iso.org/standard/68564.html}{https://\-www.iso.org/\-standard/\-68564.html}},
    63426189}
    63436190
     
    64716318    title       = {The Programming Language Concurrent Pascal},
    64726319    journal     = ieeese,
    6473     volume      = {SE-1},
    6474     number      = 2,
     6320    volume      = 2,
    64756321    month       = jun,
    64766322    year        = 1975,
    6477     pages       = {199-207}
     6323    pages       = {199-206}
    64786324}
    64796325
     
    66536499    issn        = {0164-0925},
    66546500    pages       = {429-475},
     6501    url         = {http://doi.acm.org/10.1145/1133651.1133653},
     6502    doi         = {10.1145/1133651.1133653},
     6503    acmid       = {1133653},
    66556504    publisher   = {ACM},
    66566505    address     = {New York, NY, USA},
     
    66826531}
    66836532
    6684 @article{Aravind09,
    6685     author      = {Alex A. Aravind and Wim H. Hesselink},
    6686     title       = {A Queue Based Mutual Exclusion Algorithm},
    6687     journal     = acta,
    6688     volume      = 46,
    6689     pages       = {73--86},
    6690     year        = 2009,
    6691 }
    6692 
    66936533% R
    66946534
     
    67346574    title       = {Programming languages -- {Ada} ISO/IEC 8652:2012},
    67356575    edition     = {3rd},
    6736     organization= {International Standard Organization},
    6737     address     = {Geneva, Switzerland},
     6576    publisher   = {International Standard Organization},
     6577    address     = {\href{https://www.iso.org/standard/61507.html}{https://\-www.iso.org/\-standard/\-61507.html}},
    67386578    year        = 2012,
    6739     note        = {\href{https://www.iso.org/standard/61507.html}{https://\-www.iso.org/\-standard/\-61507.html}},
    67406579}
    67416580
     
    70406879    issn        = {0001-0782},
    70416880    pages       = {565--569},
     6881    numpages    = {5},
     6882    url         = {http://doi.acm.org/10.1145/359545.359566},
     6883    doi         = {10.1145/359545.359566},
     6884    acmid       = {359566},
    70426885    publisher   = {ACM},
    70436886    address     = {New York, NY, USA}
     
    70576900    issn        = {0362-1340},
    70586901    pages       = {145--147},
     6902    numpages    = {3},
     6903    url         = {http://doi.acm.org/10.1145/122598.122614},
     6904    doi         = {10.1145/122598.122614},
     6905    acmid       = {122614},
    70596906    publisher   = {ACM},
    70606907    address     = {New York, NY, USA},
     
    71597006    issn        = {0362-1340},
    71607007    pages       = {82--87},
     7008    numpages    = {6},
     7009    url         = {http://doi.acm.org/10.1145/947680.947688},
     7010    doi         = {10.1145/947680.947688},
    71617011    publisher   = {ACM},
    71627012    address     = {New York, NY, USA},
     
    73037153}
    73047154
    7305 @article{Cascaval08,
    7306     author      = {Cascaval, Calin and Blundell, Colin and Michael, Maged and Cain, Harold W. and Wu, Peng and Chiras, Stefanie and Chatterjee, Siddhartha},
    7307     title       = {Software Transactional Memory: Why Is It Only a Research Toy?},
    7308     journal     = {Queue},
    7309     volume      = {6},
    7310     number      = {5},
    7311     month       = sep,
    7312     year        = {2008},
    7313     pages       = {40:46--40:58},
    7314     publisher   = {ACM},
    7315     address     = {New York, NY, USA},
    7316 }
    7317 
    73187155@article{Dijkstra65a,
    73197156    keywords    = {N-thread software-solution mutual exclusion},
     
    75267363    year        = 1974,
    75277364    pages       = {261-301},
     7365    issn        = {0360-0300},
     7366    doi         = {http://doi.acm.org/10.1145/356635.356640},
    75287367    publisher   = {ACM},
    75297368    address     = {New York, NY, USA},
     
    76157454    publisher   = {ACM Press},
    76167455    address     = {New York, NY, USA},
     7456    doi         = {http://doi.acm.org/10.1145/356586.356588},
    76177457}
    76187458
     
    77427582    title       = {The Thoth System: Multi-Process Structuring and Portability},
    77437583    publisher   = {American Elsevier},
    7744     address     = {New York, New York, U.S.A.},
    77457584    year        = 1982
    77467585}
     
    79167755    howpublished= {\href{https://projects.eclipse.org/proposals/trace-compass}{https://\-projects.eclipse.org/\-proposals/\-trace-compass}},
    79177756}
    7918 
    7919 @inproceedings{Boehm09,
    7920     author      = {Boehm, Hans-J.},
    7921     title       = {Transactional Memory Should Be an Implementation Technique, Not a Programming Interface},
    7922     booktitle   = {Proceedings of the First USENIX Conference on Hot Topics in Parallelism},
    7923     series      = {HotPar'09},
    7924     year        = {2009},
    7925     location    = {Berkeley, California},
    7926     publisher   = {USENIX Association},
    7927     address     = {Berkeley, CA, USA},
    7928 }
    7929 
     7757 
    79307758@article{Leroy00,
    79317759    keywords    = {type-systems, exceptions},
     
    79777805    number      = {2},
    79787806    pages       = {204-214},
    7979     month       = apr,
    7980     year        = 1988,
     7807    month       = apr, year = 1988,
    79817808    comment     = {
    79827809        Extended record types add fields to their base record.  Assignment
     
    80777904}
    80787905
    8079 @article{Karsten20,
    8080     author      = {Karsten, Martin and Barghi, Saman},
    8081     title       = {{User-level Threading: Have Your Cake and Eat It Too}},
    8082     year        = {2020},
    8083     issue_date  = {March 2020},
    8084     publisher   = {Association for Computing Machinery},
    8085     address     = {New York, NY, USA},
    8086     volume      = {4},
    8087     number      = {1},
    8088     url         = {https://doi.org/10.1145/3379483},
    8089     doi         = {10.1145/3379483},
    8090     journal     = {Proc. ACM Meas. Anal. Comput. Syst.},
    8091     month       = mar,
    8092     numpages    = {30},
    8093 }
    8094 
    80957906@techreport{Harmony,
    80967907    keywords    = {messages, concurrency},
     
    81087919    contributer = {gjditchfield@plg},
    81097920    author      = {Henry Lieverman},
    8110     title       = {Using Prototypical Objects to Implement Shared Behavior in Object Oriented Systems},
     7921    title       = {Using Prototypical Objects to Implement Shared Behavior in
     7922                  Object Oriented Systems},
    81117923    journal     = sigplan,
    8112     month       = nov,
    8113     year        = 1986,
    8114     volume      = 21,
    8115     number      = 11,
    8116     pages       = {214-223}
     7924    month       = nov, year = 1986,
     7925    volume      = 21, number = 11, pages = {214-223}
    81177926}
    81187927
     
    83018110    issn        = {0004-5411},
    83028111    pages       = {245--281},
     8112    numpages    = {37},
     8113    url         = {http://doi.acm.org/10.1145/62.2160},
     8114    doi         = {10.1145/62.2160},
     8115    acmid       = {2160},
    83038116    publisher   = {ACM},
    83048117    address     = {New York, NY, USA},
     
    83138126    contributer = {pabuhr@plg},
    83148127    author      = {Boehm, Hans-J. and Adve, Sarita V.},
    8315     title       = {You Don't Know Jack About Shared Variables or Memory Models},
     8128    title       = {You Don'T Know Jack About Shared Variables or Memory Models},
    83168129    journal     = cacm,
    83178130    volume      = 55,
  • doc/man/cfa.1

    reef8dfb rbdfc032  
    1111.\" Created On       : Wed Jul 26 22:34:47 2017
    1212.\" Last Modified By : Peter A. Buhr
    13 .\" Last Modified On : Wed Sep  2 17:59:53 2020
    14 .\" Update Count     : 78
     13.\" Last Modified On : Thu Jul 27 10:29:29 2017
     14.\" Update Count     : 44
    1515.\"
    1616.\" nroff -man cfa.1
     
    2323.ds Cf "Cforall
    2424.\"
    25 .TH CFA 1 "2020-09-2" cfa-\*(Mg "\*(Cf Project"
     25.TH cfa 1 2017-07-27 cfa-\*(Mg
    2626.SH NAME
    27 cfa \- \*(Cf project translator and runtime library to enhance C
     27cfa \- \*(Cf Translator and Runtime Library
    2828.SH SYNOPSIS
    29 cfa [cfa/gcc-options]
    30     [cfa/c source-files]
    31     [assembler/loader files]
     29cfa [gcc-options] [C/\*(Cf source-files] [assembler/loader files]
    3230.SH DESCRIPTION
    33 \*(Cf (C-for-all) is an open-source project extending ISO C with modern safety and productivity features, while still ensuring backwards compatibility with C and its programmers.
    34 
    3531The cfa command compiles C and \*(Cf source files and links C/\*(Cf object
    3632files named on the command line.
     
    3834The cfa command introduces a translator pass over the specified source files
    3935after the C preprocessor but before the C compilation.  The translator converts
    40 new \*(Cf constructs into C statements.  The cfa command also provides a fully
    41 concurrent (user-level threads) runtime library, which is linked with the
    42 \*(Cf application.
     36new \*(Cf constructs into C statements.  The cfa command also provides the
     37runtime library, which is linked with each \*(Cf application.
    4338
    4439The command line options depend on the particular C compiler used (gcc/clang
    4540supported).  As with most C compilers, the output is sent to the file a.out(5)
    4641unless the -o option is present on the command line.  See the reference pages
    47 for gcc(1) for more information on command line options.
     42for gcc(1) for more information.
    4843.SH OPTIONS
    4944When multiple conflicting options appear on the command line, e.g.,
     
    5550All of the options available to the gcc compiler are available to the cfa
    5651translator.  The following gcc flags are implicitly turned on:
    57 .IP "-std=gnu11" 3
    58 The 2011 C standard plus GNU extensions.
    59 .IP "-fgnu89-inline"
    60 Use the traditional GNU semantics for inline routines in C11 mode, which allows inline routines in header files.
    61 .IP "-imacros stdbool.h"
    62 Include stdbool.h to get defines for bool/true/false.
    63 .IP "-latomic -lm"
    64 Provide access to double-wide CAS instruction and math library.
     52.IP -std=gnu99 3
     53The 1999 C standard plus GNU extensions.
     54.IP -fgnu89-inline
     55Use the traditional GNU semantics for inline routines in C99 mode, which allows inline routines in header files.
    6556.LP
    6657The following additional options are available:
    67 .IP "-CFA" 3
     58.IP -CFA 3
    6859Only the C preprocessor and the \*(Cf translator steps are performed and the transformed program is written to standard output, which makes it possible to examine the code generated by the \*(Cf translator.
    6960The generated code starts with the standard \*(Cf prelude.
    70 .IP "-debug"
     61.IP -debug
    7162The program is linked with the debugging version of the runtime system.
    7263The debug version performs runtime checks to help during the debugging phase of a \*(Cf program, but can substantially slow program execution.
    7364The runtime checks should only be removed after the program is completely debugged.
    7465.B This option is the default.
    75 .IP "-nodebug"
     66.IP -nodebug
    7667The program is linked with the non-debugging version of the runtime system, so the execution of the program is faster.
    7768.I However, no runtime checks or asserts are performed so errors usually result in abnormal program behaviour or termination.
    78 .IP "-help"
     69.IP -help
    7970Information about the set of \*(Cf compilation flags is printed.
    80 .IP "-nohelp"
     71.IP -nohelp
    8172Information about the set of \*(Cf compilation flags is not printed.
    8273.B This option is the default.
    83 .IP "-quiet"
     74.IP -quiet
    8475The \*(Cf compilation message is not printed at the beginning of a compilation.
    85 .IP "-noquiet"
     76.IP -noquiet
    8677The \*(Cf compilation message is printed at the beginning of a compilation.
    8778.B This option is the default.
     
    9081available.  These variables allow conditional compilation of programs that must
    9182work differently in these situations.
    92 .IP "__CFA_MAJOR__" 3
     83.IP __CFA_MAJOR__ 3
    9384is available during preprocessing and its value is the major version number of \*(Cf.
    94 .IP "__CFA_MINOR__"
     85.IP __CFA_MINOR__
    9586is available during preprocessing and its value is the minor version number of \*(Cf.
    96 .IP "__CFA_PATCH__"
     87.IP __CFA_PATCH__
    9788is available during preprocessing and its value is the patch level number of \*(Cf.
    9889.IP "__CFA__, __CFORALL__, and __cforall"
    9990are always available during preprocessing and have no value.
    100 .IP "__CFA_DEBUG__"
     91.IP __CFA_DEBUG__
    10192is available during preprocessing if the -debug compilation option is
    10293specified.
     
    125116.SH REFERENCES
    126117.HP 3
    127 .I \*(Cf Home Page
     118\*(Cf Reference and Rational Manual
    128119.br
    129 https://cforall.uwaterloo.ca
     120http://plg.uwaterloo.ca/~cforall/refrat.pdf
    130121.HP
    131122.I \*(Cf User Manual
    132123.br
    133 https://cforall.uwaterloo.ca/doc/user.pdf
    134 .SH BUILDS
    135 Nightly builds are available here https://cforall.uwaterloo.ca/jenkins
     124http://plg.uwaterloo.ca/~cforall/user.pdf
    136125.SH BUGS
    137 Bugs reportss are available here https://cforall.uwaterloo.ca/trac
     126Bugs should be reported to trac@plg.cs.uwaterloo.ca.
    138127.SH COPYRIGHT
    139128\*(Cf is covered under the licence agreement in the distribution.
    140129.SH AUTHORS
    141130Andrew Beach, Richard Bilson, Peter A. Buhr, Thierry Delisle, Glen Ditchfield,
    142 Rodolfo G. Esteves, Aaron Moss, Rob Schluntz, Mubeen Zulfiqar
     131Rodolfo G. Esteves, Aaron Moss, Rob Schluntz
  • doc/papers/AMA/AMA-stix/ama/WileyNJD-v2.cls

    reef8dfb rbdfc032  
    24442444     \@afterheading}
    24452445
    2446 \renewcommand\section{\@startsection{section}{1}{\z@}{-20pt \@plus -2pt \@minus -2pt}{7\p@}{\sectionfont}}%
    2447 \renewcommand\subsection{\@startsection{subsection}{2}{\z@}{-18pt \@plus -2pt \@minus -2pt}{5\p@}{\subsectionfont}}%
    2448 \renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}{-16pt \@plus -2pt \@minus -2pt}{2\p@}{\subsubsectionfont}}%
     2446\renewcommand\section{\@startsection{section}{1}{\z@}{-25pt \@plus -2pt \@minus -2pt}{12\p@}{\sectionfont}}%
     2447\renewcommand\subsection{\@startsection{subsection}{2}{\z@}{-22pt \@plus -2pt \@minus -2pt}{5\p@}{\subsectionfont}}%
     2448\renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}{-20pt \@plus -2pt \@minus -2pt}{2\p@}{\subsubsectionfont}}%
    24492449%
    24502450\newskip\secruleskip\secruleskip8.5\p@%
  • doc/papers/concurrency/Paper.tex

    reef8dfb rbdfc032  
    6161\newcommand{\CCseventeen}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}17\xspace} % C++17 symbolic name
    6262\newcommand{\CCtwenty}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}20\xspace} % C++20 symbolic name
    63 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\large$^\sharp$}\xspace} % C# symbolic name
     63\newcommand{\Csharp}{C\raisebox{-0.7ex}{\Large$^\sharp$}\xspace} % C# symbolic name
    6464
    6565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    9999\newcommand{\CRT}{\global\columnposn=\gcolumnposn}
    100100
    101 % Denote newterms in particular font and index them without particular font and in lowercase, \eg \newterm{abc}.
    102 % The option parameter provides an index term different from the new term, \eg \newterm[\texttt{abc}]{abc}
     101% Denote newterms in particular font and index them without particular font and in lowercase, e.g., \newterm{abc}.
     102% The option parameter provides an index term different from the new term, e.g., \newterm[\texttt{abc}]{abc}
    103103% The star version does not lowercase the index information, e.g., \newterm*{IBM}.
    104104\newcommand{\newtermFontInline}{\emph}
     
    110110\newcommand{\abbrevFont}{\textit}                       % set empty for no italics
    111111\@ifundefined{eg}{
    112 %\newcommand{\EG}{\abbrevFont{e}\abbrevFont{g}}
    113 \newcommand{\EG}{for example}
     112\newcommand{\EG}{\abbrevFont{e}\abbrevFont{g}}
    114113\newcommand*{\eg}{%
    115114        \@ifnextchar{,}{\EG}%
     
    118117}}{}%
    119118\@ifundefined{ie}{
    120 %\newcommand{\IE}{\abbrevFont{i}\abbrevFont{e}}
    121 \newcommand{\IE}{that is}
     119\newcommand{\IE}{\abbrevFont{i}\abbrevFont{e}}
    122120\newcommand*{\ie}{%
    123121        \@ifnextchar{,}{\IE}%
     
    129127\newcommand*{\etc}{%
    130128        \@ifnextchar{.}{\ETC}%
    131                 {\ETC.\xspace}%
     129        {\ETC.\xspace}%
    132130}}{}%
    133131\@ifundefined{etal}{
    134132\newcommand{\ETAL}{\abbrevFont{et}~\abbrevFont{al}}
    135133\newcommand*{\etal}{%
    136         \@ifnextchar{.}{\ETAL}%
    137                 {\ETAL.\xspace}%
     134        \@ifnextchar{.}{\protect\ETAL}%
     135                {\protect\ETAL.\xspace}%
    138136}}{}%
    139137\@ifundefined{viz}{
     
    165163                __float80, float80, __float128, float128, forall, ftype, generator, _Generic, _Imaginary, __imag, __imag__,
    166164                inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or,
    167                 otype, restrict, resume, __restrict, __restrict__, __signed, __signed__, _Static_assert, suspend, thread,
     165                otype, restrict, __restrict, __restrict__, __signed, __signed__, _Static_assert, thread,
    168166                _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,
    169167                virtual, __volatile, __volatile__, waitfor, when, with, zero_t},
    170168        moredirectives={defined,include_next},
    171169        % replace/adjust listing characters that look bad in sanserif
    172         literate={-}{\makebox[1ex][c]{\raisebox{0.5ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
     170        literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
    173171                {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 % {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1
    174172                {<}{\textrm{\textless}}1 {>}{\textrm{\textgreater}}1
     
    199197                _Else, _Enable, _Event, _Finally, _Monitor, _Mutex, _Nomutex, _PeriodicTask, _RealTimeTask,
    200198                _Resume, _Select, _SporadicTask, _Task, _Timeout, _When, _With, _Throw},
     199}
     200\lstdefinelanguage{Golang}{
     201        morekeywords=[1]{package,import,func,type,struct,return,defer,panic,recover,select,var,const,iota,},
     202        morekeywords=[2]{string,uint,uint8,uint16,uint32,uint64,int,int8,int16,int32,int64,
     203                bool,float32,float64,complex64,complex128,byte,rune,uintptr, error,interface},
     204        morekeywords=[3]{map,slice,make,new,nil,len,cap,copy,close,true,false,delete,append,real,imag,complex,chan,},
     205        morekeywords=[4]{for,break,continue,range,goto,switch,case,fallthrough,if,else,default,},
     206        morekeywords=[5]{Println,Printf,Error,},
     207        sensitive=true,
     208        morecomment=[l]{//},
     209        morecomment=[s]{/*}{*/},
     210        morestring=[b]',
     211        morestring=[b]",
     212        morestring=[s]{`}{`},
    201213}
    202214
     
    226238{}
    227239\lstnewenvironment{C++}[1][]                            % use C++ style
    228 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{`}{`}}\lstset{#1}}
     240{\lstset{language=C++,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
    229241{}
    230242\lstnewenvironment{uC++}[1][]
    231 {\lstset{language=uC++,moredelim=**[is][\protect\color{red}]{`}{`}}\lstset{#1}}
     243{\lstset{#1}}
    232244{}
    233245\lstnewenvironment{Go}[1][]
    234 {\lstset{language=Golang,moredelim=**[is][\protect\color{red}]{`}{`}}\lstset{#1}}
     246{\lstset{language=Golang,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
    235247{}
    236248\lstnewenvironment{python}[1][]
    237 {\lstset{language=python,moredelim=**[is][\protect\color{red}]{`}{`}}\lstset{#1}}
    238 {}
    239 \lstnewenvironment{java}[1][]
    240 {\lstset{language=java,moredelim=**[is][\protect\color{red}]{`}{`}}\lstset{#1}}
     249{\lstset{language=python,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
    241250{}
    242251
     
    253262}
    254263
    255 \newsavebox{\myboxA}
    256 \newsavebox{\myboxB}
    257 \newsavebox{\myboxC}
    258 \newsavebox{\myboxD}
     264\newbox\myboxA
     265\newbox\myboxB
     266\newbox\myboxC
     267\newbox\myboxD
    259268
    260269\title{\texorpdfstring{Advanced Control-flow and Concurrency in \protect\CFA}{Advanced Control-flow in Cforall}}
     
    266275\address[1]{\orgdiv{Cheriton School of Computer Science}, \orgname{University of Waterloo}, \orgaddress{\state{Waterloo, ON}, \country{Canada}}}
    267276
    268 \corres{*Peter A. Buhr, Cheriton School of Computer Science, University of Waterloo, 200 University Avenue West, Waterloo, ON N2L 3G1, Canada. \email{pabuhr{\char`\@}uwaterloo.ca}}
     277\corres{*Peter A. Buhr, Cheriton School of Computer Science, University of Waterloo, 200 University Avenue West, Waterloo, ON, N2L 3G1, Canada. \email{pabuhr{\char`\@}uwaterloo.ca}}
    269278
    270279% \fundingInfo{Natural Sciences and Engineering Research Council of Canada}
    271280
    272281\abstract[Summary]{
    273 \CFA is a polymorphic, nonobject-oriented, concurrent, backwards compatible extension of the C programming language.
     282\CFA is a polymorphic, non-object-oriented, concurrent, backwards-compatible extension of the C programming language.
    274283This paper discusses the design philosophy and implementation of its advanced control-flow and concurrent/parallel features, along with the supporting runtime written in \CFA.
    275 These features are created from scratch as ISO C has only low-level and/or unimplemented concurrency, so C programmers continue to rely on library approaches like pthreads.
     284These features are created from scratch as ISO C has only low-level and/or unimplemented concurrency, so C programmers continue to rely on library features like pthreads.
    276285\CFA introduces modern language-level control-flow mechanisms, like generators, coroutines, user-level threading, and monitors for mutual exclusion and synchronization.
    277286% Library extension for executors, futures, and actors are built on these basic mechanisms.
    278287The runtime provides significant programmer simplification and safety by eliminating spurious wakeup and monitor barging.
    279 The runtime also ensures multiple monitors can be safely acquired in a deadlock-free way, and this feature is fully integrated with all monitor synchronization mechanisms.
     288The runtime also ensures multiple monitors can be safely acquired \emph{simultaneously} (deadlock free), and this feature is fully integrated with all monitor synchronization mechanisms.
    280289All control-flow features integrate with the \CFA polymorphic type-system and exception handling, while respecting the expectations and style of C programmers.
    281290Experimental results show comparable performance of the new features with similar mechanisms in other concurrent programming languages.
    282291}%
    283292
    284 \keywords{C \CFA (Cforall) coroutine concurrency generator monitor parallelism runtime thread}
     293\keywords{generator, coroutine, concurrency, parallelism, thread, monitor, runtime, C, \CFA (Cforall)}
    285294
    286295
    287296\begin{document}
    288 %\linenumbers                           % comment out to turn off line numbering
     297\linenumbers                                            % comment out to turn off line numbering
    289298
    290299\maketitle
     
    293302\section{Introduction}
    294303
    295 \CFA~\cite{Moss18,Cforall} is a modern, polymorphic, nonobject-oriented\footnote{
    296 \CFA has object-oriented features, such as constructors, destructors, and simple trait/interface inheritance.
    297 % Go interfaces, Rust traits, Swift Protocols, Haskell Type Classes and Java Interfaces.
    298 % "Trait inheritance" works for me. "Interface inheritance" might also be a good choice, and distinguish clearly from implementation inheritance.
    299 % You'll want to be a little bit careful with terms like "structural" and "nominal" inheritance as well. CFA has structural inheritance (I think Go as well) -- it's inferred based on the structure of the code.
    300 % Java, Rust, and Haskell (not sure about Swift) have nominal inheritance, where there needs to be a specific statement that "this type inherits from this type".
    301 However, functions \emph{cannot} be nested in structures and there is no mechanism to designate a function parameter as a receiver, \lstinline@this@, parameter.},
    302 , backward-compatible extension of the C programming language.
    303 In many ways, \CFA is to C as Scala~\cite{Scala} is to Java, providing a vehicle for new typing and control-flow capabilities on top of a highly popular programming language\footnote{
    304 The TIOBE index~\cite{TIOBE} for May 2020 ranks the top five \emph{popular} programming languages as C 17\%, Java 16\%, Python 9\%, \CC 6\%, and \Csharp 4\% = 52\%, and over the past 30 years, C has always ranked either first or second in popularity.}
    305 allowing immediate dissemination.
    306 This paper discusses the design philosophy and implementation of \CFA's advanced control-flow and concurrent/parallel features, along with the supporting runtime written in \CFA.
    307 
    308 % The call/return extensions retain state between callee and caller versus losing the callee's state on return;
    309 % the concurrency extensions allow high-level management of threads.
    310 
    311 The \CFA control-flow framework extends ISO \Celeven~\cite{C11} with new call/return and concurrent/parallel control-flow.
    312 Call/return control-flow with argument and parameter passing appeared in the first programming languages.
    313 Over the past 50 years, call/return has been augmented with features like static and dynamic call, exceptions (multilevel return) and generators/coroutines (see Section~\ref{s:StatefulFunction}).
    314 While \CFA has mechanisms for dynamic call (algebraic effects~\cite{Zhang19}) and exceptions\footnote{
    315 \CFA exception handling will be presented in a separate paper.
    316 The key feature that dovetails with this paper is nonlocal exceptions allowing exceptions to be raised across stacks, with synchronous exceptions raised among coroutines and asynchronous exceptions raised among threads, similar to that in \uC~\cite[\S~5]{uC++}}
    317 , this work only discusses retaining state between calls via generators and coroutines.
    318 \newterm{Coroutining} was introduced by Conway~\cite{Conway63}, discussed by Knuth~\cite[\S~1.4.2]{Knuth73V1}, implemented in Simula67~\cite{Simula67}, formalized by Marlin~\cite{Marlin80}, and is now popular and appears in old and new programming languages: CLU~\cite{CLU}, \Csharp~\cite{Csharp}, Ruby~\cite{Ruby}, Python~\cite{Python}, JavaScript~\cite{JavaScript}, Lua~\cite{Lua}, \CCtwenty~\cite{C++20Coroutine19}.
    319 Coroutining is sequential execution requiring direct handoff among coroutines, \ie only the programmer is controlling execution order.
    320 If coroutines transfer to an internal event-engine for scheduling the next coroutines (as in async-await), the program transitions into the realm of concurrency~\cite[\S~3]{Buhr05a}.
    321 Coroutines are only a stepping stone toward concurrency where the commonality is that coroutines and threads retain state between calls.
    322 
    323 \Celeven and \CCeleven define concurrency~\cite[\S~7.26]{C11}, but it is largely wrappers for a subset of the pthreads library~\cite{Pthreads}.\footnote{Pthreads concurrency is based on simple thread fork and join in a function and mutex or condition locks, which is low-level and error-prone}
    324 Interestingly, almost a decade after the \Celeven standard, the most recent versions of gcc, clang, and msvc do not support the \Celeven include @threads.h@, indicating no interest in the C11 concurrency approach (possibly because of the recent effort to add concurrency to \CC).
    325 While the \Celeven standard does not state a threading model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}, as for \CC.
     304This paper discusses the design philosophy and implementation of advanced language-level control-flow and concurrent/parallel features in \CFA~\cite{Moss18,Cforall} and its runtime, which is written entirely in \CFA.
     305\CFA is a modern, polymorphic, non-object-oriented\footnote{
     306\CFA has features often associated with object-oriented programming languages, such as constructors, destructors, virtuals and simple inheritance.
     307However, functions \emph{cannot} be nested in structures, so there is no lexical binding between a structure and set of functions (member/method) implemented by an implicit \lstinline@this@ (receiver) parameter.},
     308backwards-compatible extension of the C programming language.
     309In many ways, \CFA is to C as Scala~\cite{Scala} is to Java, providing a \emph{research vehicle} for new typing and control-flow capabilities on top of a highly popular programming language allowing immediate dissemination.
     310Within the \CFA framework, new control-flow features are created from scratch because ISO \Celeven defines only a subset of the \CFA extensions, where the overlapping features are concurrency~\cite[\S~7.26]{C11}.
     311However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}, and \Celeven and pthreads concurrency is simple, based on thread fork/join in a function and mutex/condition locks, which is low-level and error-prone;
     312no high-level language concurrency features are defined.
     313Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-9 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach (possibly because the effort to add concurrency to \CC).
     314Finally, while the \Celeven standard does not state a threading model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}.
     315
    326316In contrast, there has been a renewed interest during the past decade in user-level (M:N, green) threading in old and new programming languages.
    327 As multicore hardware became available in the 1980/1990s, both user and kernel threading were examined.
     317As multi-core hardware became available in the 1980/90s, both user and kernel threading were examined.
    328318Kernel threading was chosen, largely because of its simplicity and fit with the simpler operating systems and hardware architectures at the time, which gave it a performance advantage~\cite{Drepper03}.
    329319Libraries like pthreads were developed for C, and the Solaris operating-system switched from user (JDK 1.1~\cite{JDK1.1}) to kernel threads.
    330 As a result, many languages adopt the 1:1 kernel-threading model, like Java (Scala), Objective-C~\cite{obj-c-book}, \CCeleven~\cite{C11}, C\#~\cite{Csharp} and Rust~\cite{Rust}, with a variety of presentation mechanisms.
    331 From 2000 onward, several language implementations have championed the M:N user-threading model, like Go~\cite{Go}, Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, D~\cite{D}, and \uC~\cite{uC++,uC++book}, including putting green threads back into Java~\cite{Quasar}, and many user-threading libraries have appeared~\cite{Qthreads,MPC,Marcel}.
    332 The main argument for user-level threading is that it is lighter weight than kernel threading because locking and context switching do not cross the kernel boundary, so there is less restriction on programming styles that encourages large numbers of threads performing medium-sized work to facilitate load balancing by the runtime~\cite{Verch12}.
     320As a result, languages like Java, Scala, Objective-C~\cite{obj-c-book}, \CCeleven~\cite{C11}, and C\#~\cite{Csharp} adopt the 1:1 kernel-threading model, with a variety of presentation mechanisms.
     321From 2000 onwards, languages like Go~\cite{Go}, Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, D~\cite{D}, and \uC~\cite{uC++,uC++book} have championed the M:N user-threading model, and many user-threading libraries have appeared~\cite{Qthreads,MPC,Marcel}, including putting green threads back into Java~\cite{Quasar}.
     322The main argument for user-level threading is that it is lighter weight than kernel threading (locking and context switching do not cross the kernel boundary), so there is less restriction on programming styles that encourage large numbers of threads performing medium work units to facilitate load balancing by the runtime~\cite{Verch12}.
    333323As well, user-threading facilitates a simpler concurrency approach using thread objects that leverage sequential patterns versus events with call-backs~\cite{Adya02,vonBehren03}.
    334 Finally, performant user-threading implementations, both in time and space, meet or exceed direct kernel-threading implementations, while achieving the programming advantages of high concurrency levels and safety.
    335 
    336 A further effort over the past two decades is the development of language memory models to deal with the conflict between language features and compiler/hardware optimizations, \eg some language features are unsafe in the presence of aggressive sequential optimizations~\cite{Buhr95a,Boehm05}.
    337 The consequence is that a language must provide sufficient tools to program around safety issues, as inline and library code is compiled as sequential without any explicit concurrent directive.
    338 One solution is low-level qualifiers and functions, \eg @volatile@ and atomics, allowing \emph{programmers} to explicitly write safe, race-free~\cite{Boehm12} programs.
    339 A safer solution is high-level language constructs so the \emph{compiler} knows the concurrency boundaries, \ie where mutual exclusion and synchronization are acquired and released, and provide implicit safety at and across these boundaries.
    340 While the optimization problem is best known with respect to concurrency, it applies to other complex control-flows like exceptions and coroutines.
    341 As well, language solutions allow matching the language paradigm with the approach, \eg matching the functional paradigm with data-flow programming or the imperative paradigm with thread programming.
     324Finally, performant user-threading implementations (both time and space) meet or exceed direct kernel-threading implementations, while achieving the programming advantages of high concurrency levels and safety.
     325
     326A further effort over the past two decades is the development of language memory models to deal with the conflict between language features and compiler/hardware optimizations, \ie some language features are unsafe in the presence of aggressive sequential optimizations~\cite{Buhr95a,Boehm05}.
     327The consequence is that a language must provide sufficient tools to program around safety issues, as inline and library code is all sequential to the compiler.
     328One solution is low-level qualifiers and functions (\eg @volatile@ and atomics) allowing \emph{programmers} to explicitly write safe (race-free~\cite{Boehm12}) programs.
     329A safer solution is high-level language constructs so the \emph{compiler} knows the optimization boundaries, and hence, provides implicit safety.
     330This problem is best known with respect to concurrency, but applies to other complex control-flow, like exceptions\footnote{
     331\CFA exception handling will be presented in a separate paper.
     332The key feature that dovetails with this paper is nonlocal exceptions allowing exceptions to be raised across stacks, with synchronous exceptions raised among coroutines and asynchronous exceptions raised among threads, similar to that in \uC~\cite[\S~5]{uC++}
     333} and coroutines.
     334Finally, language solutions allow matching constructs with language paradigm, \ie imperative and functional languages often have different presentations of the same concept to fit their programming model.
    342335
    343336Finally, it is important for a language to provide safety over performance \emph{as the default}, allowing careful reduction of safety for performance when necessary.
    344 Two concurrency violations of this philosophy are \emph{spurious} or \emph{random wakeup}~\cite[\S~9]{Buhr05a}, and \emph{barging}\footnote{
    345 Barging is competitive succession instead of direct handoff, \ie after a lock is released both arriving and preexisting waiter threads compete to acquire the lock.
    346 Hence, an arriving thread can temporally \emph{barge} ahead of threads already waiting for an event, which can repeat indefinitely leading to starvation of waiter threads.
    347 } or signals-as-hints~\cite[\S~8]{Buhr05a}, where one is a consequence of the other, \ie once there is spurious wakeup, barging follows.
    348 (Author experience teaching concurrency is that students are confused by these semantics.)
    349 However, spurious wakeup is \emph{not} a foundational concurrency property~\cite[\S~9]{Buhr05a};
    350 it is a performance design choice.
    351 We argue removing spurious wakeup and signals-as-hints make concurrent programming simpler and safer as there is less local nondeterminism to manage.
    352 If barging acquisition is allowed, its specialized performance advantage should be available as an option not the default.
    353 
    354 \CFA embraces language extensions for advanced control-flow, user-level threading, and safety as the default.
    355 We present comparative examples to support our argument that the \CFA control-flow extensions are as expressive and safe as those in other concurrent imperative programming languages, and perform experiments to show the \CFA runtime is competitive with other similar mechanisms.
     337Two concurrency violations of this philosophy are \emph{spurious wakeup} (random wakeup~\cite[\S~8]{Buhr05a}) and \emph{barging}\footnote{
     338The notion of competitive succession instead of direct handoff, \ie a lock owner releases the lock and an arriving thread acquires it ahead of preexisting waiter threads.
     339} (signals-as-hints~\cite[\S~8]{Buhr05a}), where one is a consequence of the other, \ie once there is spurious wakeup, signals-as-hints follow.
     340However, spurious wakeup is \emph{not} a foundational concurrency property~\cite[\S~8]{Buhr05a}, it is a performance design choice.
     341Similarly, signals-as-hints are often a performance decision.
     342We argue removing spurious wakeup and signals-as-hints make concurrent programming significantly safer because it removes local non-determinism and matches with programmer expectation.
     343(Author experience teaching concurrency is that students are highly confused by these semantics.)
     344Clawing back performance, when local non-determinism is unimportant, should be an option not the default.
     345
     346\begin{comment}
     347Most augmented traditional (Fortran 18~\cite{Fortran18}, Cobol 14~\cite{Cobol14}, Ada 12~\cite{Ada12}, Java 11~\cite{Java11}) and new languages (Go~\cite{Go}, Rust~\cite{Rust}, and D~\cite{D}), except \CC, diverge from C with different syntax and semantics, only interoperate indirectly with C, and are not systems languages, for those with managed memory.
     348As a result, there is a significant learning curve to move to these languages, and C legacy-code must be rewritten.
     349While \CC, like \CFA, takes an evolutionary approach to extend C, \CC's constantly growing complex and interdependent features-set (\eg objects, inheritance, templates, etc.) mean idiomatic \CC code is difficult to use from C, and C programmers must expend significant effort learning \CC.
     350Hence, rewriting and retraining costs for these languages, even \CC, are prohibitive for companies with a large C software-base.
     351\CFA with its orthogonal feature-set, its high-performance runtime, and direct access to all existing C libraries circumvents these problems.
     352\end{comment}
     353
     354\CFA embraces user-level threading, language extensions for advanced control-flow, and safety as the default.
     355We present comparative examples so the reader can judge if the \CFA control-flow extensions are better and safer than those in other concurrent, imperative programming languages, and perform experiments to show the \CFA runtime is competitive with other similar mechanisms.
    356356The main contributions of this work are:
    357 \begin{itemize}[topsep=3pt,itemsep=0pt]
     357\begin{itemize}[topsep=3pt,itemsep=1pt]
    358358\item
    359 a set of fundamental execution properties that dictate which language-level control-flow features need to be supported,
    360 
     359language-level generators, coroutines and user-level threading, which respect the expectations of C programmers.
    361360\item
    362 integration of these language-level control-flow features, while respecting the style and expectations of C programmers,
    363 
     361monitor synchronization without barging, and the ability to safely acquiring multiple monitors \emph{simultaneously} (deadlock free), while seamlessly integrating these capabilities with all monitor synchronization mechanisms.
    364362\item
    365 monitor synchronization without barging, and the ability to safely acquiring multiple monitors in a deadlock-free way, while seamlessly integrating these capabilities with all monitor synchronization mechanisms,
    366 
    367 \item
    368 providing statically type-safe interfaces that integrate with the \CFA polymorphic type-system and other language features,
    369 
     363providing statically type-safe interfaces that integrate with the \CFA polymorphic type-system and other language features.
    370364% \item
    371365% library extensions for executors, futures, and actors built on the basic mechanisms.
    372 
    373366\item
    374 a runtime system without spurious wake-up and no performance loss,
    375 
     367a runtime system with no spurious wakeup.
    376368\item
    377 a dynamic partitioning mechanism to segregate groups of executing user and kernel threads performing specialized work, \eg web-server or compute engine, or requiring different scheduling, \eg NUMA or real-time.
    378 
     369a dynamic partitioning mechanism to segregate the execution environment for specialized requirements.
    379370% \item
    380 % a nonblocking I/O library
    381 
     371% a non-blocking I/O library
    382372\item
    383 experimental results showing comparable performance of the \CFA features with similar mechanisms in other languages.
     373experimental results showing comparable performance of the new features with similar mechanisms in other programming languages.
    384374\end{itemize}
    385375
    386 Section~\ref{s:FundamentalExecutionProperties} presents the compositional hierarchy of execution properties directing the design of control-flow features in \CFA.
    387 Section~\ref{s:StatefulFunction} begins advanced control by introducing sequential functions that retain data and execution state between calls producing constructs @generator@ and @coroutine@.
    388 Section~\ref{s:Concurrency} begins concurrency, or how to create (fork) and destroy (join) a thread producing the @thread@ construct.
    389 Section~\ref{s:MutualExclusionSynchronization} discusses the two mechanisms to restricted nondeterminism when controlling shared access to resources, called mutual exclusion, and timing relationships among threads, called synchronization.
     376Section~\ref{s:StatefulFunction} begins advanced control by introducing sequential functions that retain data and execution state between calls, which produces constructs @generator@ and @coroutine@.
     377Section~\ref{s:Concurrency} begins concurrency, or how to create (fork) and destroy (join) a thread, which produces the @thread@ construct.
     378Section~\ref{s:MutualExclusionSynchronization} discusses the two mechanisms to restricted nondeterminism when controlling shared access to resources (mutual exclusion) and timing relationships among threads (synchronization).
    390379Section~\ref{s:Monitor} shows how both mutual exclusion and synchronization are safely embedded in the @monitor@ and @thread@ constructs.
    391 Section~\ref{s:CFARuntimeStructure} describes the large-scale mechanism to structure threads and virtual processors (kernel threads).
    392 Section~\ref{s:Performance} uses microbenchmarks to compare \CFA threading with pthreads, Java 11.0.6, Go 1.12.6, Rust 1.37.0, Python 3.7.6, Node.js v12.18.0, and \uC 7.0.0.
    393 
    394 
    395 \section{Fundamental Execution Properties}
    396 \label{s:FundamentalExecutionProperties}
    397 
    398 The features in a programming language should be composed of a set of fundamental properties rather than an ad hoc collection chosen by the designers.
    399 To this end, the control-flow features created for \CFA are based on the fundamental properties of any language with function-stack control-flow (see also \uC~\cite[pp.~140-142]{uC++}).
    400 The fundamental properties are execution state, thread, and mutual-exclusion/synchronization.
    401 These independent properties can be used to compose different language features, forming a compositional hierarchy, where the combination of all three is the most advanced feature, called a thread.
    402 While it is possible for a language to only provide threads for composing programs~\cite{Hermes90}, this unnecessarily complicates and makes inefficient solutions to certain classes of problems.
    403 As is shown, each of the non-rejected composed language features solves a particular set of problems, and hence, has a defensible position in a programming language.
    404 If a compositional feature is missing, a programmer has too few fundamental properties resulting in a complex and/or inefficient solution.
    405 
    406 In detail, the fundamental properties are:
    407 \begin{description}[leftmargin=\parindent,topsep=3pt,parsep=0pt]
    408 \item[\newterm{execution state}:]
    409 It is the state information needed by a control-flow feature to initialize and manage both compute data and execution location(s), and de-initialize.
    410 For example, calling a function initializes a stack frame including contained objects with constructors, manages local data in blocks and return locations during calls, and de-initializes the frame by running any object destructors and management operations.
    411 State is retained in fixed-sized aggregate structures (objects) and dynamic-sized stack(s), often allocated in the heap(s) managed by the runtime system.
    412 The lifetime of state varies with the control-flow feature, where longer life-time and dynamic size provide greater power but also increase usage complexity and cost.
    413 Control-flow transfers among execution states in multiple ways, such as function call, context switch, asynchronous await, etc.
    414 Because the programming language determines what constitutes an execution state, implicitly manages this state, and defines movement mechanisms among states, execution state is an elementary property of the semantics of a programming language.
    415 % An execution-state is related to the notion of a process continuation \cite{Hieb90}.
    416 
    417 \item[\newterm{threading}:]
    418 It is execution of code that occurs independently of other execution, where an individual thread's execution is sequential.
    419 Multiple threads provide \emph{concurrent execution};
    420 concurrent execution becomes parallel when run on multiple processing units, \eg hyper-threading, cores, or sockets.
    421 A programmer needs mechanisms to create, block and unblock, and join with a thread, even if these basic mechanisms are supplied indirectly through high-level features.
    422 
    423 \item[\newterm{mutual-exclusion / synchronization (MES)}:]
    424 It is the concurrency mechanism to perform an action without interruption and establish timing relationships among multiple threads.
    425 We contented these two properties are independent, \ie mutual exclusion cannot provide synchronization and vice versa without introducing additional threads~\cite[\S~4]{Buhr05a}.
    426 Limiting MES functionality results in contrived solutions and inefficiency on multicore von Neumann computers where shared memory is a foundational aspect of its design.
    427 \end{description}
    428 These properties are fundamental as they cannot be built from existing language features, \eg a basic programming language like C99~\cite{C99} cannot create new control-flow features, concurrency, or provide MES without (atomic) hardware mechanisms.
    429 
    430 
    431 \subsection{Structuring execution properties}
    432 
    433 Programming languages seldom present the fundamental execution properties directly to programmers.
    434 Instead, the properties are packaged into higher-level constructs that encapsulate details and provide safety to these low-level mechanisms.
    435 Interestingly, language designers often pick and choose among these execution properties proving a varying subset of constructs.
    436 
    437 Table~\ref{t:ExecutionPropertyComposition} shows all combinations of the three fundamental execution properties available to language designers.
    438 (When doing combination case-analysis, not all combinations are meaningful.)
    439 The combinations of state, thread, and MES compose a hierarchy of control-flow features all of which have appeared in prior programming languages, where each of these languages have found the feature useful.
    440 To understand the table, it is important to review the basic von Neumann execution requirement of at least one thread and execution state providing some form of call stack.
    441 For table entries missing these minimal components, the property is borrowed from the invoker (caller).
    442 Each entry in the table, numbered \textbf{1}--\textbf{12}, is discussed with respect to how the execution properties combine to generate a high-level language construct.
    443 
    444 \begin{table}
    445 \caption{Execution property composition}
    446 \centering
    447 \label{t:ExecutionPropertyComposition}
    448 \renewcommand{\arraystretch}{1.25}
    449 %\setlength{\tabcolsep}{5pt}
    450 \vspace*{-5pt}
    451 \begin{tabular}{c|c||l|l}
    452 \multicolumn{2}{c||}{Execution properties} & \multicolumn{2}{c}{Mutual exclusion / synchronization} \\
    453 \hline
    454 stateful                        & thread        & \multicolumn{1}{c|}{No} & \multicolumn{1}{c}{Yes} \\
    455 \hline
    456 \hline
    457 No                                      & No            & \textbf{1}\ \ \ @struct@                              & \textbf{2}\ \ \ @mutex@ @struct@              \\
    458 \hline
    459 Yes (stackless)         & No            & \textbf{3}\ \ \ @generator@                   & \textbf{4}\ \ \ @mutex@ @generator@   \\
    460 \hline
    461 Yes (stackful)          & No            & \textbf{5}\ \ \ @coroutine@                   & \textbf{6}\ \ \ @mutex@ @coroutine@   \\
    462 \hline
    463 No                                      & Yes           & \textbf{7}\ \ \ {\color{red}rejected} & \textbf{8}\ \ \ {\color{red}rejected} \\
    464 \hline
    465 Yes (stackless)         & Yes           & \textbf{9}\ \ \ {\color{red}rejected} & \textbf{10}\ \ \ {\color{red}rejected} \\
    466 \hline
    467 Yes (stackful)          & Yes           & \textbf{11}\ \ \ @thread@                             & \textbf{12}\ \ @mutex@ @thread@               \\
    468 \end{tabular}
    469 \vspace*{-8pt}
    470 \end{table}
    471 
    472 Case 1 is a structure where access functions borrow local state (stack frame/activation) and thread from the invoker and retain this state across \emph{callees}, \ie function local-variables are retained on the borrowed stack during calls.
    473 Structures are a foundational mechanism for data organization, and access functions provide interface abstraction and code sharing in all programming languages.
    474 Case 2 is case 1 with thread safety to a structure's state where access functions provide serialization (mutual exclusion) and scheduling among calling threads (synchronization).
    475 A @mutex@ structure, often called a \newterm{monitor}, provides a high-level interface for race-free access of shared data in concurrent programming languages.
    476 Case 3 is case 1 where the structure can implicitly retain execution state and access functions use this execution state to resume/suspend across \emph{callers}, but resume/suspend does not retain a function's local state.
    477 A stackless structure, often called a \newterm{generator} or \emph{iterator}, is \newterm{stackless} because it still borrows the caller's stack and thread, but the stack is used only to preserve state across its callees not callers.
    478 Generators provide the first step toward directly solving problems like finite-state machines (FSMs) that retain data and execution state between calls, whereas normal functions restart on each call.
    479 Case 4 is cases 2 and 3 with thread safety during execution of the generator's access functions.
    480 A @mutex@ generator extends generators into the concurrent domain.
    481 Cases 5 and 6 are like cases 3 and 4 where the structure is extended with an implicit separate stack, so only the thread is borrowed by access functions.
    482 A stackful generator, often called a \newterm{coroutine}, is \newterm{stackful} because resume/suspend now context switch to/from the caller's and coroutine's stack.
    483 A coroutine extends the state retained between calls beyond the generator's structure to arbitrary call depth in the access functions.
    484 Cases 7, 8, 9 and 10 are rejected because a new thread must have its own stack, where the thread begins and stack frames are stored for calls, \ie it is unrealistic for a thread to borrow a stack.
    485 For cases 9 and 10, the stackless frame is not growable, precluding accepting nested calls, making calls, blocking as it requires calls, or preemption as it requires pushing an interrupt frame, all of which compound to require an unknown amount of execution state.
    486 Hence, if this kind of uninterruptable thread exists, it must execute to completion, \ie computation only, which severely restricts runtime management.
    487 Cases 11 and 12 are a stackful thread with and without safe access to shared state.
    488 A thread is the language mechanism to start another thread of control in a program with growable execution state for call/return execution.
    489 In general, language constructs with more execution properties increase the cost of creation and execution along with complexity of usage.
    490 
    491 Given the execution-properties taxonomy, programmers now ask three basic questions: is state necessary across callers and how much, is a separate thread necessary, is thread safety necessary.
    492 Table~\ref{t:ExecutionPropertyComposition} then suggests the optimal language feature needed for implementing a programming problem.
    493 The following sections describe how \CFA fills in \emph{all} the nonrejected table entries with language features, while other programming languages may only provide a subset of the table.
    494 
    495 
    496 \subsection{Design requirements}
    497 
    498 The following design requirements largely stem from building \CFA on top of C.
    499 \begin{itemize}[topsep=3pt,parsep=0pt]
    500 \item
    501 All communication must be statically type checkable for early detection of errors and efficient code generation.
    502 This requirement is consistent with the fact that C is a statically typed programming language.
    503 
    504 \item
    505 Direct interaction among language features must be possible allowing any feature to be selected without restricting comm\-unication.
    506 For example, many concurrent languages do not provide direct communication calls among threads, \ie threads only communicate indirectly through monitors, channels, messages, and/or futures.
    507 Indirect communication increases the number of objects, consuming more resources, and requires additional synchronization and possibly data transfer.
    508 
    509 \item
    510 All communication is performed using function calls, \ie data are transmitted from argument to parameter and results are returned from function calls.
    511 Alternative forms of communication, such as call-backs, message passing, channels, or communication ports, step outside of C's normal form of communication.
    512 
    513 \item
    514 All stateful features must follow the same declaration scopes and lifetimes as other language data.
    515 For C that means at program startup, during block and function activation, and on demand using dynamic allocation.
    516 
    517 \item
    518 MES must be available implicitly in language constructs, \eg Java built-in monitors, as well as explicitly for specialized requirements, \eg @java.util.concurrent@, because requiring programmers to build MES using low-level locks often leads to incorrect programs.
    519 Furthermore, reducing synchronization scope by encapsulating it within language constructs further reduces errors in concurrent programs.
    520 
    521 \item
    522 Both synchronous and asynchronous communication are needed.
    523 However, we believe the best way to provide asynchrony, such as call-buffering/chaining and/or returning futures~\cite{multilisp}, is building it from expressive synchronous features.
    524 
    525 \item
    526 Synchronization must be able to control the service order of requests including prioritizing selection from different kinds of outstanding requests, and postponing a request for an unspecified time while continuing to accept new requests.
    527 Otherwise, certain concurrency problems are difficult, \eg web server, disk scheduling, and the amount of concurrency is inhibited~\cite{Gentleman81}.
    528 \end{itemize}
    529 We have satisfied these requirements in \CFA while maintaining backwards compatibility with the huge body of legacy C programs.
    530 % In contrast, other new programming languages must still access C programs (\eg operating-system service routines), but do so through fragile C interfaces.
    531 
    532 
    533 \subsection{Asynchronous await / call}
    534 
    535 Asynchronous await/call is a caller mechanism for structuring programs and/or increasing concurrency, where the caller (client) postpones an action into the future, which is subsequently executed by a callee (server).
    536 The caller detects the action's completion through a \newterm{future} or \newterm{promise}.
    537 The benefit is asynchronous caller execution with respect to the callee until future resolution.
    538 For single-threaded languages like JavaScript, an asynchronous call passes a callee action, which is queued in the event-engine, and continues execution with a promise.
    539 When the caller needs the promise to be fulfilled, it executes @await@.
    540 A promise-completion call-back can be part of the callee action or the caller is rescheduled;
    541 in either case, the call back is executed after the promise is fulfilled.
    542 While asynchronous calls generate new callee (server) events, we contend this mechanism is insufficient for advanced control-flow mechanisms like generators or coroutines, which are discussed next.
    543 Specifically, control between caller and callee occurs indirectly through the event-engine precluding direct handoff and cycling among events, and requires complex resolution of a control promise and data.
    544 Note, @async-await@ is just syntactic-sugar over the event engine so it does not solve these deficiencies.
    545 For multithreaded languages like Java, the asynchronous call queues a callee action with an executor (server), which subsequently executes the work by a thread in the executor thread-pool.
    546 The problem is when concurrent work-units need to interact and/or block as this effects the executor by stopping threads.
    547 While it is possible to extend this approach to support the necessary mechanisms, \eg message passing in Actors, we show monitors and threads provide an equally competitive approach that does not deviate from normal call communication and can be used to build asynchronous call, as is done in Java.
     380Section~\ref{s:CFARuntimeStructure} describes the large-scale mechanism to structure (cluster) threads and virtual processors (kernel threads).
     381Section~\ref{s:Performance} uses a series of microbenchmarks to compare \CFA threading with pthreads, Java OpenJDK-9, Go 1.12.6 and \uC 7.0.0.
    548382
    549383
     
    551385\label{s:StatefulFunction}
    552386
    553 A \emph{stateful function} has the ability to remember state between calls, where state can be either data or execution, \eg plugin, device driver, FSM.
    554 A simple technique to retain data state between calls is @static@ declarations within a function, which is often implemented by hoisting the declarations to the global scope but hiding the names within the function using name mangling.
    555 However, each call starts the function at the top making it difficult to determine the last point of execution in an algorithm, and requiring multiple flag variables and testing to reestablish the continuation point.
    556 Hence, the next step of generalizing function state is implicitly remembering the return point between calls and reentering the function at this point rather than the top, called \emph{generators}\,/\,\emph{iterators} or \emph{stackless coroutines}.
    557 For example, a Fibonacci generator retains data and execution state allowing it to remember prior values needed to generate the next value and the location in the algorithm to compute that value.
    558 The next step of generalization is instantiating the function to allow multiple named instances, \eg multiple Fibonacci generators, where each instance has its own state, and hence, can generate an independent sequence of values.
    559 Note, a subset of generator state is a function \emph{closure}, \ie the technique of capturing lexical references when returning a nested function.
    560 A further generalization is adding a stack to a generator's state, called a \emph{coroutine}, so it can suspend outside of itself, \eg call helper functions to arbitrary depth before suspending back to its resumer without unwinding these calls.
    561 For example, a coroutine iterator for a binary tree can stop the traversal at the visit point (pre, infix, post traversal), return the node value to the caller, and then continue the recursive traversal from the current node on the next call.
    562 
    563 There are two styles of activating a stateful function, \emph{asymmetric} or \emph{symmetric}, identified by resume/suspend (no cycles) and resume/resume (cycles).
    564 These styles \emph{do not} cause incremental stack growth, \eg a million resume/suspend or resume/resume cycles do not remember each cycle just the last resumer for each cycle.
    565 Selecting between stackless/stackful semantics and asymmetric/symmetric style is a tradeoff between programming requirements, performance, and design, where stackless is faster and smaller using modified call/return between closures, stackful is more general but slower and larger using context switching between distinct stacks, and asymmetric is simpler control-flow than symmetric.
    566 Additionally, storage management for the closure/stack must be factored into design and performance, especially in unmanaged languages without garbage collection.
    567 Note, creation cost (closure/stack) is amortized across usage, so activation cost (resume/suspend) is usually the dominant factor.
    568 
    569 % The stateful function is an old idea~\cite{Conway63,Marlin80} that is new again~\cite{C++20Coroutine19}, where execution is temporarily suspended and later resumed, \eg plugin, device driver, finite-state machine.
    570 % Hence, a stateful function may not end when it returns to its caller, allowing it to be restarted with the data and execution location present at the point of suspension.
    571 % If the closure is fixed size, we call it a \emph{generator} (or \emph{stackless}), and its control flow is restricted, \eg suspending outside the generator is prohibited.
    572 % If the closure is variable size, we call it a \emph{coroutine} (or \emph{stackful}), and as the names implies, often implemented with a separate stack with no programming restrictions.
    573 % Hence, refactoring a stackless coroutine may require changing it to stackful.
    574 % A foundational property of all \emph{stateful functions} is that resume/suspend \emph{do not} cause incremental stack growth, \ie resume/suspend operations are remembered through the closure not the stack.
    575 % As well, activating a stateful function is \emph{asymmetric} or \emph{symmetric}, identified by resume/suspend (no cycles) and resume/resume (cycles).
    576 % A fixed closure activated by modified call/return is faster than a variable closure activated by context switching.
    577 % Additionally, any storage management for the closure (especially in unmanaged languages, \ie no garbage collection) must also be factored into design and performance.
    578 % Therefore, selecting between stackless and stackful semantics is a tradeoff between programming requirements and performance, where stackless is faster and stackful is more general.
    579 % nppNote, creation cost is amortized across usage, so activation cost is usually the dominant factor.
    580 
    581 For example, Python presents asymmetric generators as a function object, \uC presents symmetric coroutines as a \lstinline[language=C++]|class|-like object, and many languages present threading using function pointers, @pthreads@~\cite{Butenhof97}, \Csharp~\cite{Csharp}, Go~\cite{Go}, and Scala~\cite{Scala}.
    582 \begin{center}
    583 \begin{tabular}{@{}l|l|l@{}}
    584 \multicolumn{1}{@{}c|}{Python asymmetric generator} & \multicolumn{1}{c|}{\uC symmetric coroutine} & \multicolumn{1}{c@{}}{Pthreads thread} \\
    585 \hline
    586 \begin{python}
    587 `def Gen():` $\LstCommentStyle{\color{red}// function}$
    588         ... yield val ...
    589 gen = Gen()
    590 for i in range( 10 ):
    591         print( next( gen ) )
    592 \end{python}
    593 &
    594 \begin{uC++}
    595 `_Coroutine Cycle {` $\LstCommentStyle{\color{red}// class}$
    596         Cycle * p;
    597         void main() { p->cycle(); }
    598         void cycle() { resume(); }  `};`
    599 Cycle c1, c2; c1.p=&c2; c2.p=&c1; c1.cycle();
    600 \end{uC++}
    601 &
    602 \begin{cfa}
    603 void * `rtn`( void * arg ) { ... }
    604 int i = 3, rc;
    605 pthread_t t; $\C{// thread id}$
    606 $\LstCommentStyle{\color{red}// function pointer}$
    607 rc=pthread_create(&t, `rtn`, (void *)i);
    608 \end{cfa}
    609 \end{tabular}
    610 \end{center}
    611 \CFA's preferred presentation model for generators/coroutines/threads is a hybrid of functions and classes, giving an object-oriented flavor.
    612 Essentially, the generator/coroutine/thread function is semantically coupled with a generator/coroutine/thread custom type via the type's name.
    613 The custom type solves several issues, while accessing the underlying mechanisms used by the custom types is still allowed for flexibility reasons.
    614 Each custom type is discussed in detail in the following sections.
    615 
    616 
    617 \subsection{Generator}
    618 
    619 Stackless generators (Table~\ref{t:ExecutionPropertyComposition} case 3) have the potential to be very small and fast, \ie as small and fast as function call/return for both creation and execution.
    620 The \CFA goal is to achieve this performance target, possibly at the cost of some semantic complexity.
    621 A series of different kinds of generators and their implementation demonstrate how this goal is accomplished.\footnote{
    622 The \CFA operator syntax uses \lstinline|?| to denote operands, which allows precise definitions for pre, post, and infix operators, \eg \lstinline|?++|, \lstinline|++?|, and \lstinline|?+?|, in addition \lstinline|?\{\}| denotes a constructor, as in \lstinline|foo `f` = `\{`...`\}`|, \lstinline|^?\{\}| denotes a destructor, and \lstinline|?()| is \CC function call \lstinline|operator()|.
    623 Operator \lstinline+|+ is overloaded for printing, like bit-shift \lstinline|<<| in \CC.
    624 The \CFA \lstinline|with| clause opens an aggregate scope making its fields directly accessible, like Pascal \lstinline|with|, but using parallel semantics;
    625 multiple aggregates may be opened.
    626 \CFA has rebindable references \lstinline|int i, & ip = i, j; `&ip = &j;`| and nonrebindable references \lstinline|int i, & `const` ip = i, j; `&ip = &j;` // disallowed|.
    627 }%
     387The stateful function is an old idea~\cite{Conway63,Marlin80} that is new again~\cite{C++20Coroutine19}, where execution is temporarily suspended and later resumed, \eg plugin, device driver, finite-state machine.
     388Hence, a stateful function may not end when it returns to its caller, allowing it to be restarted with the data and execution location present at the point of suspension.
     389This capability is accomplished by retaining a data/execution \emph{closure} between invocations.
     390If the closure is fixed size, we call it a \emph{generator} (or \emph{stackless}), and its control flow is restricted, \eg suspending outside the generator is prohibited.
     391If the closure is variable size, we call it a \emph{coroutine} (or \emph{stackful}), and as the names implies, often implemented with a separate stack with no programming restrictions.
     392Hence, refactoring a stackless coroutine may require changing it to stackful.
     393A foundational property of all \emph{stateful functions} is that resume/suspend \emph{do not} cause incremental stack growth, \ie resume/suspend operations are remembered through the closure not the stack.
     394As well, activating a stateful function is \emph{asymmetric} or \emph{symmetric}, identified by resume/suspend (no cycles) and resume/resume (cycles).
     395A fixed closure activated by modified call/return is faster than a variable closure activated by context switching.
     396Additionally, any storage management for the closure (especially in unmanaged languages, \ie no garbage collection) must also be factored into design and performance.
     397Therefore, selecting between stackless and stackful semantics is a tradeoff between programming requirements and performance, where stackless is faster and stackful is more general.
     398Note, creation cost is amortized across usage, so activation cost is usually the dominant factor.
    628399
    629400\begin{figure}
     
    639410
    640411
    641 
    642 
    643412        int fn = f->fn; f->fn = f->fn1;
    644413                f->fn1 = f->fn + fn;
    645414        return fn;
     415
    646416}
    647417int main() {
     
    662432void `main(Fib & fib)` with(fib) {
    663433
    664 
    665434        [fn1, fn] = [1, 0];
    666435        for () {
     
    682451\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    683452typedef struct {
    684         int `restart`, fn1, fn;
     453        int fn1, fn;  void * `next`;
    685454} Fib;
    686 #define FibCtor { `0`, 1, 0 }
     455#define FibCtor { 1, 0, NULL }
    687456Fib * comain( Fib * f ) {
    688         `static void * states[] = {&&s0, &&s1};`
    689         `goto *states[f->restart];`
    690   s0: f->`restart` = 1;
     457        if ( f->next ) goto *f->next;
     458        f->next = &&s1;
    691459        for ( ;; ) {
    692460                return f;
    693461          s1:; int fn = f->fn + f->fn1;
    694                 f->fn1 = f->fn; f->fn = fn;
     462                        f->fn1 = f->fn; f->fn = fn;
    695463        }
    696464}
     
    704472\end{lrbox}
    705473
    706 \subfloat[C]{\label{f:CFibonacci}\usebox\myboxA}
     474\subfloat[C asymmetric generator]{\label{f:CFibonacci}\usebox\myboxA}
    707475\hspace{3pt}
    708476\vrule
    709477\hspace{3pt}
    710 \subfloat[\CFA]{\label{f:CFAFibonacciGen}\usebox\myboxB}
     478\subfloat[\CFA asymmetric generator]{\label{f:CFAFibonacciGen}\usebox\myboxB}
    711479\hspace{3pt}
    712480\vrule
    713481\hspace{3pt}
    714 \subfloat[C generated code for \CFA version]{\label{f:CFibonacciSim}\usebox\myboxC}
    715 \caption{Fibonacci output asymmetric generator}
     482\subfloat[C generator implementation]{\label{f:CFibonacciSim}\usebox\myboxC}
     483\caption{Fibonacci (output) asymmetric generator}
    716484\label{f:FibonacciAsymmetricGenerator}
    717485
     
    725493};
    726494void ?{}( Fmt & fmt ) { `resume(fmt);` } // constructor
    727 void ^?{}( Fmt & f ) with(f) { $\C[2.25in]{// destructor}$
     495void ^?{}( Fmt & f ) with(f) { $\C[1.75in]{// destructor}$
    728496        if ( g != 0 || b != 0 ) sout | nl; }
    729497void `main( Fmt & f )` with(f) {
     
    731499                for ( ; g < 5; g += 1 ) { $\C{// groups}$
    732500                        for ( ; b < 4; b += 1 ) { $\C{// blocks}$
    733                                 do { `suspend;` $\C{// wait for character}$
    734                                 while ( ch == '\n' ); // ignore newline
    735                                 sout | ch;                      $\C{// print character}$
    736                         } sout | " ";  $\C{// block separator}$
    737                 } sout | nl; $\C{// group separator}$
     501                                `suspend;` $\C{// wait for character}$
     502                                while ( ch == '\n' ) `suspend;` // ignore
     503                                sout | ch;                                              // newline
     504                        } sout | " ";  // block spacer
     505                } sout | nl; // group newline
    738506        }
    739507}
     
    753521\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    754522typedef struct {
    755         int `restart`, g, b;
     523        void * next;
    756524        char ch;
     525        int g, b;
    757526} Fmt;
    758527void comain( Fmt * f ) {
    759         `static void * states[] = {&&s0, &&s1};`
    760         `goto *states[f->restart];`
    761   s0: f->`restart` = 1;
     528        if ( f->next ) goto *f->next;
     529        f->next = &&s1;
    762530        for ( ;; ) {
    763531                for ( f->g = 0; f->g < 5; f->g += 1 ) {
    764532                        for ( f->b = 0; f->b < 4; f->b += 1 ) {
    765                                 do { return;  s1: ;
    766                                 } while ( f->ch == '\n' );
     533                                return;
     534                          s1:;  while ( f->ch == '\n' ) return;
    767535                                printf( "%c", f->ch );
    768536                        } printf( " " );
     
    771539}
    772540int main() {
    773         Fmt fmt = { `0` };  comain( &fmt ); // prime
     541        Fmt fmt = { NULL };  comain( &fmt ); // prime
    774542        for ( ;; ) {
    775543                scanf( "%c", &fmt.ch );
     
    782550\end{lrbox}
    783551
    784 \subfloat[\CFA]{\label{f:CFAFormatGen}\usebox\myboxA}
    785 \hspace{35pt}
     552\subfloat[\CFA asymmetric generator]{\label{f:CFAFormatGen}\usebox\myboxA}
     553\hspace{3pt}
    786554\vrule
    787555\hspace{3pt}
    788 \subfloat[C generated code for \CFA version]{\label{f:CFormatGenImpl}\usebox\myboxB}
     556\subfloat[C generator simulation]{\label{f:CFormatSim}\usebox\myboxB}
    789557\hspace{3pt}
    790 \caption{Formatter input asymmetric generator}
     558\caption{Formatter (input) asymmetric generator}
    791559\label{f:FormatterAsymmetricGenerator}
    792560\end{figure}
    793561
    794 Figure~\ref{f:FibonacciAsymmetricGenerator} shows an unbounded asymmetric generator for an infinite sequence of Fibonacci numbers written left to right in C, \CFA, and showing the underlying C implementation for the \CFA version.
     562Stateful functions appear as generators, coroutines, and threads, where presentations are based on function objects or pointers~\cite{Butenhof97, C++14, MS:VisualC++, BoostCoroutines15}.
     563For example, Python presents generators as a function object:
     564\begin{python}
     565def Gen():
     566        ... `yield val` ...
     567gen = Gen()
     568for i in range( 10 ):
     569        print( next( gen ) )
     570\end{python}
     571Boost presents coroutines in terms of four functor object-types:
     572\begin{cfa}
     573asymmetric_coroutine<>::pull_type
     574asymmetric_coroutine<>::push_type
     575symmetric_coroutine<>::call_type
     576symmetric_coroutine<>::yield_type
     577\end{cfa}
     578and many languages present threading using function pointers, @pthreads@~\cite{Butenhof97}, \Csharp~\cite{Csharp}, Go~\cite{Go}, and Scala~\cite{Scala}, \eg pthreads:
     579\begin{cfa}
     580void * rtn( void * arg ) { ... }
     581int i = 3, rc;
     582pthread_t t; $\C{// thread id}$
     583`rc = pthread_create( &t, rtn, (void *)i );` $\C{// create and initialized task, type-unsafe input parameter}$
     584\end{cfa}
     585% void mycor( pthread_t cid, void * arg ) {
     586%       int * value = (int *)arg;                               $\C{// type unsafe, pointer-size only}$
     587%       // thread body
     588% }
     589% int main() {
     590%       int input = 0, output;
     591%       coroutine_t cid = coroutine_create( &mycor, (void *)&input ); $\C{// type unsafe, pointer-size only}$
     592%       coroutine_resume( cid, (void *)input, (void **)&output ); $\C{// type unsafe, pointer-size only}$
     593% }
     594\CFA's preferred presentation model for generators/coroutines/threads is a hybrid of objects and functions, with an object-oriented flavour.
     595Essentially, the generator/coroutine/thread function is semantically coupled with a generator/coroutine/thread custom type.
     596The custom type solves several issues, while accessing the underlying mechanisms used by the custom types is still allowed.
     597
     598
     599\subsection{Generator}
     600
     601Stackless generators have the potential to be very small and fast, \ie as small and fast as function call/return for both creation and execution.
     602The \CFA goal is to achieve this performance target, possibly at the cost of some semantic complexity.
     603A series of different kinds of generators and their implementation demonstrate how this goal is accomplished.
     604
     605Figure~\ref{f:FibonacciAsymmetricGenerator} shows an unbounded asymmetric generator for an infinite sequence of Fibonacci numbers written in C and \CFA, with a simple C implementation for the \CFA version.
    795606This generator is an \emph{output generator}, producing a new result on each resumption.
    796607To compute Fibonacci, the previous two values in the sequence are retained to generate the next value, \ie @fn1@ and @fn@, plus the execution location where control restarts when the generator is resumed, \ie top or middle.
    797 An additional requirement is the ability to create an arbitrary number of generators of any kind, \ie retaining one state in global variables is insufficient;
     608An additional requirement is the ability to create an arbitrary number of generators (of any kind), \ie retaining one state in global variables is insufficient;
    798609hence, state is retained in a closure between calls.
    799610Figure~\ref{f:CFibonacci} shows the C approach of manually creating the closure in structure @Fib@, and multiple instances of this closure provide multiple Fibonacci generators.
    800611The C version only has the middle execution state because the top execution state is declaration initialization.
    801612Figure~\ref{f:CFAFibonacciGen} shows the \CFA approach, which also has a manual closure, but replaces the structure with a custom \CFA @generator@ type.
    802 Each generator type must have a function named \lstinline|main|,
    803 % \footnote{
    804 % The name \lstinline|main| has special meaning in C, specifically the function where a program starts execution.
    805 % Leveraging starting semantics to this name for generator/coroutine/thread is a logical extension.}
    806 called a \emph{generator main} (leveraging the starting semantics for program @main@ in C), which is connected to the generator type via its single reference parameter.
     613This generator type is then connected to a function that \emph{must be named \lstinline|main|},\footnote{
     614The name \lstinline|main| has special meaning in C, specifically the function where a program starts execution.
     615Hence, overloading this name for other starting points (generator/coroutine/thread) is a logical extension.}
     616called a \emph{generator main},which takes as its only parameter a reference to the generator type.
    807617The generator main contains @suspend@ statements that suspend execution without ending the generator versus @return@.
    808 For the Fibonacci generator-main, the top initialization state appears at the start and the middle execution state is denoted by statement @suspend@.
     618For the Fibonacci generator-main,\footnote{
     619The \CFA \lstinline|with| opens an aggregate scope making its fields directly accessible, like Pascal \lstinline|with|, but using parallel semantics.
     620Multiple aggregates may be opened.}
     621the top initialization state appears at the start and the middle execution state is denoted by statement @suspend@.
    809622Any local variables in @main@ \emph{are not retained} between calls;
    810623hence local variables are only for temporary computations \emph{between} suspends.
     
    814627Resuming an ended (returned) generator is undefined.
    815628Function @resume@ returns its argument generator so it can be cascaded in an expression, in this case to print the next Fibonacci value @fn@ computed in the generator instance.
    816 Figure~\ref{f:CFibonacciSim} shows the C implementation of the \CFA asymmetric generator.
    817 Only one execution-state field, @restart@, is needed to subscript the suspension points in the generator.
    818 At the start of the generator main, the @static@ declaration, @states@, is initialized to the N suspend points in the generator, where operator @&&@ dereferences or references a label~\cite{gccValueLabels}.
    819 Next, the computed @goto@ selects the last suspend point and branches to it.
    820 The cost of setting @restart@ and branching via the computed @goto@ adds very little cost to the suspend and resume calls.
    821 
    822 An advantage of the \CFA explicit generator type is the ability to allow multiple type-safe interface functions taking and returning arbitrary types.
     629Figure~\ref{f:CFibonacciSim} shows the C implementation of the \CFA generator only needs one additional field, @next@, to handle retention of execution state.
     630The computed @goto@ at the start of the generator main, which branches after the previous suspend, adds very little cost to the resume call.
     631Finally, an explicit generator type provides both design and performance benefits, such as multiple type-safe interface functions taking and returning arbitrary types.\footnote{
     632The \CFA operator syntax uses \lstinline|?| to denote operands, which allows precise definitions for pre, post, and infix operators, \eg \lstinline|++?|, \lstinline|?++|, and \lstinline|?+?|, in addition \lstinline|?\{\}| denotes a constructor, as in \lstinline|foo `f` = `\{`...`\}`|, \lstinline|^?\{\}| denotes a destructor, and \lstinline|?()| is \CC function call \lstinline|operator()|.
     633}%
    823634\begin{cfa}
    824635int ?()( Fib & fib ) { return `resume( fib )`.fn; } $\C[3.9in]{// function-call interface}$
    825 int ?()( Fib & fib, int N ) { for ( N - 1 ) `fib()`; return `fib()`; } $\C{// add parameter to skip N values}$
    826 double ?()( Fib & fib ) { return (int)`fib()` / 3.14159; } $\C{// different return type, cast prevents recursive call}$
    827 Fib f;  int i;  double d;
    828 i = f();  i = f( 2 );  d = f();                                         $\C{// alternative interfaces}\CRT$
     636int ?()( Fib & fib, int N ) { for ( N - 1 ) `fib()`; return `fib()`; } $\C{// use function-call interface to skip N values}$
     637double ?()( Fib & fib ) { return (int)`fib()` / 3.14159; } $\C{// different return type, cast prevents recursive call}\CRT$
     638sout | (int)f1() | (double)f1() | f2( 2 ); // alternative interface, cast selects call based on return type, step 2 values
    829639\end{cfa}
    830640Now, the generator can be a separately compiled opaque-type only accessed through its interface functions.
    831641For contrast, Figure~\ref{f:PythonFibonacci} shows the equivalent Python Fibonacci generator, which does not use a generator type, and hence only has a single interface, but an implicit closure.
    832642
    833 \begin{figure}
    834 %\centering
    835 \newbox\myboxA
    836 \begin{lrbox}{\myboxA}
    837 \begin{python}[aboveskip=0pt,belowskip=0pt]
    838 def Fib():
    839         fn1, fn = 0, 1
    840         while True:
    841                 `yield fn1`
    842                 fn1, fn = fn, fn1 + fn
    843 f1 = Fib()
    844 f2 = Fib()
    845 for i in range( 10 ):
    846         print( next( f1 ), next( f2 ) )
    847 
    848 
    849 
    850 
    851 
    852 
    853 
    854 
    855 
    856 
    857 \end{python}
    858 \end{lrbox}
    859 
    860 \newbox\myboxB
    861 \begin{lrbox}{\myboxB}
    862 \begin{python}[aboveskip=0pt,belowskip=0pt]
    863 def Fmt():
    864         try:
    865                 while True:                                             $\C[2.5in]{\# until destructor call}$
    866                         for g in range( 5 ):            $\C{\# groups}$
    867                                 for b in range( 4 ):    $\C{\# blocks}$
    868                                         while True:
    869                                                 ch = (yield)    $\C{\# receive from send}$
    870                                                 if '\n' not in ch: $\C{\# ignore newline}$
    871                                                         break
    872                                         print( ch, end='' )     $\C{\# print character}$
    873                                 print( '  ', end='' )   $\C{\# block separator}$
    874                         print()                                         $\C{\# group separator}$
    875         except GeneratorExit:                           $\C{\# destructor}$
    876                 if g != 0 | b != 0:                             $\C{\# special case}$
    877                         print()
    878 fmt = Fmt()
    879 `next( fmt )`                                                   $\C{\# prime, next prewritten}$
    880 for i in range( 41 ):
    881         `fmt.send( 'a' );`                                      $\C{\# send to yield}$
    882 \end{python}
    883 \end{lrbox}
    884 
    885 \hspace{30pt}
    886 \subfloat[Fibonacci]{\label{f:PythonFibonacci}\usebox\myboxA}
    887 \hspace{3pt}
    888 \vrule
    889 \hspace{3pt}
    890 \subfloat[Formatter]{\label{f:PythonFormatter}\usebox\myboxB}
    891 \caption{Python generator}
    892 \label{f:PythonGenerator}
    893 \end{figure}
    894 
    895 Having to manually create the generator closure by moving local-state variables into the generator type is an additional programmer burden (removed by the coroutine in Section~\ref{s:Coroutine}).
    896 This manual requirement follows from the generality of allowing variable-size local-state, \eg local state with a variable-length array requires dynamic allocation as the array size is unknown at compile time.
     643Having to manually create the generator closure by moving local-state variables into the generator type is an additional programmer burden.
     644(This restriction is removed by the coroutine in Section~\ref{s:Coroutine}.)
     645This requirement follows from the generality of variable-size local-state, \eg local state with a variable-length array requires dynamic allocation because the array size is unknown at compile time.
    897646However, dynamic allocation significantly increases the cost of generator creation/destruction and is a showstopper for embedded real-time programming.
    898647But more importantly, the size of the generator type is tied to the local state in the generator main, which precludes separate compilation of the generator main, \ie a generator must be inlined or local state must be dynamically allocated.
    899 With respect to safety, we believe static analysis can discriminate persistent generator state from temporary generator-main state and raise a compile-time error for temporary usage spanning suspend points.
    900 Our experience using generators is that the problems have simple data state, including local state, but complex execution state, so the burden of creating the generator type is small.
    901 As well, C programmers are not afraid of this kind of semantic programming requirement, if it results in very small and fast generators.
     648With respect to safety, we believe static analysis can discriminate local state from temporary variables in a generator, \ie variable usage spanning @suspend@, and generate a compile-time error.
     649Finally, our current experience is that most generator problems have simple data state, including local state, but complex execution state, so the burden of creating the generator type is small.
     650As well, C programmers are not afraid of this kind of semantic programming requirement, if it results in very small, fast generators.
    902651
    903652Figure~\ref{f:CFAFormatGen} shows an asymmetric \newterm{input generator}, @Fmt@, for restructuring text into groups of characters of fixed-size blocks, \ie the input on the left is reformatted into the output on the right, where newlines are ignored.
     
    920669The example takes advantage of resuming a generator in the constructor to prime the loops so the first character sent for formatting appears inside the nested loops.
    921670The destructor provides a newline, if formatted text ends with a full line.
    922 Figure~\ref{f:CFormatGenImpl} shows the C implementation of the \CFA input generator with one additional field and the computed @goto@.
    923 For contrast, Figure~\ref{f:PythonFormatter} shows the equivalent Python format generator with the same properties as the \CFA format generator.
    924 
    925 % https://dl-acm-org.proxy.lib.uwaterloo.ca/
    926 
    927 An important application for the asymmetric generator is a device-driver, because device drivers are a significant source of operating-system errors: 85\% in Windows XP~\cite[p.~78]{Swift05} and 51.6\% in Linux~\cite[p.~1358,]{Xiao19}. %\cite{Palix11}
    928 Swift \etal~\cite[p.~86]{Swift05} restructure device drivers using the Extension Procedure Call (XPC) within the kernel via functions @nooks_driver_call@ and @nooks_kernel_call@, which have coroutine properties context switching to separate stacks with explicit hand-off calls;
    929 however, the calls do not retain execution state, and hence always start from the top.
    930 The alternative approach for implementing device drivers is using stack-ripping.
    931 However, Adya \etal~\cite{Adya02} argue against stack ripping in Section 3.2 and suggest a hybrid approach in Section 4 using cooperatively scheduled \emph{fibers}, which is coroutining.
    932 
    933 Figure~\ref{f:DeviceDriverGen} shows the generator advantages in implementing a simple network device-driver with the following protocol:
     671Figure~\ref{f:CFormatSim} shows the C implementation of the \CFA input generator with one additional field and the computed @goto@.
     672For contrast, Figure~\ref{f:PythonFormatter} shows the equivalent Python format generator with the same properties as the Fibonacci generator.
     673
     674Figure~\ref{f:DeviceDriverGen} shows a \emph{killer} asymmetric generator, a device-driver, because device drivers caused 70\%-85\% of failures in Windows/Linux~\cite{Swift05}.
     675Device drives follow the pattern of simple data state but complex execution state, \ie finite state-machine (FSM) parsing a protocol.
     676For example, the following protocol:
    934677\begin{center}
    935678\ldots\, STX \ldots\, message \ldots\, ESC ETX \ldots\, message \ldots\, ETX 2-byte crc \ldots
    936679\end{center}
    937 where the network message begins with the control character STX, ends with an ETX, and is followed by a two-byte cyclic-redundancy check.
     680is a network message beginning with the control character STX, ending with an ETX, and followed by a 2-byte cyclic-redundancy check.
    938681Control characters may appear in a message if preceded by an ESC.
    939682When a message byte arrives, it triggers an interrupt, and the operating system services the interrupt by calling the device driver with the byte read from a hardware register.
    940 The device driver returns a status code of its current state, and when a complete message is obtained, the operating system reads the message accumulated in the supplied buffer.
    941 Hence, the device driver is an input/output generator, where the cost of resuming the device-driver generator is the same as call and return, so performance in an operating-system kernel is excellent.
    942 The key benefits of using a generator are correctness, safety, and maintenance because the execution states are transcribed directly into the programming language rather than table lookup or stack ripping.
    943 % The conclusion is that FSMs are complex and occur in important domains, so direct generator support is important in a system programming language.
     683The device driver returns a status code of its current state, and when a complete message is obtained, the operating system knows the message is in the message buffer.
     684Hence, the device driver is an input/output generator.
     685
     686Note, the cost of creating and resuming the device-driver generator, @Driver@, is virtually identical to call/return, so performance in an operating-system kernel is excellent.
     687As well, the data state is small, where variables @byte@ and @msg@ are communication variables for passing in message bytes and returning the message, and variables @lnth@, @crc@, and @sum@ are local variable that must be retained between calls and are manually hoisted into the generator type.
     688% Manually, detecting and hoisting local-state variables is easy when the number is small.
     689In contrast, the execution state is large, with one @resume@ and seven @suspend@s.
     690Hence, the key benefits of the generator are correctness, safety, and maintenance because the execution states are transcribed directly into the programming language rather than using a table-driven approach.
     691Because FSMs can be complex and frequently occur in important domains, direct generator support is important in a system programming language.
    944692
    945693\begin{figure}
    946694\centering
     695\newbox\myboxA
     696\begin{lrbox}{\myboxA}
     697\begin{python}[aboveskip=0pt,belowskip=0pt]
     698def Fib():
     699        fn1, fn = 0, 1
     700        while True:
     701                `yield fn1`
     702                fn1, fn = fn, fn1 + fn
     703f1 = Fib()
     704f2 = Fib()
     705for i in range( 10 ):
     706        print( next( f1 ), next( f2 ) )
     707
     708
     709
     710
     711
     712
     713\end{python}
     714\end{lrbox}
     715
     716\newbox\myboxB
     717\begin{lrbox}{\myboxB}
     718\begin{python}[aboveskip=0pt,belowskip=0pt]
     719def Fmt():
     720        try:
     721                while True:
     722                        for g in range( 5 ):
     723                                for b in range( 4 ):
     724                                        print( `(yield)`, end='' )
     725                                print( '  ', end='' )
     726                        print()
     727        except GeneratorExit:
     728                if g != 0 | b != 0:
     729                        print()
     730fmt = Fmt()
     731`next( fmt )`                    # prime, next prewritten
     732for i in range( 41 ):
     733        `fmt.send( 'a' );`      # send to yield
     734\end{python}
     735\end{lrbox}
     736\subfloat[Fibonacci]{\label{f:PythonFibonacci}\usebox\myboxA}
     737\hspace{3pt}
     738\vrule
     739\hspace{3pt}
     740\subfloat[Formatter]{\label{f:PythonFormatter}\usebox\myboxB}
     741\caption{Python generator}
     742\label{f:PythonGenerator}
     743
     744\bigskip
     745
    947746\begin{tabular}{@{}l|l@{}}
    948747\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     
    951750`generator` Driver {
    952751        Status status;
    953         char byte, * msg; // communication
    954         int lnth, sum;      // local state
    955         short int crc;
     752        unsigned char byte, * msg; // communication
     753        unsigned int lnth, sum;      // local state
     754        unsigned short int crc;
    956755};
    957756void ?{}( Driver & d, char * m ) { d.msg = m; }
     
    998797\end{figure}
    999798
    1000 Generators can also have symmetric activation using resume/resume to create control-flow cycles among generators.
     799Figure~\ref{f:CFAPingPongGen} shows a symmetric generator, where the generator resumes another generator, forming a resume/resume cycle.
    1001800(The trivial cycle is a generator resuming itself.)
    1002801This control flow is similar to recursion for functions but without stack growth.
    1003 Figure~\ref{f:PingPongFullCoroutineSteps} shows the steps for symmetric control-flow using for the ping/pong program in Figure~\ref{f:CFAPingPongGen}.
    1004 The program starts by creating the generators, @ping@ and @pong@, and then assigns the partners that form the cycle.
     802The steps for symmetric control-flow are creating, executing, and terminating the cycle.
    1005803Constructing the cycle must deal with definition-before-use to close the cycle, \ie, the first generator must know about the last generator, which is not within scope.
    1006804(This issue occurs for any cyclic data structure.)
    1007 % (Alternatively, the constructor can assign the partners as they are declared, except the first, and the first-generator partner is set after the last generator declaration to close the cycle.)
    1008 Once the cycle is formed, the program main resumes one of the generators, @ping@, and the generators can then traverse an arbitrary number of cycles using @resume@ to activate partner generator(s).
     805% The example creates all the generators and then assigns the partners that form the cycle.
     806% Alternatively, the constructor can assign the partners as they are declared, except the first, and the first-generator partner is set after the last generator declaration to close the cycle.
     807Once the cycle is formed, the program main resumes one of the generators, and the generators can then traverse an arbitrary cycle using @resume@ to activate partner generator(s).
    1009808Terminating the cycle is accomplished by @suspend@ or @return@, both of which go back to the stack frame that started the cycle (program main in the example).
    1010 Note, the creator and starter may be different, \eg if the creator calls another function that starts the cycle.
    1011809The starting stack-frame is below the last active generator because the resume/resume cycle does not grow the stack.
    1012 Also, since local variables are not retained in the generator function, there are no objects with destructors to be called, so the cost is the same as a function return.
    1013 Destructor cost occurs when the generator instance is deallocated by the creator.
    1014 
    1015 \begin{figure}
    1016 \centering
    1017 \input{FullCoroutinePhases.pstex_t}
    1018 \vspace*{-10pt}
    1019 \caption{Symmetric coroutine steps: Ping / Pong}
    1020 \label{f:PingPongFullCoroutineSteps}
    1021 \end{figure}
     810Also, since local variables are not retained in the generator function, it does not contain any objects with destructors that must be called, so the  cost is the same as a function return.
     811Destructor cost occurs when the generator instance is deallocated, which is easily controlled by the programmer.
     812
     813Figure~\ref{f:CPingPongSim} shows the implementation of the symmetric generator, where the complexity is the @resume@, which needs an extension to the calling convention to perform a forward rather than backward jump.
     814This jump-starts at the top of the next generator main to re-execute the normal calling convention to make space on the stack for its local variables.
     815However, before the jump, the caller must reset its stack (and any registers) equivalent to a @return@, but subsequently jump forward.
     816This semantics is basically a tail-call optimization, which compilers already perform.
     817The example shows the assembly code to undo the generator's entry code before the direct jump.
     818This assembly code depends on what entry code is generated, specifically if there are local variables and the level of optimization.
     819To provide this new calling convention requires a mechanism built into the compiler, which is beyond the scope of \CFA at this time.
     820Nevertheless, it is possible to hand generate any symmetric generators for proof of concept and performance testing.
     821A compiler could also eliminate other artifacts in the generator simulation to further increase performance, \eg LLVM has various coroutine support~\cite{CoroutineTS}, and \CFA can leverage this support should it fork @clang@.
    1022822
    1023823\begin{figure}
     
    1026826\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1027827`generator PingPong` {
    1028         int N, i;                               // local state
    1029828        const char * name;
     829        int N;
     830        int i;                          // local state
    1030831        PingPong & partner; // rebindable reference
    1031832};
    1032833
    1033834void `main( PingPong & pp )` with(pp) {
    1034 
    1035 
    1036835        for ( ; i < N; i += 1 ) {
    1037836                sout | name | i;
     
    1051850\begin{cfa}[escapechar={},aboveskip=0pt,belowskip=0pt]
    1052851typedef struct PingPong {
    1053         int restart, N, i;
    1054852        const char * name;
     853        int N, i;
    1055854        struct PingPong * partner;
     855        void * next;
    1056856} PingPong;
    1057 #define PPCtor(name, N) {0, N, 0, name, NULL}
     857#define PPCtor(name, N) {name,N,0,NULL,NULL}
    1058858void comain( PingPong * pp ) {
    1059         static void * states[] = {&&s0, &&s1};
    1060         goto *states[pp->restart];
    1061   s0: pp->restart = 1;
     859        if ( pp->next ) goto *pp->next;
     860        pp->next = &&cycle;
    1062861        for ( ; pp->i < pp->N; pp->i += 1 ) {
    1063862                printf( "%s %d\n", pp->name, pp->i );
    1064863                asm( "mov  %0,%%rdi" : "=m" (pp->partner) );
    1065864                asm( "mov  %rdi,%rax" );
    1066                 asm( "add  $16, %rsp" );
    1067                 asm( "popq %rbp" );
     865                asm( "popq %rbx" );
    1068866                asm( "jmp  comain" );
    1069           s1: ;
     867          cycle: ;
    1070868        }
    1071869}
     
    1083881\end{figure}
    1084882
    1085 Figure~\ref{f:CPingPongSim} shows the C implementation of the \CFA symmetric generator, where there is still only one additional field, @restart@, but @resume@ is more complex because it does a forward rather than backward jump.
    1086 Before the jump, the parameter for the next call @partner@ is placed into the register used for the first parameter, @rdi@, and the remaining registers are reset for a return.
    1087 The @jmp comain@ restarts the function but with a different parameter, so the new call's behavior depends on the state of the coroutine type, \ie branch to restart location with different data state.
    1088 While the semantics of call forward is a tail-call optimization, which compilers perform, the generator state is different on each call rather a common state for a tail-recursive function (\ie the parameter to the function never changes during the forward calls).
    1089 However, this assembler code depends on what entry code is generated, specifically if there are local variables and the level of optimization.
    1090 Hence, internal compiler support is necessary for any forward call or backwards return, \eg LLVM has various coroutine support~\cite{CoroutineTS}, and \CFA can leverage this support should it eventually fork @clang@.
    1091 For this reason, \CFA does not support general symmetric generators at this time, but, it is possible to hand generate any symmetric generators, as in Figure~\ref{f:CPingPongSim}, for proof of concept and performance testing.
    1092 
    1093 Finally, part of this generator work was inspired by the recent \CCtwenty coroutine proposal~\cite{C++20Coroutine19}, which uses the general term coroutine to mean generator.
     883Finally, part of this generator work was inspired by the recent \CCtwenty generator proposal~\cite{C++20Coroutine19} (which they call coroutines).
    1094884Our work provides the same high-performance asymmetric generators as \CCtwenty, and extends their work with symmetric generators.
    1095885An additional \CCtwenty generator feature allows @suspend@ and @resume@ to be followed by a restricted compound statement that is executed after the current generator has reset its stack but before calling the next generator, specified with \CFA syntax:
     
    1106896\label{s:Coroutine}
    1107897
    1108 Stackful coroutines (Table~\ref{t:ExecutionPropertyComposition} case 5) extend generator semantics with an implicit closure and @suspend@ may appear in a helper function called from the coroutine main because of the separate stack.
    1109 Note, simulating coroutines with stacks of generators, \eg Python with @yield from@ cannot handle symmetric control-flow.
    1110 Furthermore, all stack components must be of generators, so it is impossible to call a library function passing a generator that yields.
    1111 Creating a generator copy of the library function maybe impossible because the library function is opaque.
    1112 
    1113 A \CFA coroutine is specified by replacing @generator@ with @coroutine@ for the type.
    1114 Coroutine generality results in higher cost for creation, due to dynamic stack allocation, for execution, due to context switching among stacks, and for terminating, due to possible stack unwinding and dynamic stack deallocation.
     898Stackful coroutines extend generator semantics, \ie there is an implicit closure and @suspend@ may appear in a helper function called from the coroutine main.
     899A coroutine is specified by replacing @generator@ with @coroutine@ for the type.
     900Coroutine generality results in higher cost for creation, due to dynamic stack allocation, execution, due to context switching among stacks, and terminating, due to possible stack unwinding and dynamic stack deallocation.
    1115901A series of different kinds of coroutines and their implementations demonstrate how coroutines extend generators.
    1116902
    1117903First, the previous generator examples are converted to their coroutine counterparts, allowing local-state variables to be moved from the generator type into the coroutine main.
    1118 Now the coroutine type only contains communication variables between interface functions and the coroutine main.
    1119 \begin{center}
    1120 \begin{tabular}{@{}l|l|l|l@{}}
    1121 \multicolumn{1}{c|}{Fibonacci} & \multicolumn{1}{c|}{Formatter} & \multicolumn{1}{c|}{Device Driver} & \multicolumn{1}{c}{PingPong} \\
    1122 \hline
     904\begin{description}
     905\item[Fibonacci]
     906Move the declaration of @fn1@ to the start of coroutine main.
    1123907\begin{cfa}[xleftmargin=0pt]
    1124 void main( Fib & fib ) ...
     908void main( Fib & fib ) with(fib) {
    1125909        `int fn1;`
    1126 
    1127 
    1128 \end{cfa}
    1129 &
     910\end{cfa}
     911\item[Formatter]
     912Move the declaration of @g@ and @b@ to the for loops in the coroutine main.
    1130913\begin{cfa}[xleftmargin=0pt]
    1131914for ( `g`; 5 ) {
    1132915        for ( `b`; 4 ) {
    1133 
    1134 
    1135 \end{cfa}
    1136 &
     916\end{cfa}
     917\item[Device Driver]
     918Move the declaration of @lnth@ and @sum@ to their points of initialization.
    1137919\begin{cfa}[xleftmargin=0pt]
    1138 status = CONT;
    1139 `int lnth = 0, sum = 0;`
    1140 ...
    1141 `short int crc = byte << 8;`
    1142 \end{cfa}
    1143 &
     920        status = CONT;
     921        `unsigned int lnth = 0, sum = 0;`
     922        ...
     923        `unsigned short int crc = byte << 8;`
     924\end{cfa}
     925\item[PingPong]
     926Move the declaration of @i@ to the for loop in the coroutine main.
    1144927\begin{cfa}[xleftmargin=0pt]
    1145 void main( PingPong & pp ) ...
     928void main( PingPong & pp ) with(pp) {
    1146929        for ( `i`; N ) {
    1147 
    1148 
    1149 \end{cfa}
    1150 \end{tabular}
    1151 \end{center}
     930\end{cfa}
     931\end{description}
    1152932It is also possible to refactor code containing local-state and @suspend@ statements into a helper function, like the computation of the CRC for the device driver.
    1153933\begin{cfa}
    1154 int Crc() {
    1155         `suspend;`  short int crc = byte << 8;
    1156         `suspend;`  status = (crc | byte) == sum ? MSG : ECRC;
     934unsigned int Crc() {
     935        `suspend;`
     936        unsigned short int crc = byte << 8;
     937        `suspend;`
     938        status = (crc | byte) == sum ? MSG : ECRC;
    1157939        return crc;
    1158940}
    1159941\end{cfa}
    1160 A call to this function is placed at the end of the device driver's coroutine-main.
    1161 For complex FSMs, refactoring is part of normal program abstraction, especially when code is used in multiple places.
     942A call to this function is placed at the end of the driver's coroutine-main.
     943For complex finite-state machines, refactoring is part of normal program abstraction, especially when code is used in multiple places.
    1162944Again, this complexity is usually associated with execution state rather than data state.
    1163945
    1164946\begin{comment}
    1165 Figure~\ref{f:Coroutine3States} creates a @coroutine@ type, @`coroutine` Fib { int fn; }@, which provides communication, @fn@, for the \newterm{coroutine main}, @main@, which runs on the coroutine stack, and possibly multiple interface functions, \eg @restart@.
    1166 Like the structure in Figure~\ref{f:ExternalState}, the coroutine type allows multiple instances, where instances of this type are passed to the overloaded coroutine main.
     947Figure~\ref{f:Coroutine3States} creates a @coroutine@ type, @`coroutine` Fib { int fn; }@, which provides communication, @fn@, for the \newterm{coroutine main}, @main@, which runs on the coroutine stack, and possibly multiple interface functions, \eg @next@.
     948Like the structure in Figure~\ref{f:ExternalState}, the coroutine type allows multiple instances, where instances of this type are passed to the (overloaded) coroutine main.
    1167949The coroutine main's stack holds the state for the next generation, @f1@ and @f2@, and the code represents the three states in the Fibonacci formula via the three suspend points, to context switch back to the caller's @resume@.
    1168 The interface function @restart@, takes a Fibonacci instance and context switches to it using @resume@;
     950The interface function @next@, takes a Fibonacci instance and context switches to it using @resume@;
    1169951on restart, the Fibonacci field, @fn@, contains the next value in the sequence, which is returned.
    1170952The first @resume@ is special because it allocates the coroutine stack and cocalls its coroutine main on that stack;
     
    13321114\begin{figure}
    13331115\centering
     1116\lstset{language=CFA,escapechar={},moredelim=**[is][\protect\color{red}]{`}{`}}% allow $
    13341117\begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}}
    13351118\begin{cfa}
    13361119`coroutine` Prod {
    1337         Cons & c;                       $\C[1.5in]{// communication}$
     1120        Cons & c;                       // communication
    13381121        int N, money, receipt;
    13391122};
    13401123void main( Prod & prod ) with( prod ) {
    1341         for ( i; N ) {          $\C{// 1st resume}\CRT$
     1124        // 1st resume starts here
     1125        for ( i; N ) {
    13421126                int p1 = random( 100 ), p2 = random( 100 );
     1127                sout | p1 | " " | p2;
    13431128                int status = delivery( c, p1, p2 );
     1129                sout | " $" | money | nl | status;
    13441130                receipt += 1;
    13451131        }
    13461132        stop( c );
     1133        sout | "prod stops";
    13471134}
    13481135int payment( Prod & prod, int money ) {
     
    13651152\begin{cfa}
    13661153`coroutine` Cons {
    1367         Prod & p;                       $\C[1.5in]{// communication}$
     1154        Prod & p;                       // communication
    13681155        int p1, p2, status;
    13691156        bool done;
    13701157};
    13711158void ?{}( Cons & cons, Prod & p ) {
    1372         &cons.p = &p;           $\C{// reassignable reference}$
     1159        &cons.p = &p; // reassignable reference
    13731160        cons.[status, done ] = [0, false];
    13741161}
    13751162void main( Cons & cons ) with( cons ) {
    1376         int money = 1, receipt; $\C{// 1st resume}\CRT$
     1163        // 1st resume starts here
     1164        int money = 1, receipt;
    13771165        for ( ; ! done; ) {
     1166                sout | p1 | " " | p2 | nl | " $" | money;
    13781167                status += 1;
    13791168                receipt = payment( p, money );
     1169                sout | " #" | receipt;
    13801170                money += 1;
    13811171        }
     1172        sout | "cons stops";
    13821173}
    13831174int delivery( Cons & cons, int p1, int p2 ) {
     
    13981189
    13991190Figure~\ref{f:ProdCons} shows the ping-pong example in Figure~\ref{f:CFAPingPongGen} extended into a producer/consumer symmetric-coroutine performing bidirectional communication.
    1400 This example is illustrative because both producer and consumer have two interface functions with @resume@s that suspend execution in these interface functions.
     1191This example is illustrative because both producer/consumer have two interface functions with @resume@s that suspend execution in these interface (helper) functions.
    14011192The program main creates the producer coroutine, passes it to the consumer coroutine in its initialization, and closes the cycle at the call to @start@ along with the number of items to be produced.
    1402 The call to @start@ is the first @resume@ of @prod@, which remembers the program main as the starter and creates @prod@'s stack with a frame for @prod@'s coroutine main at the top, and context switches to it.
    1403 @prod@'s coroutine main starts, creates local-state variables that are retained between coroutine activations, and executes $N$ iterations, each generating two random values, calling the consumer's @deliver@ function to transfer the values, and printing the status returned from the consumer.
    1404 The producer's call to @delivery@ transfers values into the consumer's communication variables, resumes the consumer, and returns the consumer status.
    1405 Similarly on the first resume, @cons@'s stack is created and initialized, holding local-state variables retained between subsequent activations of the coroutine.
    1406 The symmetric coroutine cycle forms when the consumer calls the producer's @payment@ function, which resumes the producer in the consumer's delivery function.
    1407 When the producer calls @delivery@ again, it resumes the consumer in the @payment@ function.
    1408 Both interface functions then return to their corresponding coroutine-main functions for the next cycle.
     1193The first @resume@ of @prod@ creates @prod@'s stack with a frame for @prod@'s coroutine main at the top, and context switches to it.
     1194@prod@'s coroutine main starts, creates local-state variables that are retained between coroutine activations, and executes $N$ iterations, each generating two random values, calling the consumer to deliver the values, and printing the status returned from the consumer.
     1195
     1196The producer call to @delivery@ transfers values into the consumer's communication variables, resumes the consumer, and returns the consumer status.
     1197On the first resume, @cons@'s stack is created and initialized, holding local-state variables retained between subsequent activations of the coroutine.
     1198The consumer iterates until the @done@ flag is set, prints the values delivered by the producer, increments status, and calls back to the producer via @payment@, and on return from @payment@, prints the receipt from the producer and increments @money@ (inflation).
     1199The call from the consumer to @payment@ introduces the cycle between producer and consumer.
     1200When @payment@ is called, the consumer copies values into the producer's communication variable and a resume is executed.
     1201The context switch restarts the producer at the point where it last context switched, so it continues in @delivery@ after the resume.
     1202@delivery@ returns the status value in @prod@'s coroutine main, where the status is printed.
     1203The loop then repeats calling @delivery@, where each call resumes the consumer coroutine.
     1204The context switch to the consumer continues in @payment@.
     1205The consumer increments and returns the receipt to the call in @cons@'s coroutine main.
     1206The loop then repeats calling @payment@, where each call resumes the producer coroutine.
    14091207Figure~\ref{f:ProdConsRuntimeStacks} shows the runtime stacks of the program main, and the coroutine mains for @prod@ and @cons@ during the cycling.
    1410 As a consequence of a coroutine retaining its last resumer for suspending back, these reverse pointers allow @suspend@ to cycle \emph{backwards} around a symmetric coroutine cycle.
    14111208
    14121209\begin{figure}
     
    14171214\caption{Producer / consumer runtime stacks}
    14181215\label{f:ProdConsRuntimeStacks}
     1216
     1217\medskip
     1218
     1219\begin{center}
     1220\input{FullCoroutinePhases.pstex_t}
     1221\end{center}
     1222\vspace*{-10pt}
     1223\caption{Ping / Pong coroutine steps}
     1224\label{f:PingPongFullCoroutineSteps}
    14191225\end{figure}
    14201226
    14211227Terminating a coroutine cycle is more complex than a generator cycle, because it requires context switching to the program main's \emph{stack} to shutdown the program, whereas generators started by the program main run on its stack.
    1422 Furthermore, each deallocated coroutine must execute all destructors for objects allocated in the coroutine type \emph{and} allocated on the coroutine's stack at the point of suspension, which can be arbitrarily deep.
    1423 In the example, termination begins with the producer's loop stopping after N iterations and calling the consumer's @stop@ function, which sets the @done@ flag, resumes the consumer in function @payment@, terminating the call, and the consumer's loop in its coroutine main.
    1424 % (Not shown is having @prod@ raise a nonlocal @stop@ exception at @cons@ after it finishes generating values and suspend back to @cons@, which catches the @stop@ exception to terminate its loop.)
    1425 When the consumer's main ends, its stack is already unwound so any stack allocated objects with destructors are finalized.
    1426 The question now is where does control continue?
    1427 
    1428 The na\"{i}ve semantics for coroutine-cycle termination is to context switch to the last resumer, like executing a @suspend@ or @return@ in a generator.
     1228Furthermore, each deallocated coroutine must guarantee all destructors are run for object allocated in the coroutine type \emph{and} allocated on the coroutine's stack at the point of suspension, which can be arbitrarily deep.
     1229When a coroutine's main ends, its stack is already unwound so any stack allocated objects with destructors have been finalized.
     1230The na\"{i}ve semantics for coroutine-cycle termination is to context switch to the last resumer, like executing a @suspend@/@return@ in a generator.
    14291231However, for coroutines, the last resumer is \emph{not} implicitly below the current stack frame, as for generators, because each coroutine's stack is independent.
    14301232Unfortunately, it is impossible to determine statically if a coroutine is in a cycle and unrealistic to check dynamically (graph-cycle problem).
    14311233Hence, a compromise solution is necessary that works for asymmetric (acyclic) and symmetric (cyclic) coroutines.
    1432 Our solution is to retain a coroutine's starter (first resumer), and context switch back to the starter when the coroutine ends.
    1433 Hence, the consumer restarts its first resumer, @prod@, in @stop@, and when the producer ends, it restarts its first resumer, program main, in @start@ (see dashed lines from the end of the coroutine mains in Figure~\ref{f:ProdConsRuntimeStacks}).
     1234
     1235Our solution is to context switch back to the first resumer (starter) once the coroutine ends.
    14341236This semantics works well for the most common asymmetric and symmetric coroutine usage patterns.
    1435 For asymmetric coroutines, it is common for the first resumer (starter) coroutine to be the only resumer;
    1436 for symmetric coroutines, it is common for the cycle creator to persist for the lifetime of the cycle.
    1437 For other scenarios, it is always possible to devise a solution with additional programming effort, such as forcing the cycle forward or backward to a safe point before starting termination.
    1438 
    1439 Note, the producer/consumer example does not illustrate the full power of the starter semantics because @cons@ always ends first.
    1440 Assume generator @PingPong@ in Figure~\ref{f:PingPongSymmetricGenerator} is converted to a coroutine.
    1441 Unlike generators, coroutines have a starter structure with multiple levels, where the program main starts @ping@ and @ping@ starts @pong@.
    1442 By adjusting $N$ for either @ping@ or @pong@, it is possible to have either finish first.
    1443 If @pong@ ends first, it resumes its starter @ping@ in its coroutine main, then @ping@ ends and resumes its starter the program main on return;
    1444 if @ping@ ends first, it resumes its starter the program main on return.
    1445 Regardless of the cycle complexity, the starter structure always leads back to the program main, but the path can be entered at an arbitrary point.
    1446 Once back at the program main (creator), coroutines @ping@ and @pong@ are deallocated, running any destructors for objects within the coroutine and possibly deallocating any coroutine stacks for non-terminated coroutines, where stack deallocation implies stack unwinding to find destructors for allocated objects on the stack.
    1447 Hence, the \CFA termination semantics for the generator and coroutine ensure correct deallocation semantics, regardless of the coroutine's state (terminated or active), like any other aggregate object.
    1448 
    1449 
    1450 \subsection{Generator / coroutine implementation}
    1451 
    1452 A significant implementation challenge for generators and coroutines (and threads in Section~\ref{s:threads}) is adding extra fields to the custom types and related functions, \eg inserting code after/before the coroutine constructor/destructor and @main@ to create/initialize/de-initialize/destroy any extra fields, \eg the coroutine stack.
    1453 There are several solutions to this problem, which follow from the object-oriented flavor of adopting custom types.
     1237For asymmetric coroutines, it is common for the first resumer (starter) coroutine to be the only resumer.
     1238All previous generators converted to coroutines have this property.
     1239For symmetric coroutines, it is common for the cycle creator to persist for the lifetime of the cycle.
     1240Hence, the starter coroutine is remembered on the first resume and ending the coroutine resumes the starter.
     1241Figure~\ref{f:ProdConsRuntimeStacks} shows this semantic by the dashed lines from the end of the coroutine mains: @prod@ starts @cons@ so @cons@ resumes @prod@ at the end, and the program main starts @prod@ so @prod@ resumes the program main at the end.
     1242For other scenarios, it is always possible to devise a solution with additional programming effort, such as forcing the cycle forward (backward) to a safe point before starting termination.
     1243
     1244The producer/consumer example does not illustrate the full power of the starter semantics because @cons@ always ends first.
     1245Assume generator @PingPong@ is converted to a coroutine.
     1246Figure~\ref{f:PingPongFullCoroutineSteps} shows the creation, starter, and cyclic execution steps of the coroutine version.
     1247The program main creates (declares) coroutine instances @ping@ and @pong@.
     1248Next, program main resumes @ping@, making it @ping@'s starter, and @ping@'s main resumes @pong@'s main, making it @pong@'s starter.
     1249Execution forms a cycle when @pong@ resumes @ping@, and cycles $N$ times.
     1250By adjusting $N$ for either @ping@/@pong@, it is possible to have either one finish first, instead of @pong@ always ending first.
     1251If @pong@ ends first, it resumes its starter @ping@ in its coroutine main, then @ping@ ends and resumes its starter the program main in function @start@.
     1252If @ping@ ends first, it resumes its starter the program main in function @start@.
     1253Regardless of the cycle complexity, the starter stack always leads back to the program main, but the stack can be entered at an arbitrary point.
     1254Once back at the program main, coroutines @ping@ and @pong@ are deallocated.
     1255For generators, deallocation runs the destructors for all objects in the generator type.
     1256For coroutines, deallocation deals with objects in the coroutine type and must also run the destructors for any objects pending on the coroutine's stack for any unterminated coroutine.
     1257Hence, if a coroutine's destructor detects the coroutine is not ended, it implicitly raises a cancellation exception (uncatchable exception) at the coroutine and resumes it so the cancellation exception can propagate to the root of the coroutine's stack destroying all local variable on the stack.
     1258So the \CFA semantics for the generator and coroutine, ensure both can be safely deallocated at any time, regardless of their current state, like any other aggregate object.
     1259Explicitly raising normal exceptions at another coroutine can replace flag variables, like @stop@, \eg @prod@ raises a @stop@ exception at @cons@ after it finishes generating values and resumes @cons@, which catches the @stop@ exception to terminate its loop.
     1260
     1261Finally, there is an interesting effect for @suspend@ with symmetric coroutines.
     1262A coroutine must retain its last resumer to suspend back because the resumer is on a different stack.
     1263These reverse pointers allow @suspend@ to cycle \emph{backwards}, which may be useful in certain cases.
     1264However, there is an anomaly if a coroutine resumes itself, because it overwrites its last resumer with itself, losing the ability to resume the last external resumer.
     1265To prevent losing this information, a self-resume does not overwrite the last resumer.
     1266
     1267
     1268\subsection{Generator / Coroutine Implementation}
     1269
     1270A significant implementation challenge for generators/coroutines (and threads in Section~\ref{s:threads}) is adding extra fields to the custom types and related functions, \eg inserting code after/before the coroutine constructor/destructor and @main@ to create/initialize/de-initialize/destroy any extra fields, \eg stack.
     1271There are several solutions to these problem, which follow from the object-oriented flavour of adopting custom types.
    14541272
    14551273For object-oriented languages, inheritance is used to provide extra fields and code via explicit inheritance:
     
    14581276\end{cfa}
    14591277% The problem is that the programming language and its tool chain, \eg debugger, @valgrind@, need to understand @baseCoroutine@ because it infers special property, so type @baseCoroutine@ becomes a de facto keyword and all types inheriting from it are implicitly custom types.
    1460 The problem is that some special properties are not handled by existing language semantics, \eg the execution of constructors and destructors is in the wrong order to implicitly start threads because the thread must start \emph{after} all constructors as it relies on a completely initialized object, but the inherited constructor runs \emph{before} the derived.
     1278The problem is that some special properties are not handled by existing language semantics, \eg the execution of constructors/destructors is in the wrong order to implicitly start threads because the thread must start \emph{after} all constructors as it relies on a completely initialized object, but the inherited constructor runs \emph{before} the derived.
    14611279Alternatives, such as explicitly starting threads as in Java, are repetitive and forgetting to call start is a common source of errors.
    14621280An alternative is composition:
     
    14761294Users wanting to extend custom types or build their own can only do so in ways offered by the language.
    14771295Furthermore, implementing custom types without language support may display the power of a programming language.
    1478 \CFA blends the two approaches, providing custom type for idiomatic \CFA code, while extending and building new custom types is still possible, similar to Java concurrency with builtin and library (@java.util.concurrent@) monitors.
     1296\CFA blends the two approaches, providing custom type for idiomatic \CFA code, while extending and building new custom types is still possible, similar to Java concurrency with builtin and library.
    14791297
    14801298Part of the mechanism to generalize custom types is the \CFA trait~\cite[\S~2.3]{Moss18}, \eg the definition for custom-type @coroutine@ is anything satisfying the trait @is_coroutine@, and this trait both enforces and restricts the coroutine-interface functions.
     
    14861304forall( `dtype` T | is_coroutine(T) ) void $suspend$( T & ), resume( T & );
    14871305\end{cfa}
    1488 Note, copying generators, coroutines, and threads is undefined because multiple objects cannot execute on a shared stack and stack copying does not work in unmanaged languages (no garbage collection), like C, because the stack may contain pointers to objects within it that require updating for the copy.
    1489 The \CFA @dtype@ property provides no \emph{implicit} copying operations and the @is_coroutine@ trait provides no \emph{explicit} copying operations, so all coroutines must be passed by reference or pointer.
    1490 The function definitions ensure there is a statically typed @main@ function that is the starting point (first stack frame) of a coroutine, and a mechanism to read the coroutine descriptor from its handle.
    1491 The @main@ function has no return value or additional parameters because the coroutine type allows an arbitrary number of interface functions with arbitrary typed input and output values versus fixed ones.
     1306Note, copying generators/coroutines/threads is not meaningful.
     1307For example, both the resumer and suspender descriptors can have bidirectional pointers;
     1308copying these coroutines does not update the internal pointers so behaviour of both copies would be difficult to understand.
     1309Furthermore, two coroutines cannot logically execute on the same stack.
     1310A deep coroutine copy, which copies the stack, is also meaningless in an unmanaged language (no garbage collection), like C, because the stack may contain pointers to object within it that require updating for the copy.
     1311The \CFA @dtype@ property provides no \emph{implicit} copying operations and the @is_coroutine@ trait provides no \emph{explicit} copying operations, so all coroutines must be passed by reference (pointer).
     1312The function definitions ensure there is a statically typed @main@ function that is the starting point (first stack frame) of a coroutine, and a mechanism to get (read) the coroutine descriptor from its handle.
     1313The @main@ function has no return value or additional parameters because the coroutine type allows an arbitrary number of interface functions with corresponding arbitrary typed input/output values versus fixed ones.
    14921314The advantage of this approach is that users can easily create different types of coroutines, \eg changing the memory layout of a coroutine is trivial when implementing the @get_coroutine@ function, and possibly redefining \textsf{suspend} and @resume@.
    14931315
     
    15301352The combination of custom types and fundamental @trait@ description of these types allows a concise specification for programmers and tools, while more advanced programmers can have tighter control over memory layout and initialization.
    15311353
    1532 Figure~\ref{f:CoroutineMemoryLayout} shows different memory-layout options for a coroutine (where a thread is similar).
    1533 The coroutine handle is the @coroutine@ instance containing programmer specified type global and communication variables across interface functions.
     1354Figure~\ref{f:CoroutineMemoryLayout} shows different memory-layout options for a coroutine (where a task is similar).
     1355The coroutine handle is the @coroutine@ instance containing programmer specified type global/communication variables across interface functions.
    15341356The coroutine descriptor contains all implicit declarations needed by the runtime, \eg @suspend@/@resume@, and can be part of the coroutine handle or separate.
    15351357The coroutine stack can appear in a number of locations and be fixed or variable sized.
    1536 Hence, the coroutine's stack could be a variable-length structure (VLS)
    1537 % \footnote{
    1538 % We are examining VLSs, where fields can be variable-sized structures or arrays.
    1539 % Once allocated, a VLS is fixed sized.}
     1358Hence, the coroutine's stack could be a VLS\footnote{
     1359We are examining variable-sized structures (VLS), where fields can be variable-sized structures or arrays.
     1360Once allocated, a VLS is fixed sized.}
    15401361on the allocating stack, provided the allocating stack is large enough.
    1541 For a VLS stack allocation and deallocation is an inexpensive adjustment of the stack pointer, modulo any stack constructor costs to initial frame setup.
    1542 For stack allocation in the heap, allocation and deallocation is an expensive allocation, where the heap can be a shared resource, modulo any stack constructor costs.
    1543 It is also possible to use a split or segmented stack calling convention, available with gcc and clang, allowing a variable-sized stack via a set of connected blocks in the heap.
    1544 Currently, \CFA supports stack and heap allocated descriptors but only fixed-sized heap allocated stacks.
     1362For a VLS stack allocation/deallocation is an inexpensive adjustment of the stack pointer, modulo any stack constructor costs (\eg initial frame setup).
     1363For heap stack allocation, allocation/deallocation is an expensive heap allocation (where the heap can be a shared resource), modulo any stack constructor costs.
     1364With heap stack allocation, it is also possible to use a split (segmented) stack calling convention, available with gcc and clang, so the stack is variable sized.
     1365Currently, \CFA supports stack/heap allocated descriptors but only fixed-sized heap allocated stacks.
    15451366In \CFA debug-mode, the fixed-sized stack is terminated with a write-only page, which catches most stack overflows.
    15461367Experience teaching concurrency with \uC~\cite{CS343} shows fixed-sized stacks are rarely an issue for students.
    1547 Split-stack allocation is under development but requires recompilation of legacy code, which is not always possible.
     1368Split-stack allocation is under development but requires recompilation of legacy code, which may be impossible.
    15481369
    15491370\begin{figure}
     
    15591380
    15601381Concurrency is nondeterministic scheduling of independent sequential execution paths (threads), where each thread has its own stack.
    1561 A single thread with multiple stacks, \ie coroutining, does \emph{not} imply concurrency~\cite[\S~3]{Buhr05a}.
    1562 Coroutining self-schedule the thread across stacks so execution is deterministic.
     1382A single thread with multiple call stacks, \newterm{coroutining}~\cite{Conway63,Marlin80}, does \emph{not} imply concurrency~\cite[\S~2]{Buhr05a}.
     1383In coroutining, coroutines self-schedule the thread across stacks so execution is deterministic.
    15631384(It is \emph{impossible} to generate a concurrency error when coroutining.)
    1564 
    1565 The transition to concurrency, even for a single thread with multiple stacks, occurs when coroutines context switch to a \newterm{scheduling coroutine}, introducing non-determinism from the coroutine perspective~\cite[\S~3]{Buhr05a}.
     1385However, coroutines are a stepping stone towards concurrency.
     1386
     1387The transition to concurrency, even for a single thread with multiple stacks, occurs when coroutines context switch to a \newterm{scheduling coroutine}, introducing non-determinism from the coroutine perspective~\cite[\S~3,]{Buhr05a}.
    15661388Therefore, a minimal concurrency system requires coroutines \emph{in conjunction with a nondeterministic scheduler}.
    1567 The resulting execution system now follows a cooperative threading-model~\cite{Adya02,libdill} because context-switching points to the scheduler are known, but the next unblocking point is unknown due to the scheduler.
    1568 Adding \newterm{preemption} introduces \newterm{non-cooperative} or \newterm{preemptive} scheduling, where context switching points to the scheduler are unknown as they can occur randomly between any two instructions often based on a timer interrupt.
     1389The resulting execution system now follows a cooperative threading model~\cite{Adya02,libdill}, called \newterm{non-preemptive scheduling}.
     1390Adding \newterm{preemption} introduces non-cooperative scheduling, where context switching occurs randomly between any two instructions often based on a timer interrupt, called \newterm{preemptive scheduling}.
     1391While a scheduler introduces uncertain execution among explicit context switches, preemption introduces uncertainty by introducing implicit context switches.
    15691392Uncertainty gives the illusion of parallelism on a single processor and provides a mechanism to access and increase performance on multiple processors.
    1570 The reason is that the scheduler and runtime have complete knowledge about resources and how to best utilized them.
    1571 However, the introduction of unrestricted nondeterminism results in the need for \newterm{mutual exclusion} and \newterm{synchronization}~\cite[\S~4]{Buhr05a}, which restrict nondeterminism for correctness;
     1393The reason is that the scheduler/runtime have complete knowledge about resources and how to best utilized them.
     1394However, the introduction of unrestricted nondeterminism results in the need for \newterm{mutual exclusion} and \newterm{synchronization}, which restrict nondeterminism for correctness;
    15721395otherwise, it is impossible to write meaningful concurrent programs.
    15731396Optimal concurrent performance is often obtained by having as much nondeterminism as mutual exclusion and synchronization correctness allow.
    15741397
    1575 A scheduler can also be stackless or stackful.
     1398A scheduler can either be a stackless or stackful.
    15761399For stackless, the scheduler performs scheduling on the stack of the current coroutine and switches directly to the next coroutine, so there is one context switch.
    15771400For stackful, the current coroutine switches to the scheduler, which performs scheduling, and it then switches to the next coroutine, so there are two context switches.
     
    15821405\label{s:threads}
    15831406
    1584 Threading (Table~\ref{t:ExecutionPropertyComposition} case 11) needs the ability to start a thread and wait for its completion, where a common API is @fork@ and @join@.
    1585 \vspace{4pt}
    1586 \par\noindent
    1587 \begin{tabular}{@{}l|l|l@{}}
    1588 \multicolumn{1}{c|}{\textbf{Java}} & \multicolumn{1}{c|}{\textbf{\Celeven}} & \multicolumn{1}{c}{\textbf{pthreads}} \\
    1589 \hline
    1590 \begin{cfa}
    1591 class MyThread extends Thread {...}
    1592 mythread t = new MyThread(...);
     1407Threading needs the ability to start a thread and wait for its completion.
     1408A common API for this ability is @fork@ and @join@.
     1409\begin{cquote}
     1410\begin{tabular}{@{}lll@{}}
     1411\multicolumn{1}{c}{\textbf{Java}} & \multicolumn{1}{c}{\textbf{\Celeven}} & \multicolumn{1}{c}{\textbf{pthreads}} \\
     1412\begin{cfa}
     1413class MyTask extends Thread {...}
     1414mytask t = new MyTask(...);
    15931415`t.start();` // start
    15941416// concurrency
     
    15971419&
    15981420\begin{cfa}
    1599 class MyThread { ... } // functor
    1600 MyThread mythread;
    1601 `thread t( mythread, ... );` // start
     1421class MyTask { ... } // functor
     1422MyTask mytask;
     1423`thread t( mytask, ... );` // start
    16021424// concurrency
    16031425`t.join();` // wait
     
    16121434\end{cfa}
    16131435\end{tabular}
    1614 \vspace{1pt}
    1615 \par\noindent
    1616 \CFA has a simpler approach using a custom @thread@ type and leveraging declaration semantics, allocation and deallocation, where threads implicitly @fork@ after construction and @join@ before destruction.
    1617 \begin{cfa}
    1618 thread MyThread {};
    1619 void main( MyThread & this ) { ... }
     1436\end{cquote}
     1437\CFA has a simpler approach using a custom @thread@ type and leveraging declaration semantics (allocation/deallocation), where threads implicitly @fork@ after construction and @join@ before destruction.
     1438\begin{cfa}
     1439thread MyTask {};
     1440void main( MyTask & this ) { ... }
    16201441int main() {
    1621         MyThread team`[10]`; $\C[2.5in]{// allocate stack-based threads, implicit start after construction}$
     1442        MyTask team`[10]`; $\C[2.5in]{// allocate stack-based threads, implicit start after construction}$
    16221443        // concurrency
    16231444} $\C{// deallocate stack-based threads, implicit joins before destruction}$
    16241445\end{cfa}
    1625 This semantic ensures a thread is started and stopped exactly once, eliminating some programming error, and scales to multiple threads for basic termination synchronization.
    1626 For block allocation to arbitrary depth, including recursion, threads are created and destroyed in a lattice structure (tree with top and bottom).
     1446This semantic ensures a thread is started and stopped exactly once, eliminating some programming error, and scales to multiple threads for basic (termination) synchronization.
     1447For block allocation to arbitrary depth, including recursion, threads are created/destroyed in a lattice structure (tree with top and bottom).
    16271448Arbitrary topologies are possible using dynamic allocation, allowing threads to outlive their declaration scope, identical to normal dynamic allocation.
    16281449\begin{cfa}
    1629 MyThread * factory( int N ) { ... return `anew( N )`; } $\C{// allocate heap-based threads, implicit start after construction}$
     1450MyTask * factory( int N ) { ... return `anew( N )`; } $\C{// allocate heap-based threads, implicit start after construction}$
    16301451int main() {
    1631         MyThread * team = factory( 10 );
     1452        MyTask * team = factory( 10 );
    16321453        // concurrency
    1633         `adelete( team );` $\C{// deallocate heap-based threads, implicit joins before destruction}\CRT$
     1454        `delete( team );` $\C{// deallocate heap-based threads, implicit joins before destruction}\CRT$
    16341455}
    16351456\end{cfa}
     
    16721493
    16731494
    1674 \subsection{Thread implementation}
     1495\subsection{Thread Implementation}
    16751496
    16761497Threads in \CFA are user level run by runtime kernel threads (see Section~\ref{s:CFARuntimeStructure}), where user threads provide concurrency and kernel threads provide parallelism.
    1677 Like coroutines, and for the same design reasons, \CFA provides a custom @thread@ type and a @trait@ to enforce and restrict the thread-interface functions.
     1498Like coroutines, and for the same design reasons, \CFA provides a custom @thread@ type and a @trait@ to enforce and restrict the task-interface functions.
    16781499\begin{cquote}
    16791500\begin{tabular}{@{}c@{\hspace{3\parindentlnth}}c@{}}
     
    16951516\end{tabular}
    16961517\end{cquote}
    1697 Like coroutines, the @dtype@ property prevents \emph{implicit} copy operations and the @is_thread@ trait provides no \emph{explicit} copy operations, so threads must be passed by reference or pointer.
    1698 Similarly, the function definitions ensure there is a statically typed @main@ function that is the thread starting point (first stack frame), a mechanism to read the thread descriptor from its handle, and a special destructor to prevent deallocation while the thread is executing.
     1518Like coroutines, the @dtype@ property prevents \emph{implicit} copy operations and the @is_thread@ trait provides no \emph{explicit} copy operations, so threads must be passed by reference (pointer).
     1519Similarly, the function definitions ensure there is a statically typed @main@ function that is the thread starting point (first stack frame), a mechanism to get (read) the thread descriptor from its handle, and a special destructor to prevent deallocation while the thread is executing.
    16991520(The qualifier @mutex@ for the destructor parameter is discussed in Section~\ref{s:Monitor}.)
    17001521The difference between the coroutine and thread is that a coroutine borrows a thread from its caller, so the first thread resuming a coroutine creates the coroutine's stack and starts running the coroutine main on the stack;
    17011522whereas, a thread is scheduling for execution in @main@ immediately after its constructor is run.
    1702 No return value or additional parameters are necessary for this function because the @thread@ type allows an arbitrary number of interface functions with corresponding arbitrary typed input and output values.
     1523No return value or additional parameters are necessary for this function because the @thread@ type allows an arbitrary number of interface functions with corresponding arbitrary typed input/output values.
    17031524
    17041525
     
    17061527\label{s:MutualExclusionSynchronization}
    17071528
    1708 Unrestricted nondeterminism is meaningless as there is no way to know when a result is completed and safe to access.
     1529Unrestricted nondeterminism is meaningless as there is no way to know when the result is completed without synchronization.
    17091530To produce meaningful execution requires clawing back some determinism using mutual exclusion and synchronization, where mutual exclusion provides access control for threads using shared data, and synchronization is a timing relationship among threads~\cite[\S~4]{Buhr05a}.
    1710 The shared data protected by mutual exclusion is called a \newterm{critical section}~\cite{Dijkstra65}, and the protection can be simple, only 1 thread, or complex, only N kinds of threads, \eg group~\cite{Joung00} or readers/writer~\cite{Courtois71} problems.
    1711 Without synchronization control in a critical section, an arriving thread can barge ahead of preexisting waiter threads resulting in short/long-term starvation, staleness and freshness problems, and incorrect transfer of data.
    1712 Preventing or detecting barging is a challenge with low-level locks, but made easier through higher-level constructs.
    1713 This challenge is often split into two different approaches: barging \emph{avoidance} and \emph{prevention}.
    1714 Approaches that unconditionally releasing a lock for competing threads to acquire must use barging avoidance with flag/counter variable(s) to force barging threads to wait;
    1715 approaches that conditionally hold locks during synchronization, \eg baton-passing~\cite{Andrews89}, prevent barging completely.
    1716 
    1717 At the lowest level, concurrent control is provided by atomic operations, upon which different kinds of locking mechanisms are constructed, \eg spin locks, semaphores~\cite{Dijkstra68b}, barriers, and path expressions~\cite{Campbell74}.
     1531Some concurrent systems eliminate mutable shared-state by switching to stateless communication like message passing~\cite{Thoth,Harmony,V-Kernel,MPI} (Erlang, MPI), channels~\cite{CSP} (CSP,Go), actors~\cite{Akka} (Akka, Scala), or functional techniques (Haskell).
     1532However, these approaches introduce a new communication mechanism for concurrency different from the standard communication using function call/return.
     1533Hence, a programmer must learn and manipulate two sets of design/programming patterns.
     1534While this distinction can be hidden away in library code, effective use of the library still has to take both paradigms into account.
     1535In contrast, approaches based on stateful models more closely resemble the standard call/return programming model, resulting in a single programming paradigm.
     1536
     1537At the lowest level, concurrent control is implemented by atomic operations, upon which different kinds of locking mechanisms are constructed, \eg semaphores~\cite{Dijkstra68b}, barriers, and path expressions~\cite{Campbell74}.
    17181538However, for productivity it is always desirable to use the highest-level construct that provides the necessary efficiency~\cite{Hochstein05}.
    1719 A significant challenge with locks is composability because it takes careful organization for multiple locks to be used while preventing deadlock.
     1539A newer approach for restricting non-determinism is transactional memory~\cite{Herlihy93}.
     1540While this approach is pursued in hardware~\cite{Nakaike15} and system languages, like \CC~\cite{Cpp-Transactions}, the performance and feature set is still too restrictive to be the main concurrency paradigm for system languages, which is why it is rejected as the core paradigm for concurrency in \CFA.
     1541
     1542One of the most natural, elegant, and efficient mechanisms for mutual exclusion and synchronization for shared-memory systems is the \emph{monitor}.
     1543First proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}, many concurrent programming languages provide monitors as an explicit language construct: \eg Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}.
     1544In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as mutex locks or semaphores to simulate monitors.
     1545For these reasons, \CFA selected monitors as the core high-level concurrency construct, upon which higher-level approaches can be easily constructed.
     1546
     1547
     1548\subsection{Mutual Exclusion}
     1549
     1550A group of instructions manipulating a specific instance of shared data that must be performed atomically is called a \newterm{critical section}~\cite{Dijkstra65}, which is enforced by \newterm{simple mutual-exclusion}.
     1551The generalization is called a \newterm{group critical-section}~\cite{Joung00}, where multiple tasks with the same session use the resource simultaneously and different sessions are segregated, which is enforced by \newterm{complex mutual-exclusion} providing the correct kind and number of threads using a group critical-section.
     1552The readers/writer problem~\cite{Courtois71} is an instance of a group critical-section, where readers share a session but writers have a unique session.
     1553
     1554However, many solutions exist for mutual exclusion, which vary in terms of performance, flexibility and ease of use.
     1555Methods range from low-level locks, which are fast and flexible but require significant attention for correctness, to higher-level concurrency techniques, which sacrifice some performance to improve ease of use.
     1556Ease of use comes by either guaranteeing some problems cannot occur, \eg deadlock free, or by offering a more explicit coupling between shared data and critical section.
     1557For example, the \CC @std::atomic<T>@ offers an easy way to express mutual-exclusion on a restricted set of operations, \eg reading/writing, for numerical types.
     1558However, a significant challenge with locks is composability because it takes careful organization for multiple locks to be used while preventing deadlock.
    17201559Easing composability is another feature higher-level mutual-exclusion mechanisms can offer.
    1721 Some concurrent systems eliminate mutable shared-state by switching to non-shared communication like message passing~\cite{Thoth,Harmony,V-Kernel,MPI} (Erlang, MPI), channels~\cite{CSP} (CSP,Go), actors~\cite{Akka} (Akka, Scala), or functional techniques (Haskell).
    1722 However, these approaches introduce a new communication mechanism for concurrency different from the standard communication using function call/return.
    1723 Hence, a programmer must learn and manipulate two sets of design and programming patterns.
    1724 While this distinction can be hidden away in library code, effective use of the library still has to take both paradigms into account.
    1725 In contrast, approaches based on shared-state models more closely resemble the standard call and return programming model, resulting in a single programming paradigm.
    1726 Finally, a newer approach for restricting non-determinism is transactional memory~\cite{Herlihy93}.
    1727 While this approach is pursued in hardware~\cite{Nakaike15} and system languages, like \CC~\cite{Cpp-Transactions}, the performance and feature set is still too restrictive~\cite{Cascaval08,Boehm09} to be the main concurrency paradigm for system languages.
     1560
     1561
     1562\subsection{Synchronization}
     1563
     1564Synchronization enforces relative ordering of execution, and synchronization tools provide numerous mechanisms to establish these timing relationships.
     1565Low-level synchronization primitives offer good performance and flexibility at the cost of ease of use;
     1566higher-level mechanisms often simplify usage by adding better coupling between synchronization and data, \eg receive-specific versus receive-any thread in message passing or offering specialized solutions, \eg barrier lock.
     1567Often synchronization is used to order access to a critical section, \eg ensuring a waiting writer thread enters the critical section before a calling reader thread.
     1568If the calling reader is scheduled before the waiting writer, the reader has barged.
     1569Barging can result in staleness/freshness problems, where a reader barges ahead of a writer and reads temporally stale data, or a writer barges ahead of another writer overwriting data with a fresh value preventing the previous value from ever being read (lost computation).
     1570Preventing or detecting barging is an involved challenge with low-level locks, which is made easier through higher-level constructs.
     1571This challenge is often split into two different approaches: barging avoidance and prevention.
     1572Algorithms that unconditionally releasing a lock for competing threads to acquire use barging avoidance during synchronization to force a barging thread to wait;
     1573algorithms that conditionally hold locks during synchronization, \eg baton-passing~\cite{Andrews89}, prevent barging completely.
    17281574
    17291575
     
    17311577\label{s:Monitor}
    17321578
    1733 One of the most natural, elegant, efficient, high-level mechanisms for mutual exclusion and synchronization for shared-memory systems is the \emph{monitor} (Table~\ref{t:ExecutionPropertyComposition} case 2).
    1734 First proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}, many concurrent programming languages provide monitors as an explicit language construct: \eg Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}.
    1735 In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as mutex locks or semaphores to manually implement a monitor.
    1736 For these reasons, \CFA selected monitors as the core high-level concurrency construct, upon which higher-level approaches can be easily constructed.
    1737 
    1738 Figure~\ref{f:AtomicCounter} compares a \CFA and Java monitor implementing an atomic counter.
    1739 (Like other concurrent programming languages, \CFA and Java have performant specializations for the basic types using atomic instructions.)
    1740 A \newterm{monitor} is a set of functions that ensure mutual exclusion when accessing shared state.
    1741 (Note, in \CFA, @monitor@ is short-hand for @mutex struct@.)
    1742 More precisely, a monitor is a programming technique that implicitly binds mutual exclusion to static function scope by call and return, as opposed to locks, where mutual exclusion is defined by acquire/release calls, independent of lexical context (analogous to block and heap storage allocation).
    1743 Restricting acquire and release points eases programming, comprehension, and maintenance, at a slight cost in flexibility and efficiency.
    1744 As for other special types, \CFA has a custom @monitor@ type.
    1745 
    1746 \begin{figure}
    1747 \centering
    1748 
    1749 \begin{lrbox}{\myboxA}
    1750 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1751 `monitor` Aint { // atomic integer counter
    1752         int cnt;
    1753 };
    1754 int ++?( Aint & `mutex` this ) with(this) { return ++cnt; }
    1755 int ?=?( Aint & `mutex` lhs, int rhs ) with(lhs) { cnt = rhs; }
    1756 int ?=?(int & lhs, Aint & rhs) with(rhs) { lhs = cnt; }
    1757 
     1579A \textbf{monitor} is a set of functions that ensure mutual exclusion when accessing shared state.
     1580More precisely, a monitor is a programming technique that implicitly binds mutual exclusion to static function scope, as opposed to locks, where mutual-exclusion is defined by acquire/release calls, independent of lexical context (analogous to block and heap storage allocation).
     1581Restricting acquire/release points eases programming, comprehension, and maintenance, at a slight cost in flexibility and efficiency.
     1582\CFA uses a custom @monitor@ type and leverages declaration semantics (deallocation) to protect active or waiting threads in a monitor.
     1583
     1584The following is a \CFA monitor implementation of an atomic counter.
     1585\begin{cfa}[morekeywords=nomutex]
     1586`monitor` Aint { int cnt; }; $\C[4.25in]{// atomic integer counter}$
     1587int ++?( Aint & `mutex`$\(_{opt}\)$ this ) with( this ) { return ++cnt; } $\C{// increment}$
     1588int ?=?( Aint & `mutex`$\(_{opt}\)$ lhs, int rhs ) with( lhs ) { cnt = rhs; } $\C{// conversions with int}\CRT$
     1589int ?=?( int & lhs, Aint & `mutex`$\(_{opt}\)$ rhs ) with( rhs ) { lhs = cnt; }
     1590\end{cfa}
     1591% The @Aint@ constructor, @?{}@, uses the \lstinline[morekeywords=nomutex]@nomutex@ qualifier indicating mutual exclusion is unnecessary during construction because an object is inaccessible (private) until after it is initialized.
     1592% (While a constructor may publish its address into a global variable, doing so generates a race-condition.)
     1593The prefix increment operation, @++?@, is normally @mutex@, indicating mutual exclusion is necessary during function execution, to protect the incrementing from race conditions, unless there is an atomic increment instruction for the implementation type.
     1594The assignment operators provide bidirectional conversion between an atomic and normal integer without accessing field @cnt@;
     1595these operations only need @mutex@, if reading/writing the implementation type is not atomic.
     1596The atomic counter is used without any explicit mutual-exclusion and provides thread-safe semantics, which is similar to the \CC template @std::atomic@.
     1597\begin{cfa}
    17581598int i = 0, j = 0, k = 5;
    1759 Aint x = { 0 }, y = { 0 }, z = { 5 }; // no mutex
    1760 ++x; ++y; ++z;     // mutex
    1761 x = 2; y = i; z = k;  // mutex
    1762 i = x; j = y; k = z;  // no mutex
    1763 \end{cfa}
    1764 \end{lrbox}
    1765 
    1766 \begin{lrbox}{\myboxB}
    1767 \begin{java}[aboveskip=0pt,belowskip=0pt]
    1768 class Aint {
    1769     private int cnt;
    1770     public Aint( int init ) { cnt = init; }
    1771     `synchronized` public int inc() { return ++cnt; }
    1772     `synchronized` public void set( int rhs ) {cnt=rhs;}
    1773     public int get() { return cnt; }
    1774 }
    1775 int i = 0, j = 0, k = 5;
    1776 Aint x=new Aint(0), y=new Aint(0), z=new Aint(5);
    1777 x.inc(); y.inc(); z.inc();
    1778 x.set( 2 ); y.set( i ); z.set( k );
    1779 i = x.get(); j = y.get(); k = z.get();
    1780 \end{java}
    1781 \end{lrbox}
    1782 
    1783 \subfloat[\CFA]{\label{f:AtomicCounterCFA}\usebox\myboxA}
    1784 \hspace{3pt}
    1785 \vrule
    1786 \hspace{3pt}
    1787 \subfloat[Java]{\label{f:AtomicCounterJava}\usebox\myboxB}
    1788 \caption{Atomic counter}
    1789 \label{f:AtomicCounter}
    1790 \end{figure}
    1791 
    1792 Like Java, \CFA monitors have \newterm{multi-acquire} semantics so the thread in the monitor may acquire it multiple times without deadlock, allowing recursion and calling other interface functions.
    1793 % \begin{cfa}
    1794 % monitor M { ... } m;
    1795 % void foo( M & mutex m ) { ... } $\C{// acquire mutual exclusion}$
    1796 % void bar( M & mutex m ) { $\C{// acquire mutual exclusion}$
    1797 %       ... `bar( m );` ... `foo( m );` ... $\C{// reacquire mutual exclusion}$
    1798 % }
    1799 % \end{cfa}
    1800 \CFA monitors also ensure the monitor lock is released regardless of how an acquiring function ends, normal or exceptional, and returning a shared variable is safe via copying before the lock is released.
    1801 Similar safety is offered by \emph{explicit} opt-in disciplines like \CC RAII versus the monitor \emph{implicit} language-enforced safety guarantee ensuring no programmer usage errors.
    1802 However, RAII mechanisms cannot handle complex synchronization within a monitor, where the monitor lock may not be released on function exit because it is passed to an unblocking thread;
     1599Aint x = { 0 }, y = { 0 }, z = { 5 }; $\C{// no mutex required}$
     1600++x; ++y; ++z; $\C{// safe increment by multiple threads}$
     1601x = 2; y = i; z = k; $\C{// conversions}$
     1602i = x; j = y; k = z;
     1603\end{cfa}
     1604
     1605\CFA monitors have \newterm{multi-acquire} semantics so the thread in the monitor may acquire it multiple times without deadlock, allowing recursion and calling other interface functions.
     1606\begin{cfa}
     1607monitor M { ... } m;
     1608void foo( M & mutex m ) { ... } $\C{// acquire mutual exclusion}$
     1609void bar( M & mutex m ) { $\C{// acquire mutual exclusion}$
     1610        ... `bar( m );` ... `foo( m );` ... $\C{// reacquire mutual exclusion}$
     1611}
     1612\end{cfa}
     1613\CFA monitors also ensure the monitor lock is released regardless of how an acquiring function ends (normal or exceptional), and returning a shared variable is safe via copying before the lock is released.
     1614Similar safety is offered by \emph{explicit} mechanisms like \CC RAII;
     1615monitor \emph{implicit} safety ensures no programmer usage errors.
     1616Furthermore, RAII mechanisms cannot handle complex synchronization within a monitor, where the monitor lock may not be released on function exit because it is passed to an unblocking thread;
    18031617RAII is purely a mutual-exclusion mechanism (see Section~\ref{s:Scheduling}).
    18041618
    1805 Both Java and \CFA use a keyword @mutex@/\lstinline[language=java]|synchronized| to designate functions that implicitly acquire/release the monitor lock on call/return providing mutual exclusion to the stared data.
    1806 Non-designated functions provide no mutual exclusion for read-only access or as an interface to a multi-step protocol requiring several steps of acquiring and releasing the monitor.
    1807 Monitor objects can be passed through multiple helper functions without acquiring mutual exclusion, until a designated function associated with the object is called.
    1808 \CFA designated functions are marked by an explicitly parameter-only pointer/reference qualifier @mutex@ (discussed further in Section\ref{s:MutexAcquisition}).
    1809 Whereas, Java designated members are marked with \lstinline[language=java]|synchronized| that applies to the implicit reference parameter @this@.
    1810 In the example, the increment and setter operations need mutual exclusion while the read-only getter operation can be nonmutex if reading the implementation is atomic.
    1811 
    1812 
    1813 \subsection{Monitor implementation}
     1619
     1620\subsection{Monitor Implementation}
    18141621
    18151622For the same design reasons, \CFA provides a custom @monitor@ type and a @trait@ to enforce and restrict the monitor-interface functions.
     
    18311638\end{tabular}
    18321639\end{cquote}
    1833 The @dtype@ property prevents \emph{implicit} copy operations and the @is_monitor@ trait provides no \emph{explicit} copy operations, so monitors must be passed by reference or pointer.
    1834 Similarly, the function definitions ensure there is a mechanism to read the monitor descriptor from its handle, and a special destructor to prevent deallocation if a thread is using the shared data.
     1640The @dtype@ property prevents \emph{implicit} copy operations and the @is_monitor@ trait provides no \emph{explicit} copy operations, so monitors must be passed by reference (pointer).
     1641% Copying a lock is insecure because it is possible to copy an open lock and then use the open copy when the original lock is closed to simultaneously access the shared data.
     1642% Copying a monitor is secure because both the lock and shared data are copies, but copying the shared data is meaningless because it no longer represents a unique entity.
     1643Similarly, the function definitions ensures there is a mechanism to get (read) the monitor descriptor from its handle, and a special destructor to prevent deallocation if a thread using the shared data.
    18351644The custom monitor type also inserts any locks needed to implement the mutual exclusion semantics.
    1836 \CFA relies heavily on traits as an abstraction mechanism, so the @mutex@ qualifier prevents coincidentally matching of a monitor trait with a type that is not a monitor, similar to coincidental inheritance where a shape and playing card can both be drawable.
    1837 
    1838 
    1839 \subsection{Mutex acquisition}
     1645
     1646
     1647\subsection{Mutex Acquisition}
    18401648\label{s:MutexAcquisition}
    18411649
    1842 For object-oriented programming languages, the mutex property applies to one object, the implicit pointer/reference to the monitor type.
    1843 Because \CFA uses a pointer qualifier, other possibilities exist, \eg:
    1844 \begin{cfa}
    1845 monitor M { ... };
     1650While the monitor lock provides mutual exclusion for shared data, there are implementation options for when and where the locking/unlocking occurs.
     1651(Much of this discussion also applies to basic locks.)
     1652For example, a monitor may be passed through multiple helper functions before it is necessary to acquire the monitor's mutual exclusion.
     1653
     1654The benefit of mandatory monitor qualifiers is self-documentation, but requiring both @mutex@ and \lstinline[morekeywords=nomutex]@nomutex@ for all monitor parameters is redundant.
     1655Instead, the semantics has one qualifier as the default and the other required.
     1656For example, make the safe @mutex@ qualifier the default because assuming \lstinline[morekeywords=nomutex]@nomutex@ may cause subtle errors.
     1657Alternatively, make the unsafe \lstinline[morekeywords=nomutex]@nomutex@ qualifier the default because it is the \emph{normal} parameter semantics while @mutex@ parameters are rare.
     1658Providing a default qualifier implies knowing whether a parameter is a monitor.
     1659Since \CFA relies heavily on traits as an abstraction mechanism, types can coincidentally match the monitor trait but not be a monitor, similar to inheritance where a shape and playing card can both be drawable.
     1660For this reason, \CFA requires programmers to identify the kind of parameter with the @mutex@ keyword and uses no keyword to mean \lstinline[morekeywords=nomutex]@nomutex@.
     1661
     1662The next semantic decision is establishing which parameter \emph{types} may be qualified with @mutex@.
     1663The following has monitor parameter types that are composed of multiple objects.
     1664\begin{cfa}
     1665monitor M { ... }
    18461666int f1( M & mutex m ); $\C{// single parameter object}$
    18471667int f2( M * mutex m ); $\C{// single or multiple parameter object}$
     
    18491669int f4( stack( M * ) & mutex m ); $\C{// multiple parameters object}$
    18501670\end{cfa}
    1851 Function @f1@ has a single object parameter, while functions @f2@ to @f4@ can be a single or multi-element parameter with statically unknown size.
    1852 Because of the statically unknown size, \CFA only supports a single reference @mutex@ parameter, @f1@.
    1853 
    1854 The \CFA @mutex@ qualifier does allow the ability to support multimonitor functions,\footnote{
     1671Function @f1@ has a single parameter object, while @f2@'s indirection could be a single or multi-element array, where static array size is often unknown in C.
     1672Function @f3@ has a multiple object matrix, and @f4@ a multiple object data structure.
     1673While shown shortly, multiple object acquisition is possible, but the number of objects must be statically known.
     1674Therefore, \CFA only acquires one monitor per parameter with at most one level of indirection, excluding pointers as it is impossible to statically determine the size.
     1675
     1676For object-oriented monitors, \eg Java, calling a mutex member \emph{implicitly} acquires mutual exclusion of the receiver object, @`rec`.foo(...)@.
     1677\CFA has no receiver, and hence, the explicit @mutex@ qualifier is used to specify which objects acquire mutual exclusion.
     1678A positive consequence of this design decision is the ability to support multi-monitor functions,\footnote{
    18551679While object-oriented monitors can be extended with a mutex qualifier for multiple-monitor members, no prior example of this feature could be found.}
    1856 where the number of acquisitions is statically known, called \newterm{bulk acquire}.
    1857 \CFA guarantees bulk acquisition order is consistent across calls to @mutex@ functions using the same monitors as arguments, so acquiring multiple monitors in a bulk acquire is safe from deadlock.
     1680called \newterm{bulk acquire}.
     1681\CFA guarantees acquisition order is consistent across calls to @mutex@ functions using the same monitors as arguments, so acquiring multiple monitors is safe from deadlock.
    18581682Figure~\ref{f:BankTransfer} shows a trivial solution to the bank transfer problem~\cite{BankTransfer}, where two resources must be locked simultaneously, using \CFA monitors with implicit locking and \CC with explicit locking.
    18591683A \CFA programmer only has to manage when to acquire mutual exclusion;
     
    18751699void transfer( BankAccount & `mutex` my,
    18761700        BankAccount & `mutex` your, int me2you ) {
    1877         // bulk acquire
     1701
    18781702        deposit( my, -me2you ); // debit
    18791703        deposit( your, me2you ); // credit
     
    19051729void transfer( BankAccount & my,
    19061730                        BankAccount & your, int me2you ) {
    1907         `scoped_lock lock( my.m, your.m );` // bulk acquire
     1731        `scoped_lock lock( my.m, your.m );`
    19081732        deposit( my, -me2you ); // debit
    19091733        deposit( your, me2you ); // credit
     
    19331757\end{figure}
    19341758
    1935 Users can still force the acquiring order by using or not using @mutex@.
     1759Users can still force the acquiring order by using @mutex@/\lstinline[morekeywords=nomutex]@nomutex@.
    19361760\begin{cfa}
    19371761void foo( M & mutex m1, M & mutex m2 ); $\C{// acquire m1 and m2}$
    1938 void bar( M & mutex m1, M & m2 ) { $\C{// only acquire m1}$
     1762void bar( M & mutex m1, M & /* nomutex */ m2 ) { $\C{// acquire m1}$
    19391763        ... foo( m1, m2 ); ... $\C{// acquire m2}$
    19401764}
    1941 void baz( M & m1, M & mutex m2 ) { $\C{// only acquire m2}$
     1765void baz( M & /* nomutex */ m1, M & mutex m2 ) { $\C{// acquire m2}$
    19421766        ... foo( m1, m2 ); ... $\C{// acquire m1}$
    19431767}
     
    19821806% There are many aspects of scheduling in a concurrency system, all related to resource utilization by waiting threads, \ie which thread gets the resource next.
    19831807% Different forms of scheduling include access to processors by threads (see Section~\ref{s:RuntimeStructureCluster}), another is access to a shared resource by a lock or monitor.
    1984 This section discusses scheduling for waiting threads eligible for monitor entry~\cite{Buhr95b}, \ie which user thread gets the shared resource next.
    1985 (See Section~\ref{s:RuntimeStructureCluster} for scheduling kernel threads on virtual processors.)
    1986 While monitor mutual-exclusion provides safe access to its shared data, the data may indicate a thread cannot proceed, \eg a bounded buffer may be full/\-empty so produce/consumer threads must block.
    1987 Leaving the monitor and retrying (busy waiting) is impractical for high-level programming.
    1988 
    1989 Monitors eliminate busy waiting by providing synchronization within the monitor critical-section to schedule threads needing access to the shared data, where threads block versus spin.
     1808This section discusses monitor scheduling for waiting threads eligible for entry, \ie which thread gets the shared resource next. (See Section~\ref{s:RuntimeStructureCluster} for scheduling threads on virtual processors.)
     1809While monitor mutual-exclusion provides safe access to shared data, the monitor data may indicate that a thread accessing it cannot proceed, \eg a bounded buffer may be full/empty so produce/consumer threads must block.
     1810Leaving the monitor and trying again (busy waiting) is impractical for high-level programming.
     1811Monitors eliminate busy waiting by providing synchronization to schedule threads needing access to the shared data, where threads block versus spinning.
    19901812Synchronization is generally achieved with internal~\cite{Hoare74} or external~\cite[\S~2.9.2]{uC++} scheduling.
    1991 \newterm{Internal} largely schedules threads located \emph{inside} the monitor and is accomplished using condition variables with signal and wait.
    1992 \newterm{External} largely schedules threads located \emph{outside} the monitor and is accomplished with the @waitfor@ statement.
    1993 Note, internal scheduling has a small amount of external scheduling and vice versa, so the naming denotes where the majority of the block threads reside (inside or outside) for scheduling.
    1994 For complex scheduling, the approaches can be combined, so there are threads waiting inside and outside.
    1995 
    1996 \CFA monitors do not allow calling threads to barge ahead of signaled threads via barging prevention, which simplifies synchronization among threads in the monitor and increases correctness.
    1997 A direct consequence of this semantics is that unblocked waiting threads are not required to recheck the waiting condition, \ie waits are not in a starvation-prone busy-loop as required by the signals-as-hints style with barging.
    1998 Preventing barging comes directly from Hoare's semantics in the seminal paper on monitors~\cite[p.~550]{Hoare74}.
     1813\newterm{Internal scheduling} is characterized by each thread entering the monitor and making an individual decision about proceeding or blocking, while \newterm{external scheduling} is characterized by an entering thread making a decision about proceeding for itself and on behalf of other threads attempting entry.
     1814Finally, \CFA monitors do not allow calling threads to barge ahead of signalled threads, which simplifies synchronization among threads in the monitor and increases correctness.
     1815If barging is allowed, synchronization between a signaller and signallee is difficult, often requiring additional flags and multiple unblock/block cycles.
     1816In fact, signals-as-hints is completely opposite from that proposed by Hoare in the seminal paper on monitors~\cite[p.~550]{Hoare74}.
    19991817% \begin{cquote}
    20001818% However, we decree that a signal operation be followed immediately by resumption of a waiting program, without possibility of an intervening procedure call from yet a third program.
    2001 % It is only in this way that a waiting program has an absolute guarantee that it can acquire the resource just released by the signaling program without any danger that a third program will interpose a monitor entry and seize the resource instead.~\cite[p.~550]{Hoare74}
     1819% It is only in this way that a waiting program has an absolute guarantee that it can acquire the resource just released by the signalling program without any danger that a third program will interpose a monitor entry and seize the resource instead.~\cite[p.~550]{Hoare74}
    20021820% \end{cquote}
    2003 Furthermore, \CFA concurrency has no spurious wakeup~\cite[\S~9]{Buhr05a}, which eliminates an implicit self barging.
    2004 
    2005 Monitor mutual-exclusion means signaling cannot have the signaller and signaled thread in the monitor simultaneously, so only the signaller or signallee can proceed and the other waits on an implicit urgent list~\cite[p.~551]{Hoare74}.
    2006 Figure~\ref{f:MonitorScheduling} shows internal and external scheduling for the bounded-buffer examples in Figure~\ref{f:GenericBoundedBuffer}.
    2007 For internal scheduling in Figure~\ref{f:BBInt}, the @signal@ moves the signallee, front thread of the specified condition queue, to the urgent list (see Figure~\ref{f:MonitorScheduling}) and the signaller continues (solid line).
    2008 Multiple signals move multiple signallees to urgent until the condition queue is empty.
    2009 When the signaller exits or waits, a thread is implicitly unblocked from urgent, if available, before unblocking a calling thread to prevent barging.
    2010 (Java conceptually moves the signaled thread to the calling queue, and hence, allows barging.)
    2011 Signal is used when the signaller is providing the cooperation needed by the signallee, \eg creating an empty slot in a buffer for a producer, and the signaller immediately exits the monitor to run concurrently consuming the buffer element, and passes control of the monitor to the signaled thread, which can immediately take advantage of the state change.
    2012 Specifically, the @wait@ function atomically blocks the calling thread and implicitly releases the monitor lock(s) for all monitors in the function's parameter list.
    2013 Signalling is unconditional because signaling an empty condition queue does nothing.
    2014 It is common to declare condition queues as monitor fields to prevent shared access, hence no locking is required for access as the queues are protected by the monitor lock.
    2015 In \CFA, a condition queue can be created and stored independently.
     1821Furthermore, \CFA concurrency has no spurious wakeup~\cite[\S~9]{Buhr05a}, which eliminates an implicit form of self barging.
     1822Hence, a \CFA @wait@ statement is not enclosed in a @while@ loop retesting a blocking predicate, which can cause thread starvation due to barging.
     1823
     1824Figure~\ref{f:MonitorScheduling} shows general internal/external scheduling (for the bounded-buffer example in Figure~\ref{f:InternalExternalScheduling}).
     1825External calling threads block on the calling queue, if the monitor is occupied, otherwise they enter in FIFO order.
     1826Internal threads block on condition queues via @wait@ and reenter from the condition in FIFO order.
     1827Alternatively, internal threads block on urgent from the @signal_block@ or @waitfor@, and reenter implicitly when the monitor becomes empty, \ie, the thread in the monitor exits or waits.
     1828
     1829There are three signalling mechanisms to unblock waiting threads to enter the monitor.
     1830Note, signalling cannot have the signaller and signalled thread in the monitor simultaneously because of the mutual exclusion, so either the signaller or signallee can proceed.
     1831For internal scheduling, threads are unblocked from condition queues using @signal@, where the signallee is moved to urgent and the signaller continues (solid line).
     1832Multiple signals move multiple signallees to urgent until the condition is empty.
     1833When the signaller exits or waits, a thread blocked on urgent is processed before calling threads to prevent barging.
     1834(Java conceptually moves the signalled thread to the calling queue, and hence, allows barging.)
     1835The alternative unblock is in the opposite order using @signal_block@, where the signaller is moved to urgent and the signallee continues (dashed line), and is implicitly unblocked from urgent when the signallee exits or waits.
     1836
     1837For external scheduling, the condition queues are not used;
     1838instead threads are unblocked directly from the calling queue using @waitfor@ based on function names requesting mutual exclusion.
     1839(The linear search through the calling queue to locate a particular call can be reduced to $O(1)$.)
     1840The @waitfor@ has the same semantics as @signal_block@, where the signalled thread executes before the signallee, which waits on urgent.
     1841Executing multiple @waitfor@s from different signalled functions causes the calling threads to move to urgent.
     1842External scheduling requires urgent to be a stack, because the signaller expects to execute immediately after the specified monitor call has exited or waited.
     1843Internal scheduling behaves the same for an urgent stack or queue, except for multiple signalling, where the threads unblock from urgent in reverse order from signalling.
     1844If the restart order is important, multiple signalling by a signal thread can be transformed into daisy-chain signalling among threads, where each thread signals the next thread.
     1845We tried both a stack for @waitfor@ and queue for signalling, but that resulted in complex semantics about which thread enters next.
     1846Hence, \CFA uses a single urgent stack to correctly handle @waitfor@ and adequately support both forms of signalling.
    20161847
    20171848\begin{figure}
     
    20311862\end{figure}
    20321863
     1864Figure~\ref{f:BBInt} shows a \CFA generic bounded-buffer with internal scheduling, where producers/consumers enter the monitor, detect the buffer is full/empty, and block on an appropriate condition variable, @full@/@empty@.
     1865The @wait@ function atomically blocks the calling thread and implicitly releases the monitor lock(s) for all monitors in the function's parameter list.
     1866The appropriate condition variable is signalled to unblock an opposite kind of thread after an element is inserted/removed from the buffer.
     1867Signalling is unconditional, because signalling an empty condition variable does nothing.
     1868It is common to declare condition variables as monitor fields to prevent shared access, hence no locking is required for access as the conditions are protected by the monitor lock.
     1869In \CFA, a condition variable can be created/stored independently.
     1870% To still prevent expensive locking on access, a condition variable is tied to a \emph{group} of monitors on first use, called \newterm{branding}, resulting in a low-cost boolean test to detect sharing from other monitors.
     1871
     1872% Signalling semantics cannot have the signaller and signalled thread in the monitor simultaneously, which means:
     1873% \begin{enumerate}
     1874% \item
     1875% The signalling thread returns immediately and the signalled thread continues.
     1876% \item
     1877% The signalling thread continues and the signalled thread is marked for urgent unblocking at the next scheduling point (exit/wait).
     1878% \item
     1879% The signalling thread blocks but is marked for urgent unblocking at the next scheduling point and the signalled thread continues.
     1880% \end{enumerate}
     1881% The first approach is too restrictive, as it precludes solving a reasonable class of problems, \eg dating service (see Figure~\ref{f:DatingService}).
     1882% \CFA supports the next two semantics as both are useful.
     1883
    20331884\begin{figure}
    20341885\centering
     
    20421893                T elements[10];
    20431894        };
    2044         void ?{}( Buffer(T) & buf ) with(buf) {
     1895        void ?{}( Buffer(T) & buffer ) with(buffer) {
    20451896                front = back = count = 0;
    20461897        }
    2047 
    2048         void insert(Buffer(T) & mutex buf, T elm) with(buf){
    2049                 if ( count == 10 ) `wait( empty )`; // full ?
    2050                 // insert elm into buf
     1898        void insert( Buffer(T) & mutex buffer, T elem )
     1899                                with(buffer) {
     1900                if ( count == 10 ) `wait( empty )`;
     1901                // insert elem into buffer
    20511902                `signal( full )`;
    20521903        }
    2053         T remove( Buffer(T) & mutex buf ) with(buf) {
    2054                 if ( count == 0 ) `wait( full )`; // empty ?
    2055                 // remove elm from buf
     1904        T remove( Buffer(T) & mutex buffer ) with(buffer) {
     1905                if ( count == 0 ) `wait( full )`;
     1906                // remove elem from buffer
    20561907                `signal( empty )`;
    2057                 return elm;
     1908                return elem;
    20581909        }
    20591910}
    20601911\end{cfa}
    20611912\end{lrbox}
     1913
     1914% \newbox\myboxB
     1915% \begin{lrbox}{\myboxB}
     1916% \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     1917% forall( otype T ) { // distribute forall
     1918%       monitor Buffer {
     1919%
     1920%               int front, back, count;
     1921%               T elements[10];
     1922%       };
     1923%       void ?{}( Buffer(T) & buffer ) with(buffer) {
     1924%               [front, back, count] = 0;
     1925%       }
     1926%       T remove( Buffer(T) & mutex buffer ); // forward
     1927%       void insert( Buffer(T) & mutex buffer, T elem )
     1928%                               with(buffer) {
     1929%               if ( count == 10 ) `waitfor( remove, buffer )`;
     1930%               // insert elem into buffer
     1931%
     1932%       }
     1933%       T remove( Buffer(T) & mutex buffer ) with(buffer) {
     1934%               if ( count == 0 ) `waitfor( insert, buffer )`;
     1935%               // remove elem from buffer
     1936%
     1937%               return elem;
     1938%       }
     1939% }
     1940% \end{cfa}
     1941% \end{lrbox}
    20621942
    20631943\newbox\myboxB
    20641944\begin{lrbox}{\myboxB}
    20651945\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    2066 forall( otype T ) { // distribute forall
    2067         monitor Buffer {
    2068 
    2069                 int front, back, count;
    2070                 T elements[10];
    2071         };
    2072         void ?{}( Buffer(T) & buf ) with(buf) {
    2073                 front = back = count = 0;
    2074         }
    2075         T remove( Buffer(T) & mutex buf ); // forward
    2076         void insert(Buffer(T) & mutex buf, T elm) with(buf){
    2077                 if ( count == 10 ) `waitfor( remove : buf )`;
    2078                 // insert elm into buf
    2079 
    2080         }
    2081         T remove( Buffer(T) & mutex buf ) with(buf) {
    2082                 if ( count == 0 ) `waitfor( insert : buf )`;
    2083                 // remove elm from buf
    2084 
    2085                 return elm;
    2086         }
    2087 }
    2088 \end{cfa}
    2089 \end{lrbox}
    2090 
    2091 \subfloat[Internal scheduling]{\label{f:BBInt}\usebox\myboxA}
    2092 \hspace{1pt}
    2093 \vrule
    2094 \hspace{3pt}
    2095 \subfloat[External scheduling]{\label{f:BBExt}\usebox\myboxB}
    2096 
    2097 \caption{Generic bounded buffer}
    2098 \label{f:GenericBoundedBuffer}
    2099 \end{figure}
    2100 
    2101 The @signal_block@ provides the opposite unblocking order, where the signaller is moved to urgent and the signallee continues and a thread is implicitly unblocked from urgent when the signallee exits or waits (dashed line)~\cite[p.~551]{Hoare74}.
    2102 Signal block is used when the signallee is providing the cooperation needed by the signaller, \eg if the buffer is removed and a producer hands off an item to a consumer as in Figure~\ref{f:DatingSignalBlock}, so the signaller must wait until the signallee unblocks, provides the cooperation, exits the monitor to run concurrently, and passes control of the monitor to the signaller, which can immediately take advantage of the state change.
    2103 Using @signal@ or @signal_block@ can be a dynamic decision based on whether the thread providing the cooperation arrives before or after the thread needing the cooperation.
    2104 
    2105 For external scheduling in Figure~\ref{f:BBExt}, the internal scheduling is replaced, eliminating condition queues and @signal@/@wait@ (cases where it cannot are discussed shortly), and has existed in the programming language Ada for almost 40 years with variants in other languages~\cite{SR,ConcurrentC++,uC++}.
    2106 While prior languages use external scheduling solely for thread interaction, \CFA generalizes it to both monitors and threads.
    2107 External scheduling allows waiting for events from other threads while restricting unrelated events, that would otherwise have to wait on condition queues in the monitor.
    2108 Scheduling is controlled by the @waitfor@ statement, which atomically blocks the calling thread, releases the monitor lock, and restricts the function calls that can next acquire mutual exclusion.
    2109 Specifically, a thread calling the monitor is unblocked directly from the calling queue based on function names that can fulfill the cooperation required by the signaller.
    2110 (The linear search through the calling queue to locate a particular call can be reduced to $O(1)$.)
    2111 Hence, the @waitfor@ has the same semantics as @signal_block@, where the signallee thread from the calling queue executes before the signaller, which waits on urgent.
    2112 Now when a producer/consumer detects a full/empty buffer, the necessary cooperation for continuation is specified by indicating the next function call that can occur.
    2113 For example, a producer detecting a full buffer must have cooperation from a consumer to remove an item so function @remove@ is accepted, which prevents producers from entering the monitor, and after a consumer calls @remove@, the producer waiting on urgent is \emph{implicitly} unblocked because it can now continue its insert operation.
    2114 Hence, this mechanism is done in terms of control flow, next call, versus in terms of data, channels, as in Go and Rust @select@.
    2115 While both mechanisms have strengths and weaknesses, \CFA uses the control-flow mechanism to be consistent with other language features.
    2116 
    2117 Figure~\ref{f:ReadersWriterLock} shows internal and external scheduling for a readers/writer lock with no barging and threads are serviced in FIFO order to eliminate staleness and freshness among the reader/writer threads.
    2118 For internal scheduling in Figure~\ref{f:RWInt}, the readers and writers wait on the same condition queue in FIFO order, making it impossible to tell if a waiting thread is a reader or writer.
    2119 To clawback the kind of thread, a \CFA condition can store user data in the node for a blocking thread at the @wait@, \ie whether the thread is a @READER@ or @WRITER@.
    2120 An unblocked reader thread checks if the thread at the front of the queue is a reader and unblock it, \ie the readers daisy-chain signal the next group of readers demarcated by the next writer or end of the queue.
    2121 For external scheduling in Figure~\ref{f:RWExt}, a waiting reader checks if a writer is using the resource, and if so, restricts further calls until the writer exits by calling @EndWrite@.
    2122 The writer does a similar action for each reader or writer using the resource.
    2123 Note, no new calls to @StartRead@/@StartWrite@ may occur when waiting for the call to @EndRead@/@EndWrite@.
    2124 
    2125 \begin{figure}
    2126 \centering
    2127 \newbox\myboxA
    2128 \begin{lrbox}{\myboxA}
    2129 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    2130 enum RW { READER, WRITER };
    21311946monitor ReadersWriter {
    2132         int rcnt, wcnt; // readers/writer using resource
    2133         `condition RWers;`
     1947        int rcnt, wcnt; // readers/writer using resource
    21341948};
    21351949void ?{}( ReadersWriter & rw ) with(rw) {
     
    21381952void EndRead( ReadersWriter & mutex rw ) with(rw) {
    21391953        rcnt -= 1;
    2140         if ( rcnt == 0 ) `signal( RWers )`;
    21411954}
    21421955void EndWrite( ReadersWriter & mutex rw ) with(rw) {
    21431956        wcnt = 0;
    2144         `signal( RWers );`
    21451957}
    21461958void StartRead( ReadersWriter & mutex rw ) with(rw) {
    2147         if ( wcnt !=0 || ! empty( RWers ) )
    2148                 `wait( RWers, READER )`;
     1959        if ( wcnt > 0 ) `waitfor( EndWrite, rw );`
    21491960        rcnt += 1;
    2150         if ( ! empty(RWers) && `front(RWers) == READER` )
    2151                 `signal( RWers )`;  // daisy-chain signaling
    21521961}
    21531962void StartWrite( ReadersWriter & mutex rw ) with(rw) {
    2154         if ( wcnt != 0 || rcnt != 0 ) `wait( RWers, WRITER )`;
    2155 
     1963        if ( wcnt > 0 ) `waitfor( EndWrite, rw );`
     1964        else while ( rcnt > 0 ) `waitfor( EndRead, rw );`
    21561965        wcnt = 1;
    21571966}
     1967
    21581968\end{cfa}
    21591969\end{lrbox}
    21601970
    2161 \newbox\myboxB
    2162 \begin{lrbox}{\myboxB}
    2163 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    2164 
    2165 monitor ReadersWriter {
    2166         int rcnt, wcnt; // readers/writer using resource
    2167 
    2168 };
    2169 void ?{}( ReadersWriter & rw ) with(rw) {
    2170         rcnt = wcnt = 0;
    2171 }
    2172 void EndRead( ReadersWriter & mutex rw ) with(rw) {
    2173         rcnt -= 1;
    2174 
    2175 }
    2176 void EndWrite( ReadersWriter & mutex rw ) with(rw) {
    2177         wcnt = 0;
    2178 
    2179 }
    2180 void StartRead( ReadersWriter & mutex rw ) with(rw) {
    2181         if ( wcnt > 0 ) `waitfor( EndWrite : rw );`
    2182 
    2183         rcnt += 1;
    2184 
    2185 
    2186 }
    2187 void StartWrite( ReadersWriter & mutex rw ) with(rw) {
    2188         if ( wcnt > 0 ) `waitfor( EndWrite : rw );`
    2189         else while ( rcnt > 0 ) `waitfor( EndRead : rw );`
    2190         wcnt = 1;
    2191 }
    2192 \end{cfa}
    2193 \end{lrbox}
    2194 
    2195 \subfloat[Internal scheduling]{\label{f:RWInt}\usebox\myboxA}
    2196 \hspace{1pt}
     1971\subfloat[Generic bounded buffer, internal scheduling]{\label{f:BBInt}\usebox\myboxA}
     1972\hspace{3pt}
    21971973\vrule
    21981974\hspace{3pt}
    2199 \subfloat[External scheduling]{\label{f:RWExt}\usebox\myboxB}
    2200 
    2201 \caption{Readers / writer lock}
    2202 \label{f:ReadersWriterLock}
     1975\subfloat[Readers / writer lock, external scheduling]{\label{f:RWExt}\usebox\myboxB}
     1976
     1977\caption{Internal / external scheduling}
     1978\label{f:InternalExternalScheduling}
    22031979\end{figure}
    22041980
    2205 Finally, external scheduling requires urgent to be a stack, because the signaller expects to execute immediately after the specified monitor call has exited or waited.
    2206 Internal scheduling performing multiple signaling results in unblocking from urgent in the reverse order from signaling.
    2207 It is rare for the unblocking order to be important as an unblocked thread can be time-sliced immediately after leaving the monitor.
    2208 If the unblocking order is important, multiple signaling can be restructured into daisy-chain signaling, where each thread signals the next thread.
    2209 Hence, \CFA uses a single urgent stack to correctly handle @waitfor@ and adequately support both forms of signaling.
    2210 (Advanced @waitfor@ features are discussed in Section~\ref{s:ExtendedWaitfor}.)
     1981Figure~\ref{f:BBInt} can be transformed into external scheduling by removing the condition variables and signals/waits, and adding the following lines at the locations of the current @wait@s in @insert@/@remove@, respectively.
     1982\begin{cfa}[aboveskip=2pt,belowskip=1pt]
     1983if ( count == 10 ) `waitfor( remove, buffer )`;       |      if ( count == 0 ) `waitfor( insert, buffer )`;
     1984\end{cfa}
     1985Here, the producers/consumers detects a full/\-empty buffer and prevents more producers/consumers from entering the monitor until there is a free/empty slot in the buffer.
     1986External scheduling is controlled by the @waitfor@ statement, which atomically blocks the calling thread, releases the monitor lock, and restricts the function calls that can next acquire mutual exclusion.
     1987If the buffer is full, only calls to @remove@ can acquire the buffer, and if the buffer is empty, only calls to @insert@ can acquire the buffer.
     1988Threads calling excluded functions block outside of (external to) the monitor on the calling queue, versus blocking on condition queues inside of (internal to) the monitor.
     1989Figure~\ref{f:RWExt} shows a readers/writer lock written using external scheduling, where a waiting reader detects a writer using the resource and restricts further calls until the writer exits by calling @EndWrite@.
     1990The writer does a similar action for each reader or writer using the resource.
     1991Note, no new calls to @StarRead@/@StartWrite@ may occur when waiting for the call to @EndRead@/@EndWrite@.
     1992External scheduling allows waiting for events from other threads while restricting unrelated events, that would otherwise have to wait on conditions in the monitor.
     1993The mechnaism can be done in terms of control flow, \eg Ada @accept@ or \uC @_Accept@, or in terms of data, \eg Go @select@ on channels.
     1994While both mechanisms have strengths and weaknesses, this project uses the control-flow mechanism to be consistent with other language features.
     1995% Two challenges specific to \CFA for external scheduling are loose object-definitions (see Section~\ref{s:LooseObjectDefinitions}) and multiple-monitor functions (see Section~\ref{s:Multi-MonitorScheduling}).
     1996
     1997Figure~\ref{f:DatingService} shows a dating service demonstrating non-blocking and blocking signalling.
     1998The dating service matches girl and boy threads with matching compatibility codes so they can exchange phone numbers.
     1999A thread blocks until an appropriate partner arrives.
     2000The complexity is exchanging phone numbers in the monitor because of the mutual-exclusion property.
     2001For signal scheduling, the @exchange@ condition is necessary to block the thread finding the match, while the matcher unblocks to take the opposite number, post its phone number, and unblock the partner.
     2002For signal-block scheduling, the implicit urgent-queue replaces the explict @exchange@-condition and @signal_block@ puts the finding thread on the urgent condition and unblocks the matcher.
     2003The dating service is an example of a monitor that cannot be written using external scheduling because it requires knowledge of calling parameters to make scheduling decisions, and parameters of waiting threads are unavailable;
     2004as well, an arriving thread may not find a partner and must wait, which requires a condition variable, and condition variables imply internal scheduling.
     2005Furthermore, barging corrupts the dating service during an exchange because a barger may also match and change the phone numbers, invalidating the previous exchange phone number.
     2006Putting loops around the @wait@s does not correct the problem;
     2007the simple solution must be restructured to account for barging.
    22112008
    22122009\begin{figure}
     
    22222019};
    22232020int girl( DS & mutex ds, int phNo, int ccode ) {
    2224         if ( empty( Boys[ccode] ) ) {
     2021        if ( is_empty( Boys[ccode] ) ) {
    22252022                wait( Girls[ccode] );
    22262023                GirlPhNo = phNo;
     
    22492046};
    22502047int girl( DS & mutex ds, int phNo, int ccode ) {
    2251         if ( empty( Boys[ccode] ) ) { // no compatible
     2048        if ( is_empty( Boys[ccode] ) ) { // no compatible
    22522049                wait( Girls[ccode] ); // wait for boy
    22532050                GirlPhNo = phNo; // make phone number available
     
    22692066\qquad
    22702067\subfloat[\lstinline@signal_block@]{\label{f:DatingSignalBlock}\usebox\myboxB}
    2271 \caption{Dating service Monitor}
    2272 \label{f:DatingServiceMonitor}
     2068\caption{Dating service}
     2069\label{f:DatingService}
    22732070\end{figure}
    22742071
    2275 Figure~\ref{f:DatingServiceMonitor} shows a dating service demonstrating nonblocking and blocking signaling.
    2276 The dating service matches girl and boy threads with matching compatibility codes so they can exchange phone numbers.
    2277 A thread blocks until an appropriate partner arrives.
    2278 The complexity is exchanging phone numbers in the monitor because of the mutual-exclusion property.
    2279 For signal scheduling, the @exchange@ condition is necessary to block the thread finding the match, while the matcher unblocks to take the opposite number, post its phone number, and unblock the partner.
    2280 For signal-block scheduling, the implicit urgent-queue replaces the explicit @exchange@-condition and @signal_block@ puts the finding thread on the urgent stack and unblocks the matcher.
    2281 Note, barging corrupts the dating service during an exchange because a barger may also match and change the phone numbers, invalidating the previous exchange phone number.
    2282 This situation shows rechecking the waiting condition and waiting again (signals-as-hints) fails, requiring significant restructured to account for barging.
    2283 
    2284 Given external and internal scheduling, what guidelines can a programmer use to select between them?
    2285 In general, external scheduling is easier to understand and code because only the next logical action (mutex function(s)) is stated, and the monitor implicitly handles all the details.
    2286 Therefore, there are no condition variables, and hence, no wait and signal, which reduces coding complexity and synchronization errors.
    2287 If external scheduling is simpler than internal, why not use it all the time?
    2288 Unfortunately, external scheduling cannot be used if: scheduling depends on parameter value(s) or scheduling must block across an unknown series of calls on a condition variable, \ie internal scheduling.
    2289 For example, the dating service cannot be written using external scheduling.
    2290 First, scheduling requires knowledge of calling parameters to make matching decisions and parameters of calling threads are unavailable within the monitor.
    2291 Specifically, a thread within the monitor cannot examine the @ccode@ of threads waiting on the calling queue to determine if there is a matching partner.
    2292 (Similarly, if the bounded buffer or readers/writer are restructured with a single interface function with a parameter denoting producer/consumer or reader/write, they cannot be solved with external scheduling.)
    2293 Second, a scheduling decision may be delayed across an unknown number of calls when there is no immediate match so the thread in the monitor must block on a condition.
    2294 Specifically, if a thread determines there is no opposite calling thread with the same @ccode@, it must wait an unknown period until a matching thread arrives.
    2295 For complex synchronization, both external and internal scheduling can be used to take advantage of best of properties of each.
    2296 
    2297 Finally, both internal and external scheduling extend to multiple monitors in a natural way.
     2072In summation, for internal scheduling, non-blocking signalling (as in the producer/consumer example) is used when the signaller is providing the cooperation for a waiting thread;
     2073the signaller enters the monitor and changes state, detects a waiting threads that can use the state, performs a non-blocking signal on the condition queue for the waiting thread, and exits the monitor to run concurrently.
     2074The waiter unblocks next from the urgent queue, uses/takes the state, and exits the monitor.
     2075Blocking signal is the reverse, where the waiter is providing the cooperation for the signalling thread;
     2076the signaller enters the monitor, detects a waiting thread providing the necessary state, performs a blocking signal to place it on the urgent queue and unblock the waiter.
     2077The waiter changes state and exits the monitor, and the signaller unblocks next from the urgent queue to use/take the state.
     2078
     2079Both internal and external scheduling extend to multiple monitors in a natural way.
    22982080\begin{cquote}
    2299 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}}
     2081\begin{tabular}{@{}l@{\hspace{3\parindentlnth}}l@{}}
    23002082\begin{cfa}
    23012083monitor M { `condition e`; ... };
     
    23082090&
    23092091\begin{cfa}
    2310 void rtn$\(_1\)$( M & mutex m1, M & mutex m2 ); // overload rtn
     2092void rtn$\(_1\)$( M & mutex m1, M & mutex m2 );
    23112093void rtn$\(_2\)$( M & mutex m1 );
    23122094void bar( M & mutex m1, M & mutex m2 ) {
    2313         ... waitfor( `rtn`${\color{red}\(_1\)}$ ); ...       // $\LstCommentStyle{waitfor( rtn\(_1\) : m1, m2 )}$
    2314         ... waitfor( `rtn${\color{red}\(_2\)}$ : m1` ); ...
     2095        ... waitfor( `rtn` ); ...       // $\LstCommentStyle{waitfor( rtn\(_1\), m1, m2 )}$
     2096        ... waitfor( `rtn, m1` ); ... // $\LstCommentStyle{waitfor( rtn\(_2\), m1 )}$
    23152097}
    23162098\end{cfa}
     
    23182100\end{cquote}
    23192101For @wait( e )@, the default semantics is to atomically block the signaller and release all acquired mutex parameters, \ie @wait( e, m1, m2 )@.
    2320 To override the implicit multimonitor wait, specific mutex parameter(s) can be specified, \eg @wait( e, m1 )@.
    2321 Wait cannot statically verify the released monitors are the acquired mutex-parameters without disallowing separately compiled helper functions calling @wait@.
    2322 While \CC supports bulk locking, @wait@ only accepts a single lock for a condition queue, so bulk locking with condition queues is asymmetric.
     2102To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @wait( e, m1 )@.
     2103Wait cannot statically verifies the released monitors are the acquired mutex-parameters without disallowing separately compiled helper functions calling @wait@.
     2104While \CC supports bulk locking, @wait@ only accepts a single lock for a condition variable, so bulk locking with condition variables is asymmetric.
    23232105Finally, a signaller,
    23242106\begin{cfa}
     
    23272109}
    23282110\end{cfa}
    2329 must have acquired at least the same locks as the waiting thread signaled from a condition queue to allow the locks to be passed, and hence, prevent barging.
    2330 
    2331 Similarly, for @waitfor( rtn )@, the default semantics is to atomically block the acceptor and release all acquired mutex parameters, \ie @waitfor( rtn : m1, m2 )@.
    2332 To override the implicit multimonitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn : m1 )@.
    2333 @waitfor@ does statically verify the monitor types passed are the same as the acquired mutex-parameters of the given function or function pointer, hence the prototype must be accessible.
     2111must have acquired at least the same locks as the waiting thread signalled from a condition queue to allow the locks to be passed, and hence, prevent barging.
     2112
     2113Similarly, for @waitfor( rtn )@, the default semantics is to atomically block the acceptor and release all acquired mutex parameters, \ie @waitfor( rtn, m1, m2 )@.
     2114To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn, m1 )@.
     2115@waitfor@ does statically verify the monitor types passed are the same as the acquired mutex-parameters of the given function or function pointer, hence the function (pointer) prototype must be accessible.
    23342116% When an overloaded function appears in an @waitfor@ statement, calls to any function with that name are accepted.
    2335 % The rationale is that functions with the same name should perform a similar actions, and therefore, all should be eligible to accept a call.
     2117% The rationale is that members with the same name should perform a similar function, and therefore, all should be eligible to accept a call.
    23362118Overloaded functions can be disambiguated using a cast
    23372119\begin{cfa}
    23382120void rtn( M & mutex m );
    23392121`int` rtn( M & mutex m );
    2340 waitfor( (`int` (*)( M & mutex ))rtn : m );
    2341 \end{cfa}
    2342 
    2343 The ability to release a subset of acquired monitors can result in a \newterm{nested monitor}~\cite{Lister77} deadlock (see Section~\ref{s:MutexAcquisition}).
     2122waitfor( (`int` (*)( M & mutex ))rtn, m );
     2123\end{cfa}
     2124
     2125The ability to release a subset of acquired monitors can result in a \newterm{nested monitor}~\cite{Lister77} deadlock.
    23442126\begin{cfa}
    23452127void foo( M & mutex m1, M & mutex m2 ) {
    2346         ... wait( `e, m1` ); ...                                $\C{// release m1, keeping m2 acquired}$
    2347 void bar( M & mutex m1, M & mutex m2 ) {        $\C{// must acquire m1 and m2}$
     2128        ... wait( `e, m1` ); ...                                $\C{// release m1, keeping m2 acquired )}$
     2129void bar( M & mutex m1, M & mutex m2 ) {        $\C{// must acquire m1 and m2 )}$
    23482130        ... signal( `e` ); ...
    23492131\end{cfa}
    2350 The @wait@ only releases @m1@ so the signaling thread cannot acquire @m1@ and @m2@ to enter @bar@ and @signal@ the condition.
    2351 While deadlock can occur with multiple/nesting acquisition, this is a consequence of locks, and by extension monitor locking is not perfectly composable.
     2132The @wait@ only releases @m1@ so the signalling thread cannot acquire @m1@ and @m2@ to enter @bar@ and @signal@ the condition.
     2133While deadlock can occur with multiple/nesting acquisition, this is a consequence of locks, and by extension monitors, not being perfectly composable.
     2134
    23522135
    23532136
    23542137\subsection{\texorpdfstring{Extended \protect\lstinline@waitfor@}{Extended waitfor}}
    2355 \label{s:ExtendedWaitfor}
    23562138
    23572139Figure~\ref{f:ExtendedWaitfor} shows the extended form of the @waitfor@ statement to conditionally accept one of a group of mutex functions, with an optional statement to be performed \emph{after} the mutex function finishes.
    2358 For a @waitfor@ clause to be executed, its @when@ must be true and an outstanding call to its corresponding function(s) must exist.
     2140For a @waitfor@ clause to be executed, its @when@ must be true and an outstanding call to its corresponding member(s) must exist.
    23592141The \emph{conditional-expression} of a @when@ may call a function, but the function must not block or context switch.
    2360 If there are multiple acceptable mutex calls, selection is prioritized top-to-bottom among the @waitfor@ clauses, whereas some programming languages with similar mechanisms accept nondeterministically for this case, \eg Go \lstinline[morekeywords=select]@select@.
    2361 If some accept guards are true and there are no outstanding calls to these functions, the acceptor is blocked until a call to one of these functions is made.
     2142If there are multiple acceptable mutex calls, selection occurs top-to-bottom (prioritized) among the @waitfor@ clauses, whereas some programming languages with similar mechanisms accept nondeterministically for this case, \eg Go \lstinline[morekeywords=select]@select@.
     2143If some accept guards are true and there are no outstanding calls to these members, the acceptor is blocked until a call to one of these members is made.
    23622144If there is a @timeout@ clause, it provides an upper bound on waiting.
    23632145If all the accept guards are false, the statement does nothing, unless there is a terminating @else@ clause with a true guard, which is executed instead.
    23642146Hence, the terminating @else@ clause allows a conditional attempt to accept a call without blocking.
    23652147If both @timeout@ and @else@ clause are present, the @else@ must be conditional, or the @timeout@ is never triggered.
    2366 % There is also a traditional future wait queue (not shown) (\eg Microsoft @WaitForMultipleObjects@), to wait for a specified number of future elements in the queue.
    2367 Finally, there is a shorthand for specifying multiple functions using the same set of monitors: @waitfor( f, g, h : m1, m2, m3 )@.
     2148There is also a traditional future wait queue (not shown) (\eg Microsoft (@WaitForMultipleObjects@)), to wait for a specified number of future elements in the queue.
    23682149
    23692150\begin{figure}
     
    23712152\begin{cfa}
    23722153`when` ( $\emph{conditional-expression}$ )      $\C{// optional guard}$
    2373         waitfor( $\emph{mutex-function-name}$ ) $\emph{statement}$ $\C{// action after call}$
     2154        waitfor( $\emph{mutex-member-name}$ ) $\emph{statement}$ $\C{// action after call}$
    23742155`or` `when` ( $\emph{conditional-expression}$ ) $\C{// any number of functions}$
    2375         waitfor( $\emph{mutex-function-name}$ ) $\emph{statement}$
     2156        waitfor( $\emph{mutex-member-name}$ ) $\emph{statement}$
    23762157`or`    ...
    23772158`when` ( $\emph{conditional-expression}$ ) $\C{// optional guard}$
     
    23912172The left example only accepts @mem1@ if @C1@ is true or only @mem2@ if @C2@ is true.
    23922173The right example accepts either @mem1@ or @mem2@ if @C1@ and @C2@ are true.
    2393 Hence, the @waitfor@ has parallel semantics, accepting any true @when@ clause.
    2394 
    2395 An interesting use of @waitfor@ is accepting the @mutex@ destructor to know when an object is deallocated, \eg assume the bounded buffer is restructured from a monitor to a thread with the following @main@.
     2174
     2175An interesting use of @waitfor@ is accepting the @mutex@ destructor to know when an object is deallocated, \eg assume the bounded buffer is restructred from a monitor to a thread with the following @main@.
    23962176\begin{cfa}
    23972177void main( Buffer(T) & buffer ) with(buffer) {
    23982178        for () {
    2399                 `waitfor( ^?{} : buffer )` break;
    2400                 or when ( count != 20 ) waitfor( insert : buffer ) { ... }
    2401                 or when ( count != 0 ) waitfor( remove : buffer ) { ... }
     2179                `waitfor( ^?{}, buffer )` break;
     2180                or when ( count != 20 ) waitfor( insert, buffer ) { ... }
     2181                or when ( count != 0 ) waitfor( remove, buffer ) { ... }
    24022182        }
    24032183        // clean up
     
    24122192
    24132193
    2414 \subsection{Bulk barging prevention}
    2415 
    2416 Figure~\ref{f:BulkBargingPrevention} shows \CFA code where bulk acquire adds complexity to the internal-signaling semantics.
     2194\subsection{Bulk Barging Prevention}
     2195
     2196Figure~\ref{f:BulkBargingPrevention} shows \CFA code where bulk acquire adds complexity to the internal-signalling semantics.
    24172197The complexity begins at the end of the inner @mutex@ statement, where the semantics of internal scheduling need to be extended for multiple monitors.
    24182198The problem is that bulk acquire is used in the inner @mutex@ statement where one of the monitors is already acquired.
    2419 When the signaling thread reaches the end of the inner @mutex@ statement, it should transfer ownership of @m1@ and @m2@ to the waiting threads to prevent barging into the outer @mutex@ statement by another thread.
    2420 However, both the signaling and waiting threads W1 and W2 need some subset of monitors @m1@ and @m2@.
     2199When the signalling thread reaches the end of the inner @mutex@ statement, it should transfer ownership of @m1@ and @m2@ to the waiting threads to prevent barging into the outer @mutex@ statement by another thread.
     2200However, both the signalling and waiting threads W1 and W2 need some subset of monitors @m1@ and @m2@.
    24212201\begin{cquote}
    24222202condition c: (order 1) W2(@m2@), W1(@m1@,@m2@)\ \ \ or\ \ \ (order 2) W1(@m1@,@m2@), W2(@m2@) \\
     
    24852265\end{figure}
    24862266
    2487 One scheduling solution is for the signaller S to keep ownership of all locks until the last lock is ready to be transferred, because this semantics fits most closely to the behavior of single-monitor scheduling.
    2488 However, this solution is inefficient if W2 waited first and immediate passed @m2@ when released, while S retains @m1@ until completion of the outer mutex statement.
     2267One scheduling solution is for the signaller S to keep ownership of all locks until the last lock is ready to be transferred, because this semantics fits most closely to the behaviour of single-monitor scheduling.
     2268However, this solution is inefficient if W2 waited first and can be immediate passed @m2@ when released, while S retains @m1@ until completion of the outer mutex statement.
    24892269If W1 waited first, the signaller must retain @m1@ amd @m2@ until completion of the outer mutex statement and then pass both to W1.
    24902270% Furthermore, there is an execution sequence where the signaller always finds waiter W2, and hence, waiter W1 starves.
    2491 To support these efficient semantics and prevent barging, the implementation maintains a list of monitors acquired for each blocked thread.
    2492 When a signaller exits or waits in a mutex function or statement, the front waiter on urgent is unblocked if all its monitors are released.
    2493 Implementing a fast subset check for the necessarily released monitors is important and discussed in the following sections.
     2271To support this efficient semantics (and prevent barging), the implementation maintains a list of monitors acquired for each blocked thread.
     2272When a signaller exits or waits in a monitor function/statement, the front waiter on urgent is unblocked if all its monitors are released.
     2273Implementing a fast subset check for the necessary released monitors is important.
    24942274% The benefit is encapsulating complexity into only two actions: passing monitors to the next owner when they should be released and conditionally waking threads if all conditions are met.
    24952275
    24962276
    2497 \subsection{\texorpdfstring{\protect\lstinline@waitfor@ Implementation}{waitfor Implementation}}
    2498 \label{s:waitforImplementation}
    2499 
    2500 In a statically typed object-oriented programming language, a class has an exhaustive list of members, even when members are added via static inheritance (see Figure~\ref{f:uCinheritance}).
    2501 Knowing all members at compilation, even separate compilation, allows uniquely numbered them so the accept-statement implementation can use a fast and compact bit mask with $O(1)$ compare.
    2502 
    2503 \begin{figure}
    2504 \centering
    2505 \begin{lrbox}{\myboxA}
    2506 \begin{uC++}[aboveskip=0pt,belowskip=0pt]
    2507 $\emph{translation unit 1}$
    2508 _Monitor B { // common type in .h file
    2509         _Mutex virtual void `f`( ... );
    2510         _Mutex virtual void `g`( ... );
    2511         _Mutex virtual void w1( ... ) { ... _Accept(`f`, `g`); ... }
    2512 };
    2513 $\emph{translation unit 2}$
    2514 // include B
    2515 _Monitor D : public B { // inherit
    2516         _Mutex void `h`( ... ); // add
    2517         _Mutex void w2( ... ) { ... _Accept(`f`, `h`); ... }
    2518 };
    2519 \end{uC++}
    2520 \end{lrbox}
    2521 
    2522 \begin{lrbox}{\myboxB}
    2523 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    2524 $\emph{translation unit 1}$
    2525 monitor M { ... }; // common type in .h file
    2526 void `f`( M & mutex m, ... );
    2527 void `g`( M & mutex m, ... );
    2528 void w1( M & mutex m, ... ) { ... waitfor(`f`, `g` : m); ... }
    2529 
    2530 $\emph{translation unit 2}$
    2531 // include M
    2532 extern void `f`( M & mutex m, ... ); // import f but not g
    2533 void `h`( M & mutex m ); // add
    2534 void w2( M & mutex m, ... ) { ... waitfor(`f`, `h` : m); ... }
    2535 
    2536 \end{cfa}
    2537 \end{lrbox}
    2538 
    2539 \subfloat[\uC]{\label{f:uCinheritance}\usebox\myboxA}
    2540 \hspace{3pt}
    2541 \vrule
    2542 \hspace{3pt}
    2543 \subfloat[\CFA]{\label{f:CFinheritance}\usebox\myboxB}
    2544 \caption{Member / function visibility}
    2545 \label{f:MemberFunctionVisibility}
    2546 \end{figure}
    2547 
    2548 However, the @waitfor@ statement in translation unit 2 (see Figure~\ref{f:CFinheritance}) cannot see function @g@ in translation unit 1 precluding a unique numbering for a bit-mask because the monitor type only carries the protected shared data.
     2277\subsection{Loose Object Definitions}
     2278\label{s:LooseObjectDefinitions}
     2279
     2280In an object-oriented programming language, a class includes an exhaustive list of operations.
     2281A new class can add members via static inheritance but the subclass still has an exhaustive list of operations.
     2282(Dynamic member adding, \eg JavaScript~\cite{JavaScript}, is not considered.)
     2283In the object-oriented scenario, the type and all its operators are always present at compilation (even separate compilation), so it is possible to number the operations in a bit mask and use an $O(1)$ compare with a similar bit mask created for the operations specified in a @waitfor@.
     2284
     2285However, in \CFA, monitor functions can be statically added/removed in translation units, making a fast subset check difficult.
     2286\begin{cfa}
     2287        monitor M { ... }; // common type, included in .h file
     2288translation unit 1
     2289        void `f`( M & mutex m );
     2290        void g( M & mutex m ) { waitfor( `f`, m ); }
     2291translation unit 2
     2292        void `f`( M & mutex m ); $\C{// replacing f and g for type M in this translation unit}$
     2293        void `g`( M & mutex m );
     2294        void h( M & mutex m ) { waitfor( `f`, m ) or waitfor( `g`, m ); } $\C{// extending type M in this translation unit}$
     2295\end{cfa}
     2296The @waitfor@ statements in each translation unit cannot form a unique bit-mask because the monitor type does not carry that information.
     2297Hence, function pointers are used to identify the functions listed in the @waitfor@ statement, stored in a variable-sized array.
     2298Then, the same implementation approach used for the urgent stack is used for the calling queue.
     2299Each caller has a list of monitors acquired, and the @waitfor@ statement performs a (usually short) linear search matching functions in the @waitfor@ list with called functions, and then verifying the associated mutex locks can be transfers.
    25492300(A possible way to construct a dense mapping is at link or load-time.)
    2550 Hence, function pointers are used to identify the functions listed in the @waitfor@ statement, stored in a variable-sized array.
    2551 Then, the same implementation approach used for the urgent stack (see Section~\ref{s:Scheduling}) is used for the calling queue.
    2552 Each caller has a list of monitors acquired, and the @waitfor@ statement performs a short linear search matching functions in the @waitfor@ list with called functions, and then verifying the associated mutex locks can be transferred.
    2553 
    2554 
    2555 \subsection{Multimonitor scheduling}
     2301
     2302
     2303\subsection{Multi-Monitor Scheduling}
    25562304\label{s:Multi-MonitorScheduling}
    25572305
    2558 External scheduling, like internal scheduling, becomes significantly more complex for multimonitor semantics.
     2306External scheduling, like internal scheduling, becomes significantly more complex for multi-monitor semantics.
    25592307Even in the simplest case, new semantics need to be established.
    25602308\begin{cfa}
     
    25652313The solution is for the programmer to disambiguate:
    25662314\begin{cfa}
    2567 waitfor( f : `m2` ); $\C{// wait for call to f with argument m2}$
     2315waitfor( f, `m2` ); $\C{// wait for call to f with argument m2}$
    25682316\end{cfa}
    25692317Both locks are acquired by function @g@, so when function @f@ is called, the lock for monitor @m2@ is passed from @g@ to @f@, while @g@ still holds lock @m1@.
    2570 This behavior can be extended to the multimonitor @waitfor@ statement.
     2318This behaviour can be extended to the multi-monitor @waitfor@ statement.
    25712319\begin{cfa}
    25722320monitor M { ... };
    25732321void f( M & mutex m1, M & mutex m2 );
    2574 void g( M & mutex m1, M & mutex m2 ) { waitfor( f : `m1, m2` ); $\C{// wait for call to f with arguments m1 and m2}$
     2322void g( M & mutex m1, M & mutex m2 ) { waitfor( f, `m1, m2` ); $\C{// wait for call to f with arguments m1 and m2}$
    25752323\end{cfa}
    25762324Again, the set of monitors passed to the @waitfor@ statement must be entirely contained in the set of monitors already acquired by the accepting function.
    2577 % Also, the order of the monitors in a @waitfor@ statement must match the order of the mutex parameters.
    2578 
    2579 Figure~\ref{f:UnmatchedMutexSets} shows internal and external scheduling with multiple monitors that must match exactly with a signaling or accepting thread, \ie partial matching results in waiting.
    2580 In both cases, the set of monitors is disjoint so unblocking is impossible.
     2325Also, the order of the monitors in a @waitfor@ statement is unimportant.
     2326
     2327Figure~\ref{f:UnmatchedMutexSets} shows an example where, for internal and external scheduling with multiple monitors, a signalling or accepting thread must match exactly, \ie partial matching results in waiting.
     2328For both examples, the set of monitors is disjoint so unblocking is impossible.
    25812329
    25822330\begin{figure}
     
    26072355}
    26082356void g( M1 & mutex m1, M2 & mutex m2 ) {
    2609         waitfor( f : m1, m2 );
     2357        waitfor( f, m1, m2 );
    26102358}
    26112359g( `m11`, m2 ); // block on accept
     
    26222370\end{figure}
    26232371
     2372
     2373\subsection{\texorpdfstring{\protect\lstinline@mutex@ Threads}{mutex Threads}}
     2374
     2375Threads in \CFA can also be monitors to allow \emph{direct communication} among threads, \ie threads can have mutex functions that are called by other threads.
     2376Hence, all monitor features are available when using threads.
     2377Figure~\ref{f:DirectCommunication} shows a comparison of direct call communication in \CFA with direct channel communication in Go.
     2378(Ada provides a similar mechanism to the \CFA direct communication.)
     2379The program main in both programs communicates directly with the other thread versus indirect communication where two threads interact through a passive monitor.
     2380Both direct and indirection thread communication are valuable tools in structuring concurrent programs.
     2381
    26242382\begin{figure}
    26252383\centering
     
    26282386
    26292387struct Msg { int i, j; };
    2630 mutex thread GoRtn { int i;  float f;  Msg m; };
     2388thread GoRtn { int i;  float f;  Msg m; };
    26312389void mem1( GoRtn & mutex gortn, int i ) { gortn.i = i; }
    26322390void mem2( GoRtn & mutex gortn, float f ) { gortn.f = f; }
     
    26342392void ^?{}( GoRtn & mutex ) {}
    26352393
    2636 void main( GoRtn & mutex gortn ) with(gortn) { // thread starts
     2394void main( GoRtn & gortn ) with( gortn ) { // thread starts
    26372395
    26382396        for () {
    26392397
    2640                 `waitfor( mem1 : gortn )` sout | i;  // wait for calls
    2641                 or `waitfor( mem2 : gortn )` sout | f;
    2642                 or `waitfor( mem3 : gortn )` sout | m.i | m.j;
    2643                 or `waitfor( ^?{} : gortn )` break; // low priority
     2398                `waitfor( mem1, gortn )` sout | i;  // wait for calls
     2399                or `waitfor( mem2, gortn )` sout | f;
     2400                or `waitfor( mem3, gortn )` sout | m.i | m.j;
     2401                or `waitfor( ^?{}, gortn )` break;
    26442402
    26452403        }
     
    26952453\hspace{3pt}
    26962454\subfloat[Go]{\label{f:Gochannel}\usebox\myboxB}
    2697 \caption{Direct versus indirect communication}
    2698 \label{f:DirectCommunicationComparison}
    2699 
    2700 \medskip
    2701 
    2702 \begin{cfa}
    2703 mutex thread DatingService {
    2704         condition Girls[CompCodes], Boys[CompCodes];
    2705         int girlPhoneNo, boyPhoneNo, ccode;
    2706 };
    2707 int girl( DatingService & mutex ds, int phoneno, int code ) with( ds ) {
    2708         girlPhoneNo = phoneno;  ccode = code;
    2709         `wait( Girls[ccode] );`                                                         $\C{// wait for boy}$
    2710         girlPhoneNo = phoneno;  return boyPhoneNo;
    2711 }
    2712 int boy( DatingService & mutex ds, int phoneno, int code ) with( ds ) {
    2713         boyPhoneNo = phoneno;  ccode = code;
    2714         `wait( Boys[ccode] );`                                                          $\C{// wait for girl}$
    2715         boyPhoneNo = phoneno;  return girlPhoneNo;
    2716 }
    2717 void main( DatingService & ds ) with( ds ) {                    $\C{// thread starts, ds defaults to mutex}$
    2718         for () {
    2719                 waitfor( ^?{} ) break;                                                  $\C{// high priority}$
    2720                 or waitfor( girl )                                                              $\C{// girl called, compatible boy ? restart boy then girl}$
    2721                         if ( ! is_empty( Boys[ccode] ) ) { `signal_block( Boys[ccode] );  signal_block( Girls[ccode] );` }
    2722                 or waitfor( boy ) {                                                             $\C{// boy called, compatible girl ? restart girl then boy}$
    2723                         if ( ! is_empty( Girls[ccode] ) ) { `signal_block( Girls[ccode] );  signal_block( Boys[ccode] );` }
    2724         }
    2725 }
    2726 \end{cfa}
    2727 \caption{Direct communication dating service}
    2728 \label{f:DirectCommunicationDatingService}
     2455\caption{Direct communication}
     2456\label{f:DirectCommunication}
    27292457\end{figure}
    27302458
     
    27412469void main( Ping & pi ) {
    27422470        for ( 10 ) {
    2743                 `waitfor( ping : pi );`
     2471                `waitfor( ping, pi );`
    27442472                `pong( po );`
    27452473        }
     
    27542482        for ( 10 ) {
    27552483                `ping( pi );`
    2756                 `waitfor( pong : po );`
     2484                `waitfor( pong, po );`
    27572485        }
    27582486}
     
    27652493% \label{f:pingpong}
    27662494% \end{figure}
    2767 Note, the ping/pong threads are globally declared, @pi@/@po@, and hence, start and possibly complete before the program main starts.
     2495Note, the ping/pong threads are globally declared, @pi@/@po@, and hence, start (and possibly complete) before the program main starts.
    27682496\end{comment}
    27692497
    27702498
    2771 \subsection{\texorpdfstring{\protect\lstinline@mutex@ Generators / coroutines / threads}{monitor Generators / coroutines / threads}}
    2772 
    2773 \CFA generators, coroutines, and threads can also be @mutex@ (Table~\ref{t:ExecutionPropertyComposition} cases 4, 6, 12) allowing safe \emph{direct communication} with threads, \ie the custom types can have mutex functions that are called by other threads.
    2774 All monitor features are available within these mutex functions.
    2775 For example, if the formatter generator or coroutine equivalent in Figure~\ref{f:CFAFormatGen} is extended with the monitor property and this interface function is used to communicate with the formatter:
    2776 \begin{cfa}
    2777 void fmt( Fmt & mutex fmt, char ch ) { fmt.ch = ch; resume( fmt ) }
    2778 \end{cfa}
    2779 multiple threads can safely pass characters for formatting.
    2780 
    2781 Figure~\ref{f:DirectCommunicationComparison} shows a comparison of direct call-communication in \CFA versus indirect channel-communication in Go.
    2782 (Ada has a similar mechanism to \CFA direct communication.)
    2783 % The thread main function is by default @mutex@, so the @mutex@ qualifier for the thread parameter is optional.
    2784 % The reason is that the thread logically starts instantaneously in the thread main acquiring its mutual exclusion, so it starts before any calls to prepare for synchronizing these calls.
    2785 The \CFA program @main@ uses the call/return paradigm to directly communicate with the @GoRtn main@, whereas Go switches to the unbuffered channel paradigm to indirectly communicate with the goroutine.
    2786 Communication by multiple threads is safe for the @gortn@ thread via mutex calls in \CFA or channel assignment in Go.
    2787 The difference between call and channel send occurs for buffered channels making the send asynchronous.
    2788 In \CFA, asynchronous call and multiple buffers are provided using an administrator and worker threads~\cite{Gentleman81} and/or futures (not discussed).
    2789 
    2790 Figure~\ref{f:DirectCommunicationDatingService} shows the dating-service problem in Figure~\ref{f:DatingServiceMonitor} extended from indirect monitor communication to direct thread communication.
    2791 When converting a monitor to a thread (server), the coding pattern is to move as much code as possible from the accepted functions into the thread main so it does as much work as possible.
    2792 Notice, the dating server is postponing requests for an unspecified time while continuing to accept new requests.
    2793 For complex servers, \eg web-servers, there can be hundreds of lines of code in the thread main and safe interaction with clients can be complex.
     2499\subsection{Execution Properties}
     2500
     2501Table~\ref{t:ObjectPropertyComposition} shows how the \CFA high-level constructs cover 3 fundamental execution properties: thread, stateful function, and mutual exclusion.
     2502Case 1 is a basic object, with none of the new execution properties.
     2503Case 2 allows @mutex@ calls to Case 1 to protect shared data.
     2504Case 3 allows stateful functions to suspend/resume but restricts operations because the state is stackless.
     2505Case 4 allows @mutex@ calls to Case 3 to protect shared data.
     2506Cases 5 and 6 are the same as 3 and 4 without restriction because the state is stackful.
     2507Cases 7 and 8 are rejected because a thread cannot execute without a stackful state in a preemptive environment when context switching from the signal handler.
     2508Cases 9 and 10 have a stackful thread without and with @mutex@ calls.
     2509For situations where threads do not require direct communication, case 9 provides faster creation/destruction by eliminating @mutex@ setup.
     2510
     2511\begin{table}
     2512\caption{Object property composition}
     2513\centering
     2514\label{t:ObjectPropertyComposition}
     2515\renewcommand{\arraystretch}{1.25}
     2516%\setlength{\tabcolsep}{5pt}
     2517\begin{tabular}{c|c||l|l}
     2518\multicolumn{2}{c||}{object properties} & \multicolumn{2}{c}{mutual exclusion} \\
     2519\hline
     2520thread  & stateful                              & \multicolumn{1}{c|}{No} & \multicolumn{1}{c}{Yes} \\
     2521\hline
     2522\hline
     2523No              & No                                    & \textbf{1}\ \ \ aggregate type                & \textbf{2}\ \ \ @monitor@ aggregate type \\
     2524\hline
     2525No              & Yes (stackless)               & \textbf{3}\ \ \ @generator@                   & \textbf{4}\ \ \ @monitor@ @generator@ \\
     2526\hline
     2527No              & Yes (stackful)                & \textbf{5}\ \ \ @coroutine@                   & \textbf{6}\ \ \ @monitor@ @coroutine@ \\
     2528\hline
     2529Yes             & No / Yes (stackless)  & \textbf{7}\ \ \ {\color{red}rejected} & \textbf{8}\ \ \ {\color{red}rejected} \\
     2530\hline
     2531Yes             & Yes (stackful)                & \textbf{9}\ \ \ @thread@                              & \textbf{10}\ \ @monitor@ @thread@ \\
     2532\end{tabular}
     2533\end{table}
    27942534
    27952535
     
    27972537
    27982538For completeness and efficiency, \CFA provides a standard set of low-level locks: recursive mutex, condition, semaphore, barrier, \etc, and atomic instructions: @fetchAssign@, @fetchAdd@, @testSet@, @compareSet@, \etc.
    2799 Some of these low-level mechanisms are used to build the \CFA runtime, but we always advocate using high-level mechanisms whenever possible.
     2539Some of these low-level mechanism are used in the \CFA runtime, but we strongly advocate using high-level mechanisms whenever possible.
    28002540
    28012541
     
    28112551%
    28122552%
    2813 % \subsection{User threads}
     2553% \subsection{User Threads}
    28142554%
    28152555% A direct improvement on kernel threads is user threads, \eg Erlang~\cite{Erlang} and \uC~\cite{uC++book}.
     
    28262566
    28272567\begin{comment}
    2828 \subsection{Thread pools}
     2568\subsection{Thread Pools}
    28292569
    28302570In contrast to direct threading is indirect \newterm{thread pools}, \eg Java @executor@, where small jobs (work units) are inserted into a work pool for execution.
    2831 If the jobs are dependent, \ie interact, there is an implicit dependency graph that ties them together.
     2571If the jobs are dependent, \ie interact, there is an implicit/explicit dependency graph that ties them together.
    28322572While removing direct concurrency, and hence the amount of context switching, thread pools significantly limit the interaction that can occur among jobs.
    28332573Indeed, jobs should not block because that also blocks the underlying thread, which effectively means the CPU utilization, and therefore throughput, suffers.
     
    28402580\begin{cfa}
    28412581struct Adder {
    2842         int * row, cols;
     2582    int * row, cols;
    28432583};
    28442584int operator()() {
     
    28992639\label{s:RuntimeStructureCluster}
    29002640
    2901 A \newterm{cluster} is a collection of user and kernel threads, where the kernel threads run the user threads from the cluster's ready queue, and the operating system runs the kernel threads on the processors from its ready queue~\cite{Buhr90a}.
    2902 The term \newterm{virtual processor} is introduced as a synonym for kernel thread to disambiguate between user and kernel thread.
    2903 From the language perspective, a virtual processor is an actual processor (core).
    2904 
     2641A \newterm{cluster} is a collection of threads and virtual processors (abstract kernel-thread) that execute the (user) threads from its own ready queue (like an OS executing kernel threads).
    29052642The purpose of a cluster is to control the amount of parallelism that is possible among threads, plus scheduling and other execution defaults.
    29062643The default cluster-scheduler is single-queue multi-server, which provides automatic load-balancing of threads on processors.
    2907 However, the design allows changing the scheduler, \eg multi-queue multiserver with work-stealing/sharing across the virtual processors.
     2644However, the design allows changing the scheduler, \eg multi-queue multi-server with work-stealing/sharing across the virtual processors.
    29082645If several clusters exist, both threads and virtual processors, can be explicitly migrated from one cluster to another.
    29092646No automatic load balancing among clusters is performed by \CFA.
     
    29152652
    29162653
    2917 \subsection{Virtual processor}
     2654\subsection{Virtual Processor}
    29182655\label{s:RuntimeStructureProcessor}
    29192656
    2920 A virtual processor is implemented by a kernel thread, \eg UNIX process, which are scheduled for execution on a hardware processor by the underlying operating system.
     2657A virtual processor is implemented by a kernel thread (\eg UNIX process), which are scheduled for execution on a hardware processor by the underlying operating system.
    29212658Programs may use more virtual processors than hardware processors.
    29222659On a multiprocessor, kernel threads are distributed across the hardware processors resulting in virtual processors executing in parallel.
    2923 (It is possible to use affinity to lock a virtual processor onto a particular hardware processor~\cite{affinityLinux,affinityWindows}, which is used when caching issues occur or for heterogeneous hardware processors.) %, affinityFreebsd, affinityNetbsd, affinityMacosx
     2660(It is possible to use affinity to lock a virtual processor onto a particular hardware processor~\cite{affinityLinux, affinityWindows, affinityFreebsd, affinityNetbsd, affinityMacosx}, which is used when caching issues occur or for heterogeneous hardware processors.)
    29242661The \CFA runtime attempts to block unused processors and unblock processors as the system load increases;
    2925 balancing the workload with processors is difficult because it requires future knowledge, \ie what will the application workload do next.
     2662balancing the workload with processors is difficult because it requires future knowledge, \ie what will the applicaton workload do next.
    29262663Preemption occurs on virtual processors rather than user threads, via operating-system interrupts.
    29272664Thus virtual processors execute user threads, where preemption frequency applies to a virtual processor, so preemption occurs randomly across the executed user threads.
     
    29332670\label{s:Implementation}
    29342671
    2935 A primary implementation challenge is avoiding contention from dynamically allocating memory because of bulk acquire, \eg the internal-scheduling design is almost free of allocations.
     2672A primary implementation challenge is avoiding contention from dynamically allocating memory because of bulk acquire, \eg the internal-scheduling design is (almost) free of allocations.
    29362673All blocking operations are made by parking threads onto queues, therefore all queues are designed with intrusive nodes, where each node has preallocated link fields for chaining.
    29372674Furthermore, several bulk-acquire operations need a variable amount of memory.
    29382675This storage is allocated at the base of a thread's stack before blocking, which means programmers must add a small amount of extra space for stacks.
    29392676
    2940 In \CFA, ordering of monitor acquisition relies on memory ordering to prevent deadlock~\cite{Havender68}, because all objects have distinct nonoverlapping memory layouts, and mutual-exclusion for a monitor is only defined for its lifetime.
     2677In \CFA, ordering of monitor acquisition relies on memory ordering to prevent deadlock~\cite{Havender68}, because all objects have distinct non-overlapping memory layouts, and mutual-exclusion for a monitor is only defined for its lifetime.
    29412678When a mutex call is made, pointers to the concerned monitors are aggregated into a variable-length array and sorted.
    29422679This array persists for the entire duration of the mutual exclusion and is used extensively for synchronization operations.
     
    29572694
    29582695Nondeterministic preemption provides fairness from long-running threads, and forces concurrent programmers to write more robust programs, rather than relying on code between cooperative scheduling to be atomic.
    2959 This atomic reliance can fail on multicore machines, because execution across cores is nondeterministic.
    2960 A different reason for not supporting preemption is that it significantly complicates the runtime system, \eg Windows runtime does not support interrupts and on Linux systems, interrupts are complex (see below).
     2696This atomic reliance can fail on multi-core machines, because execution across cores is nondeterministic.
     2697A different reason for not supporting preemption is that it significantly complicates the runtime system, \eg Microsoft runtime does not support interrupts and on Linux systems, interrupts are complex (see below).
    29612698Preemption is normally handled by setting a countdown timer on each virtual processor.
    2962 When the timer expires, an interrupt is delivered, and its signal handler resets the countdown timer, and if the virtual processor is executing in user code, the signal handler performs a user-level context-switch, or if executing in the language runtime kernel, the preemption is ignored or rolled forward to the point where the runtime kernel context switches back to user code.
     2699When the timer expires, an interrupt is delivered, and the interrupt handler resets the countdown timer, and if the virtual processor is executing in user code, the signal handler performs a user-level context-switch, or if executing in the language runtime kernel, the preemption is ignored or rolled forward to the point where the runtime kernel context switches back to user code.
    29632700Multiple signal handlers may be pending.
    29642701When control eventually switches back to the signal handler, it returns normally, and execution continues in the interrupted user thread, even though the return from the signal handler may be on a different kernel thread than the one where the signal is delivered.
    29652702The only issue with this approach is that signal masks from one kernel thread may be restored on another as part of returning from the signal handler;
    29662703therefore, the same signal mask is required for all virtual processors in a cluster.
    2967 Because preemption interval is usually long (1 ms) performance cost is negligible.
    2968 
    2969 Linux switched a decade ago from specific to arbitrary virtual-processor signal-delivery for applications with multiple kernel threads.
    2970 In the new semantics, a virtual-processor directed signal may be delivered to any virtual processor created by the application that does not have the signal blocked.
     2704Because preemption frequency is usually long (1 millisecond) performance cost is negligible.
     2705
     2706Linux switched a decade ago from specific to arbitrary process signal-delivery for applications with multiple kernel threads.
     2707\begin{cquote}
     2708A process-directed signal may be delivered to any one of the threads that does not currently have the signal blocked.
     2709If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which it will deliver the signal.
     2710SIGNAL(7) - Linux Programmer's Manual
     2711\end{cquote}
    29712712Hence, the timer-expiry signal, which is generated \emph{externally} by the Linux kernel to an application, is delivered to any of its Linux subprocesses (kernel threads).
    29722713To ensure each virtual processor receives a preemption signal, a discrete-event simulation is run on a special virtual processor, and only it sets and receives timer events.
     
    29762717
    29772718
    2978 \subsection{Debug kernel}
    2979 
    2980 There are two versions of the \CFA runtime kernel: debug and nondebug.
    2981 The debugging version has many runtime checks and internal assertions, \eg stack nonwritable guard page, and checks for stack overflow whenever context switches occur among coroutines and threads, which catches most stack overflows.
    2982 After a program is debugged, the nondebugging version can be used to significantly decrease space and increase performance.
     2719\subsection{Debug Kernel}
     2720
     2721There are two versions of the \CFA runtime kernel: debug and non-debug.
     2722The debugging version has many runtime checks and internal assertions, \eg stack (non-writable) guard page, and checks for stack overflow whenever context switches occur among coroutines and threads, which catches most stack overflows.
     2723After a program is debugged, the non-debugging version can be used to significantly decrease space and increase performance.
    29832724
    29842725
     
    29862727\label{s:Performance}
    29872728
    2988 To test the performance of the \CFA runtime, a series of microbenchmarks are used to compare \CFA with pthreads, Java 11.0.6, Go 1.12.6, Rust 1.37.0, Python 3.7.6, Node.js 12.14.1, and \uC 7.0.0.
    2989 For comparison, the package must be multiprocessor (M:N), which excludes libdil and libmil~\cite{libdill} (M:1)), and use a shared-memory programming model, \eg not message passing.
    2990 The benchmark computer is an AMD Opteron\texttrademark\ 6380 NUMA 64-core, 8 socket, 2.5 GHz processor, running Ubuntu 16.04.6 LTS, and pthreads/\CFA/\uC are compiled with gcc 9.2.1.
    2991 
    2992 All benchmarks are run using the following harness.
    2993 (The Java harness is augmented to circumvent JIT issues.)
    2994 \begin{cfa}
    2995 #define BENCH( `run` ) uint64_t start = cputime_ns();  `run;`  double result = (double)(cputime_ns() - start) / N;
    2996 \end{cfa}
    2997 where CPU time in nanoseconds is from the appropriate language clock.
    2998 Each benchmark is performed @N@ times, where @N@ is selected so the benchmark runs in the range of 2--20 s for the specific programming language;
    2999 each @N@ appears after the experiment name in the following tables.
    3000 The total time is divided by @N@ to obtain the average time for a benchmark.
    3001 Each benchmark experiment is run 13 times and the average appears in the table.
    3002 For languages with a runtime JIT (Java, Node.js, Python), a single half-hour long experiment is run to check stability;
    3003 all long-experiment results are statistically equivalent, \ie median/average/SD correlate with the short-experiment results, indicating the short experiments reached a steady state.
    3004 All omitted tests for other languages are functionally identical to the \CFA tests and available online~\cite{CforallConcurrentBenchmarks}.
    3005 
    3006 \subsection{Creation}
    3007 
    3008 Creation is measured by creating and deleting a specific kind of control-flow object.
    3009 Figure~\ref{f:creation} shows the code for \CFA with results in Table~\ref{t:creation}.
    3010 Note, the call stacks of \CFA coroutines are lazily created on the first resume, therefore the cost of creation with and without a stack are presented.
     2729To verify the implementation of the \CFA runtime, a series of microbenchmarks are performed comparing \CFA with pthreads, Java OpenJDK-9, Go 1.12.6 and \uC 7.0.0.
     2730For comparison, the package must be multi-processor (M:N), which excludes libdill/libmil~\cite{libdill} (M:1)), and use a shared-memory programming model, \eg not message passing.
     2731The benchmark computer is an AMD Opteron\texttrademark\ 6380 NUMA 64-core, 8 socket, 2.5 GHz processor, running Ubuntu 16.04.6 LTS, and \CFA/\uC are compiled with gcc 6.5.
     2732
     2733All benchmarks are run using the following harness. (The Java harness is augmented to circumvent JIT issues.)
     2734\begin{cfa}
     2735unsigned int N = 10_000_000;
     2736#define BENCH( `run` ) Time before = getTimeNsec();  `run;`  Duration result = (getTimeNsec() - before) / N;
     2737\end{cfa}
     2738The method used to get time is @clock_gettime( CLOCK_REALTIME )@.
     2739Each benchmark is performed @N@ times, where @N@ varies depending on the benchmark;
     2740the total time is divided by @N@ to obtain the average time for a benchmark.
     2741Each benchmark experiment is run 31 times.
     2742All omitted tests for other languages are functionally identical to the \CFA tests and available online~\cite{CforallBenchMarks}.
     2743% tar --exclude=.deps --exclude=Makefile --exclude=Makefile.in --exclude=c.c --exclude=cxx.cpp --exclude=fetch_add.c -cvhf benchmark.tar benchmark
     2744
     2745\paragraph{Object Creation}
     2746
     2747Object creation is measured by creating/deleting the specific kind of concurrent object.
     2748Figure~\ref{f:creation} shows the code for \CFA, with results in Table~\ref{tab:creation}.
     2749The only note here is that the call stacks of \CFA coroutines are lazily created, therefore without priming the coroutine to force stack creation, the creation cost is artificially low.
    30112750
    30122751\begin{multicols}{2}
    3013 \begin{cfa}[xleftmargin=0pt]
    3014 `coroutine` MyCoroutine {};
    3015 void ?{}( MyCoroutine & this ) {
    3016 #ifdef EAGER
    3017         resume( this );
    3018 #endif
    3019 }
    3020 void main( MyCoroutine & ) {}
     2752\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
     2753\begin{cfa}
     2754@thread@ MyThread {};
     2755void @main@( MyThread & ) {}
    30212756int main() {
    3022         BENCH( for ( N ) { `MyCoroutine c;` } )
    3023         sout | result;
    3024 }
    3025 \end{cfa}
    3026 \captionof{figure}{\CFA creation benchmark}
     2757        BENCH( for ( N ) { @MyThread m;@ } )
     2758        sout | result`ns;
     2759}
     2760\end{cfa}
     2761\captionof{figure}{\CFA object-creation benchmark}
    30272762\label{f:creation}
    30282763
     
    30302765
    30312766\vspace*{-16pt}
    3032 \captionof{table}{Creation comparison (nanoseconds)}
    3033 \label{t:creation}
     2767\captionof{table}{Object creation comparison (nanoseconds)}
     2768\label{tab:creation}
    30342769
    30352770\begin{tabular}[t]{@{}r*{3}{D{.}{.}{5.2}}@{}}
    3036 \multicolumn{1}{@{}r}{Object(N)\hspace*{10pt}} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    3037 \CFA generator (1B)                     & 0.6           & 0.6           & 0.0           \\
    3038 \CFA coroutine lazy     (100M)  & 13.4          & 13.1          & 0.5           \\
    3039 \CFA coroutine eager (10M)      & 144.7         & 143.9         & 1.5           \\
    3040 \CFA thread (10M)                       & 466.4         & 468.0         & 11.3          \\
    3041 \uC coroutine (10M)                     & 155.6         & 155.7         & 1.7           \\
    3042 \uC thread (10M)                        & 523.4         & 523.9         & 7.7           \\
    3043 Python generator (10M)          & 123.2         & 124.3         & 4.1           \\
    3044 Node.js generator (10M)         & 33.4          & 33.5          & 0.3           \\
    3045 Goroutine thread (10M)          & 751.0         & 750.5         & 3.1           \\
    3046 Rust tokio thread (10M)         & 1860.0        & 1881.1        & 37.6          \\
    3047 Rust thread     (250K)                  & 53801.0       & 53896.8       & 274.9         \\
    3048 Java thread (250K)                      & 119256.0      & 119679.2      & 2244.0        \\
    3049 % Java thread (1 000 000)               & 123100.0      & 123052.5      & 751.6         \\
    3050 Pthreads thread (250K)          & 31465.5       & 31419.5       & 140.4
     2771\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
     2772\CFA Coroutine Lazy             & 13.2          & 13.1          & 0.44          \\
     2773\CFA Coroutine Eager    & 531.3         & 536.0         & 26.54         \\
     2774\CFA Thread                             & 2074.9        & 2066.5        & 170.76        \\
     2775\uC Coroutine                   & 89.6          & 90.5          & 1.83          \\
     2776\uC Thread                              & 528.2         & 528.5         & 4.94          \\
     2777Goroutine                               & 4068.0        & 4113.1        & 414.55        \\
     2778Java Thread                             & 103848.5      & 104295.4      & 2637.57       \\
     2779Pthreads                                & 33112.6       & 33127.1       & 165.90
    30512780\end{tabular}
    30522781\end{multicols}
    30532782
    3054 \vspace*{-10pt}
    3055 \subsection{Internal scheduling}
    3056 
    3057 Internal scheduling is measured using a cycle of two threads signaling and waiting.
    3058 Figure~\ref{f:schedint} shows the code for \CFA, with results in Table~\ref{t:schedint}.
    3059 Note, the \CFA incremental cost for bulk acquire is a fixed cost for small numbers of mutex objects.
    3060 User-level threading has one kernel thread, eliminating contention between the threads (direct handoff of the kernel thread).
    3061 Kernel-level threading has two kernel threads allowing some contention.
     2783
     2784\paragraph{Context-Switching}
     2785
     2786In procedural programming, the cost of a function call is important as modularization (refactoring) increases.
     2787(In many cases, a compiler inlines function calls to eliminate this cost.)
     2788Similarly, when modularization extends to coroutines/tasks, the time for a context switch becomes a relevant factor.
     2789The coroutine test is from resumer to suspender and from suspender to resumer, which is two context switches.
     2790The thread test is using yield to enter and return from the runtime kernel, which is two context switches.
     2791The difference in performance between coroutine and thread context-switch is the cost of scheduling for threads, whereas coroutines are self-scheduling.
     2792Figure~\ref{f:ctx-switch} only shows the \CFA code for coroutines/threads (other systems are similar) with all results in Table~\ref{tab:ctx-switch}.
    30622793
    30632794\begin{multicols}{2}
    3064 \setlength{\tabcolsep}{3pt}
    3065 \begin{cfa}[xleftmargin=0pt]
     2795\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
     2796\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     2797@coroutine@ C {} c;
     2798void main( C & ) { for ( ;; ) { @suspend;@ } }
     2799int main() { // coroutine test
     2800        BENCH( for ( N ) { @resume( c );@ } )
     2801        sout | result`ns;
     2802}
     2803int main() { // task test
     2804        BENCH( for ( N ) { @yield();@ } )
     2805        sout | result`ns;
     2806}
     2807\end{cfa}
     2808\captionof{figure}{\CFA context-switch benchmark}
     2809\label{f:ctx-switch}
     2810
     2811\columnbreak
     2812
     2813\vspace*{-16pt}
     2814\captionof{table}{Context switch comparison (nanoseconds)}
     2815\label{tab:ctx-switch}
     2816\begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
     2817\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
     2818C function              & 1.8   & 1.8   & 0.01  \\
     2819\CFA generator  & 2.4   & 2.2   & 0.25  \\
     2820\CFA Coroutine  & 36.2  & 36.2  & 0.25  \\
     2821\CFA Thread             & 93.2  & 93.5  & 2.09  \\
     2822\uC Coroutine   & 52.0  & 52.1  & 0.51  \\
     2823\uC Thread              & 96.2  & 96.3  & 0.58  \\
     2824Goroutine               & 141.0 & 141.3 & 3.39  \\
     2825Java Thread             & 374.0 & 375.8 & 10.38 \\
     2826Pthreads Thread & 361.0 & 365.3 & 13.19
     2827\end{tabular}
     2828\end{multicols}
     2829
     2830
     2831\paragraph{Mutual-Exclusion}
     2832
     2833Uncontented mutual exclusion, which frequently occurs, is measured by entering/leaving a critical section.
     2834For monitors, entering and leaving a monitor function is measured.
     2835To put the results in context, the cost of entering a non-inline function and the cost of acquiring and releasing a @pthread_mutex@ lock is also measured.
     2836Figure~\ref{f:mutex} shows the code for \CFA with all results in Table~\ref{tab:mutex}.
     2837Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
     2838
     2839\begin{multicols}{2}
     2840\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
     2841\begin{cfa}
     2842@monitor@ M {} m1/*, m2, m3, m4*/;
     2843void __attribute__((noinline))
     2844do_call( M & @mutex m/*, m2, m3, m4*/@ ) {}
     2845int main() {
     2846        BENCH(
     2847                for( N ) do_call( m1/*, m2, m3, m4*/ );
     2848        )
     2849        sout | result`ns;
     2850}
     2851\end{cfa}
     2852\captionof{figure}{\CFA acquire/release mutex benchmark}
     2853\label{f:mutex}
     2854
     2855\columnbreak
     2856
     2857\vspace*{-16pt}
     2858\captionof{table}{Mutex comparison (nanoseconds)}
     2859\label{tab:mutex}
     2860\begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
     2861\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
     2862test and test-and-test lock             & 19.1  & 18.9  & 0.40  \\
     2863\CFA @mutex@ function, 1 arg.   & 45.9  & 46.6  & 1.45  \\
     2864\CFA @mutex@ function, 2 arg.   & 105.0 & 104.7 & 3.08  \\
     2865\CFA @mutex@ function, 4 arg.   & 165.0 & 167.6 & 5.65  \\
     2866\uC @monitor@ member rtn.               & 54.0  & 53.7  & 0.82  \\
     2867Java synchronized method                & 31.0  & 31.1  & 0.50  \\
     2868Pthreads Mutex Lock                             & 33.6  & 32.6  & 1.14
     2869\end{tabular}
     2870\end{multicols}
     2871
     2872
     2873\paragraph{External Scheduling}
     2874
     2875External scheduling is measured using a cycle of two threads calling and accepting the call using the @waitfor@ statement.
     2876Figure~\ref{f:ext-sched} shows the code for \CFA, with results in Table~\ref{tab:ext-sched}.
     2877Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
     2878
     2879\begin{multicols}{2}
     2880\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
     2881\vspace*{-16pt}
     2882\begin{cfa}
    30662883volatile int go = 0;
    3067 `condition c;`
    3068 `monitor` M {} m1/*, m2, m3, m4*/;
    3069 void call( M & `mutex p1/*, p2, p3, p4*/` ) {
    3070         `signal( c );`
    3071 }
    3072 void wait( M & `mutex p1/*, p2, p3, p4*/` ) {
     2884@monitor@ M {} m;
     2885thread T {};
     2886void __attribute__((noinline))
     2887do_call( M & @mutex@ ) {}
     2888void main( T & ) {
     2889        while ( go == 0 ) { yield(); }
     2890        while ( go == 1 ) { do_call( m ); }
     2891}
     2892int __attribute__((noinline))
     2893do_wait( M & @mutex@ m ) {
    30732894        go = 1; // continue other thread
    3074         for ( N ) { `wait( c );` } );
    3075 }
    3076 thread T {};
    3077 void main( T & ) {
    3078         while ( go == 0 ) { yield(); } // waiter must start first
    3079         BENCH( for ( N ) { call( m1/*, m2, m3, m4*/ ); } )
    3080         sout | result;
     2895        BENCH( for ( N ) { @waitfor( do_call, m );@ } )
     2896        go = 0; // stop other thread
     2897        sout | result`ns;
    30812898}
    30822899int main() {
    30832900        T t;
    3084         wait( m1/*, m2, m3, m4*/ );
    3085 }
    3086 \end{cfa}
    3087 \vspace*{-8pt}
     2901        do_wait( m );
     2902}
     2903\end{cfa}
     2904\captionof{figure}{\CFA external-scheduling benchmark}
     2905\label{f:ext-sched}
     2906
     2907\columnbreak
     2908
     2909\vspace*{-16pt}
     2910\captionof{table}{External-scheduling comparison (nanoseconds)}
     2911\label{tab:ext-sched}
     2912\begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
     2913\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
     2914\CFA @waitfor@, 1 @monitor@     & 376.4 & 376.8 & 7.63  \\
     2915\CFA @waitfor@, 2 @monitor@     & 491.4 & 492.0 & 13.31 \\
     2916\CFA @waitfor@, 4 @monitor@     & 681.0 & 681.7 & 19.10 \\
     2917\uC @_Accept@                           & 331.1 & 331.4 & 2.66
     2918\end{tabular}
     2919\end{multicols}
     2920
     2921
     2922\paragraph{Internal Scheduling}
     2923
     2924Internal scheduling is measured using a cycle of two threads signalling and waiting.
     2925Figure~\ref{f:int-sched} shows the code for \CFA, with results in Table~\ref{tab:int-sched}.
     2926Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
     2927Java scheduling is significantly greater because the benchmark explicitly creates multiple thread in order to prevent the JIT from making the program sequential, \ie removing all locking.
     2928
     2929\begin{multicols}{2}
     2930\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
     2931\begin{cfa}
     2932volatile int go = 0;
     2933@monitor@ M { @condition c;@ } m;
     2934void __attribute__((noinline))
     2935do_call( M & @mutex@ a1 ) { @signal( c );@ }
     2936thread T {};
     2937void main( T & this ) {
     2938        while ( go == 0 ) { yield(); }
     2939        while ( go == 1 ) { do_call( m ); }
     2940}
     2941int  __attribute__((noinline))
     2942do_wait( M & mutex m ) with(m) {
     2943        go = 1; // continue other thread
     2944        BENCH( for ( N ) { @wait( c );@ } );
     2945        go = 0; // stop other thread
     2946        sout | result`ns;
     2947}
     2948int main() {
     2949        T t;
     2950        do_wait( m );
     2951}
     2952\end{cfa}
    30882953\captionof{figure}{\CFA Internal-scheduling benchmark}
    3089 \label{f:schedint}
     2954\label{f:int-sched}
    30902955
    30912956\columnbreak
     
    30932958\vspace*{-16pt}
    30942959\captionof{table}{Internal-scheduling comparison (nanoseconds)}
    3095 \label{t:schedint}
     2960\label{tab:int-sched}
    30962961\bigskip
    30972962
    30982963\begin{tabular}{@{}r*{3}{D{.}{.}{5.2}}@{}}
    3099 \multicolumn{1}{@{}r}{Object(N)\hspace*{10pt}} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    3100 \CFA @signal@, 1 monitor (10M)  & 364.4         & 364.2         & 4.4           \\
    3101 \CFA @signal@, 2 monitor (10M)  & 484.4         & 483.9         & 8.8           \\
    3102 \CFA @signal@, 4 monitor (10M)  & 709.1         & 707.7         & 15.0          \\
    3103 \uC @signal@ monitor (10M)              & 328.3         & 327.4         & 2.4           \\
    3104 Rust cond. variable     (1M)            & 7514.0        & 7437.4        & 397.2         \\
    3105 Java @notify@ monitor (1M)              & 8717.0        & 8774.1        & 471.8         \\
    3106 % Java @notify@ monitor (100 000 000)           & 8634.0        & 8683.5        & 330.5         \\
    3107 Pthreads cond. variable (1M)    & 5553.7        & 5576.1        & 345.6
     2964\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
     2965\CFA @signal@, 1 @monitor@      & 372.6         & 374.3         & 14.17         \\
     2966\CFA @signal@, 2 @monitor@      & 492.7         & 494.1         & 12.99         \\
     2967\CFA @signal@, 4 @monitor@      & 749.4         & 750.4         & 24.74         \\
     2968\uC @signal@                            & 320.5         & 321.0         & 3.36          \\
     2969Java @notify@                           & 10160.5       & 10169.4       & 267.71        \\
     2970Pthreads Cond. Variable         & 4949.6        & 5065.2        & 363
    31082971\end{tabular}
    31092972\end{multicols}
    31102973
    31112974
    3112 \subsection{External scheduling}
    3113 
    3114 External scheduling is measured using a cycle of two threads calling and accepting the call using the @waitfor@ statement.
    3115 Figure~\ref{f:schedext} shows the code for \CFA with results in Table~\ref{t:schedext}.
    3116 Note, the \CFA incremental cost for bulk acquire is a fixed cost for small numbers of mutex objects.
    3117 
    3118 \begin{multicols}{2}
    3119 \setlength{\tabcolsep}{5pt}
    3120 \vspace*{-16pt}
    3121 \begin{cfa}[xleftmargin=0pt]
    3122 `monitor` M {} m1/*, m2, m3, m4*/;
    3123 void call( M & `mutex p1/*, p2, p3, p4*/` ) {}
    3124 void wait( M & `mutex p1/*, p2, p3, p4*/` ) {
    3125         for ( N ) { `waitfor( call : p1/*, p2, p3, p4*/ );` }
    3126 }
    3127 thread T {};
    3128 void main( T & ) {
    3129         BENCH( for ( N ) { call( m1/*, m2, m3, m4*/ ); } )
    3130         sout | result;
    3131 }
    3132 int main() {
    3133         T t;
    3134         wait( m1/*, m2, m3, m4*/ );
    3135 }
    3136 \end{cfa}
    3137 \captionof{figure}{\CFA external-scheduling benchmark}
    3138 \label{f:schedext}
    3139 
    3140 \columnbreak
    3141 
    3142 \vspace*{-18pt}
    3143 \captionof{table}{External-scheduling comparison (nanoseconds)}
    3144 \label{t:schedext}
    3145 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
    3146 \multicolumn{1}{@{}r}{Object(N)\hspace*{10pt}} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    3147 \CFA @waitfor@, 1 monitor (10M) & 367.1 & 365.3 & 5.0   \\
    3148 \CFA @waitfor@, 2 monitor (10M) & 463.0 & 464.6 & 7.1   \\
    3149 \CFA @waitfor@, 4 monitor (10M) & 689.6 & 696.2 & 21.5  \\
    3150 \uC \lstinline[language=uC++]|_Accept| monitor (10M)    & 328.2 & 329.1 & 3.4   \\
    3151 Go \lstinline[language=Golang]|select| channel (10M)    & 365.0 & 365.5 & 1.2
    3152 \end{tabular}
    3153 \end{multicols}
    3154 
    3155 \subsection{Mutual-Exclusion}
    3156 
    3157 Uncontented mutual exclusion, which frequently occurs, is measured by entering and leaving a critical section.
    3158 For monitors, entering and leaving a mutex function are measured, otherwise the language-appropriate mutex-lock is measured.
    3159 For comparison, a spinning (vs.\ blocking) test-and-test-set lock is presented.
    3160 Figure~\ref{f:mutex} shows the code for \CFA with results in Table~\ref{t:mutex}.
    3161 Note the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
    3162 
    3163 \begin{multicols}{2}
    3164 \setlength{\tabcolsep}{3pt}
    3165 \begin{cfa}[xleftmargin=0pt]
    3166 `monitor` M {} m1/*, m2, m3, m4*/;
    3167 call( M & `mutex p1/*, p2, p3, p4*/` ) {}
    3168 int main() {
    3169         BENCH( for( N ) call( m1/*, m2, m3, m4*/ ); )
    3170         sout | result;
    3171 }
    3172 \end{cfa}
    3173 \captionof{figure}{\CFA acquire/release mutex benchmark}
    3174 \label{f:mutex}
    3175 
    3176 \columnbreak
    3177 
    3178 \vspace*{-16pt}
    3179 \captionof{table}{Mutex comparison (nanoseconds)}
    3180 \label{t:mutex}
    3181 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
    3182 \multicolumn{1}{@{}r}{Object(N)\hspace*{10pt}} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    3183 test-and-test-set lock (50M)            & 19.1  & 18.9  & 0.4   \\
    3184 \CFA @mutex@ function, 1 arg. (50M)     & 48.3  & 47.8  & 0.9   \\
    3185 \CFA @mutex@ function, 2 arg. (50M)     & 86.7  & 87.6  & 1.9   \\
    3186 \CFA @mutex@ function, 4 arg. (50M)     & 173.4 & 169.4 & 5.9   \\
    3187 \uC @monitor@ member rtn. (50M)         & 54.8  & 54.8  & 0.1   \\
    3188 Goroutine mutex lock (50M)                      & 34.0  & 34.0  & 0.0   \\
    3189 Rust mutex lock (50M)                           & 33.0  & 33.2  & 0.8   \\
    3190 Java synchronized method (50M)          & 31.0  & 30.9  & 0.5   \\
    3191 % Java synchronized method (10 000 000 000)             & 31.0 & 30.2 & 0.9 \\
    3192 Pthreads mutex Lock (50M)                       & 31.0  & 31.1  & 0.4
    3193 \end{tabular}
    3194 \end{multicols}
    3195 
    3196 \subsection{Context switching}
    3197 
    3198 In procedural programming, the cost of a function call is important as modularization (refactoring) increases.
    3199 (In many cases, a compiler inlines function calls to increase the size and number of basic blocks for optimizing.)
    3200 Similarly, when modularization extends to coroutines and threads, the time for a context switch becomes a relevant factor.
    3201 The coroutine test is from resumer to suspender and from suspender to resumer, which is two context switches.
    3202 %For async-await systems, the test is scheduling and fulfilling @N@ empty promises, where all promises are allocated before versus interleaved with fulfillment to avoid garbage collection.
    3203 For async-await systems, the test measures the cost of the @await@ expression entering the event engine by awaiting @N@ promises, where each created promise is resolved by an immediate event in the engine (using Node.js @setImmediate@).
    3204 The thread test is using yield to enter and return from the runtime kernel, which is two context switches.
    3205 The difference in performance between coroutine and thread context-switch is the cost of scheduling for threads, whereas coroutines are self-scheduling.
    3206 Figure~\ref{f:ctx-switch} shows the \CFA code for a coroutine and thread with results in Table~\ref{t:ctx-switch}.
    3207 
    3208 % From: Gregor Richards <gregor.richards@uwaterloo.ca>
    3209 % To: "Peter A. Buhr" <pabuhr@plg2.cs.uwaterloo.ca>
    3210 % Date: Fri, 24 Jan 2020 13:49:18 -0500
    3211 %
    3212 % I can also verify that the previous version, which just tied a bunch of promises together, *does not* go back to the
    3213 % event loop at all in the current version of Node. Presumably they're taking advantage of the fact that the ordering of
    3214 % events is intentionally undefined to just jump right to the next 'then' in the chain, bypassing event queueing
    3215 % entirely. That's perfectly correct behavior insofar as its difference from the specified behavior isn't observable, but
    3216 % it isn't typical or representative of much anything useful, because most programs wouldn't have whole chains of eager
    3217 % promises. Also, it's not representative of *anything* you can do with async/await, as there's no way to encode such an
    3218 % eager chain that way.
    3219 
    3220 \begin{multicols}{2}
    3221 \begin{cfa}[xleftmargin=0pt]
    3222 `coroutine` C {};
    3223 void main( C & ) { for () { `suspend;` } }
    3224 int main() { // coroutine test
    3225         C c;
    3226         BENCH( for ( N ) { `resume( c );` } )
    3227         sout | result;
    3228 }
    3229 int main() { // thread test
    3230         BENCH( for ( N ) { `yield();` } )
    3231         sout | result;
    3232 }
    3233 \end{cfa}
    3234 \captionof{figure}{\CFA context-switch benchmark}
    3235 \label{f:ctx-switch}
    3236 
    3237 \columnbreak
    3238 
    3239 \vspace*{-16pt}
    3240 \captionof{table}{Context switch comparison (nanoseconds)}
    3241 \label{t:ctx-switch}
    3242 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
    3243 \multicolumn{1}{@{}r}{Object(N)\hspace*{10pt}} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    3244 C function (10B)                        & 1.8           & 1.8           & 0.0   \\
    3245 \CFA generator (5B)                     & 1.8           & 2.0           & 0.3   \\
    3246 \CFA coroutine (100M)           & 32.5          & 32.9          & 0.8   \\
    3247 \CFA thread (100M)                      & 93.8          & 93.6          & 2.2   \\
    3248 \uC coroutine (100M)            & 50.3          & 50.3          & 0.2   \\
    3249 \uC thread (100M)                       & 97.3          & 97.4          & 1.0   \\
    3250 Python generator (100M)         & 40.9          & 41.3          & 1.5   \\
    3251 Node.js await (5M)                      & 1852.2        & 1854.7        & 16.4  \\
    3252 Node.js generator (100M)        & 33.3          & 33.4          & 0.3   \\
    3253 Goroutine thread (100M)         & 143.0         & 143.3         & 1.1   \\
    3254 Rust async await (100M)         & 32.0          & 32.0          & 0.0   \\
    3255 Rust tokio thread (100M)        & 143.0         & 143.0         & 1.7   \\
    3256 Rust thread (25M)                       & 332.0         & 331.4         & 2.4   \\
    3257 Java thread (100M)                      & 405.0         & 415.0         & 17.6  \\
    3258 % Java thread (  100 000 000)                   & 413.0 & 414.2 & 6.2 \\
    3259 % Java thread (5 000 000 000)                   & 415.0 & 415.2 & 6.1 \\
    3260 Pthreads thread (25M)           & 334.3         & 335.2         & 3.9
    3261 \end{tabular}
    3262 \end{multicols}
    3263 
    3264 
    3265 \subsection{Discussion}
    3266 
    3267 Languages using 1:1 threading based on pthreads can at best meet or exceed, due to language overhead, the pthread results.
    3268 Note, pthreads has a fast zero-contention mutex lock checked in user space.
    3269 Languages with M:N threading have better performance than 1:1 because there is no operating-system interactions (context-switching or locking).
    3270 As well, for locking experiments, M:N threading has less contention if only one kernel thread is used.
    3271 Languages with stackful coroutines have higher cost than stackless coroutines because of stack allocation and context switching;
    3272 however, stackful \uC and \CFA coroutines have approximately the same performance as stackless Python and Node.js generators.
    3273 The \CFA stackless generator is approximately 25 times faster for suspend/resume and 200 times faster for creation than stackless Python and Node.js generators.
    3274 The Node.js context-switch is costly when asynchronous await must enter the event engine because a promise is not fulfilled.
    3275 Finally, the benchmark results correlate across programming languages with and without JIT, indicating the JIT has completed any runtime optimizations.
    3276 
    3277 
    3278 \section{Conclusions and Future Work}
     2975\section{Conclusion}
    32792976
    32802977Advanced control-flow will always be difficult, especially when there is temporal ordering and nondeterminism.
    32812978However, many systems exacerbate the difficulty through their presentation mechanisms.
    3282 This paper shows it is possible to understand high-level control-flow using three properties: statefulness, thread, mutual-exclusion/synchronization.
    3283 Combining these properties creates a number of high-level, efficient, and maintainable control-flow types: generator, coroutine, thread, each of which can be a monitor.
    3284 Eliminated from \CFA are barging and spurious wakeup, which are nonintuitive and lead to errors, and having to work with a bewildering set of low-level locks and acquisition techniques.
    3285 \CFA high-level race-free monitors and threads, when used with mutex access function, provide the core mechanisms for mutual exclusion and synchronization, without having to resort to magic qualifiers like @volatile@ or @atomic@.
     2979This paper shows it is possible to present a hierarchy of control-flow features, generator, coroutine, thread, and monitor, providing an integrated set of high-level, efficient, and maintainable control-flow features.
     2980Eliminated from \CFA are spurious wakeup and barging, which are nonintuitive and lead to errors, and having to work with a bewildering set of low-level locks and acquisition techniques.
     2981\CFA high-level race-free monitors and tasks provide the core mechanisms for mutual exclusion and synchronization, without having to resort to magic qualifiers like @volatile@/@atomic@.
    32862982Extending these mechanisms to handle high-level deadlock-free bulk acquire across both mutual exclusion and synchronization is a unique contribution.
    32872983The \CFA runtime provides concurrency based on a preemptive M:N user-level threading-system, executing in clusters, which encapsulate scheduling of work on multiple kernel threads providing parallelism.
    32882984The M:N model is judged to be efficient and provide greater flexibility than a 1:1 threading model.
    32892985These concepts and the \CFA runtime-system are written in the \CFA language, extensively leveraging the \CFA type-system, which demonstrates the expressiveness of the \CFA language.
    3290 Performance comparisons with other concurrent systems and languages show the \CFA approach is competitive across all basic operations, which translates directly into good performance in well-written applications with advanced control-flow.
    3291 C programmers should feel comfortable using these mechanisms for developing complex control-flow in applications, with the ability to obtain maximum available performance by selecting mechanisms at the appropriate level of need using only calling communication.
     2986Performance comparisons with other concurrent systems/languages show the \CFA approach is competitive across all low-level operations, which translates directly into good performance in well-written concurrent applications.
     2987C programmers should feel comfortable using these mechanisms for developing complex control-flow in applications, with the ability to obtain maximum available performance by selecting mechanisms at the appropriate level of need.
     2988
     2989
     2990\section{Future Work}
    32922991
    32932992While control flow in \CFA has a strong start, development is still underway to complete a number of missing features.
    32942993
    3295 \medskip
    3296 \textbf{Flexible scheduling:}
     2994\paragraph{Flexible Scheduling}
     2995\label{futur:sched}
     2996
    32972997An important part of concurrency is scheduling.
    3298 Different scheduling algorithms can affect performance, both in terms of average and variation.
     2998Different scheduling algorithms can affect performance (both in terms of average and variation).
    32992999However, no single scheduler is optimal for all workloads and therefore there is value in being able to change the scheduler for given programs.
    33003000One solution is to offer various tuning options, allowing the scheduler to be adjusted to the requirements of the workload.
    33013001However, to be truly flexible, a pluggable scheduler is necessary.
    3302 Currently, the \CFA pluggable scheduler is too simple to handle complex scheduling, \eg quality of service and real time, where the scheduler must interact with mutex objects to deal with issues like priority inversion~\cite{Buhr00b}.
    3303 
    3304 \smallskip
    3305 \textbf{Non-Blocking I/O:}
    3306 Many modern workloads are not bound by computation but IO operations, common cases being web servers and XaaS~\cite{XaaS} (anything as a service).
     3002Currently, the \CFA pluggable scheduler is too simple to handle complex scheduling, \eg quality of service and real-time, where the scheduler must interact with mutex objects to deal with issues like priority inversion~\cite{Buhr00b}.
     3003
     3004\paragraph{Non-Blocking I/O}
     3005\label{futur:nbio}
     3006
     3007Many modern workloads are not bound by computation but IO operations, a common case being web servers and XaaS~\cite{XaaS} (anything as a service).
    33073008These types of workloads require significant engineering to amortizing costs of blocking IO-operations.
    3308 At its core, nonblocking I/O is an operating-system level feature queuing IO operations, \eg network operations, and registering for notifications instead of waiting for requests to complete.
     3009At its core, non-blocking I/O is an operating-system level feature queuing IO operations, \eg network operations, and registering for notifications instead of waiting for requests to complete.
    33093010Current trends use asynchronous programming like callbacks, futures, and/or promises, \eg Node.js~\cite{NodeJs} for JavaScript, Spring MVC~\cite{SpringMVC} for Java, and Django~\cite{Django} for Python.
    3310 However, these solutions lead to code that is hard to create, read, and maintain.
    3311 A better approach is to tie nonblocking I/O into the concurrency system to provide ease of use with low overhead, \eg thread-per-connection web-services.
    3312 A nonblocking I/O library is currently under development for \CFA.
    3313 
    3314 \smallskip
    3315 \textbf{Other concurrency tools:}
     3011However, these solutions lead to code that is hard to create, read and maintain.
     3012A better approach is to tie non-blocking I/O into the concurrency system to provide ease of use with low overhead, \eg thread-per-connection web-services.
     3013A non-blocking I/O library is currently under development for \CFA.
     3014
     3015\paragraph{Other Concurrency Tools}
     3016\label{futur:tools}
     3017
    33163018While monitors offer flexible and powerful concurrency for \CFA, other concurrency tools are also necessary for a complete multi-paradigm concurrency package.
    33173019Examples of such tools can include futures and promises~\cite{promises}, executors and actors.
     
    33193021As well, new \CFA extensions should make it possible to create a uniform interface for virtually all mutual exclusion, including monitors and low-level locks.
    33203022
    3321 \smallskip
    3322 \textbf{Implicit threading:}
    3323 Basic \emph{embarrassingly parallel} applications can benefit greatly from implicit concurrency, where sequential programs are converted to concurrent, with some help from pragmas to guide the conversion.
     3023\paragraph{Implicit Threading}
     3024\label{futur:implcit}
     3025
     3026Basic concurrent (embarrassingly parallel) applications can benefit greatly from implicit concurrency, where sequential programs are converted to concurrent, possibly with some help from pragmas to guide the conversion.
    33243027This type of concurrency can be achieved both at the language level and at the library level.
    33253028The canonical example of implicit concurrency is concurrent nested @for@ loops, which are amenable to divide and conquer algorithms~\cite{uC++book}.
    3326 The \CFA language features should make it possible to develop a reasonable number of implicit concurrency mechanisms to solve basic HPC data-concurrency problems.
     3029The \CFA language features should make it possible to develop a reasonable number of implicit concurrency mechanism to solve basic HPC data-concurrency problems.
    33273030However, implicit concurrency is a restrictive solution with significant limitations, so it can never replace explicit concurrent programming.
    33283031
     
    33303033\section{Acknowledgements}
    33313034
    3332 The authors recognize the design assistance of Aaron Moss, Rob Schluntz, Andrew Beach, and Michael Brooks; David Dice for commenting and helping with the Java benchmarks; and Gregor Richards for helping with the Node.js benchmarks.
    3333 This research is funded by the NSERC/Waterloo-Huawei (\url{http://www.huawei.com}) Joint Innovation Lab. %, and Peter Buhr is partially funded by the Natural Sciences and Engineering Research Council of Canada.
     3035The authors would like to recognize the design assistance of Aaron Moss, Rob Schluntz, Andrew Beach and Michael Brooks on the features described in this paper.
     3036Funding for this project has been provided by Huawei Ltd.\ (\url{http://www.huawei.com}). %, and Peter Buhr is partially funded by the Natural Sciences and Engineering Research Council of Canada.
    33343037
    33353038{%
    3336 \fontsize{9bp}{11.5bp}\selectfont%
     3039\fontsize{9bp}{12bp}\selectfont%
    33373040\bibliography{pl,local}
    33383041}%
  • doc/papers/concurrency/annex/local.bib

    reef8dfb rbdfc032  
    2929    booktitle   = {Supercomputing, 2005. Proceedings of the ACM/IEEE SC 2005 Conference},
    3030    publisher   = {IEEE},
    31     location    = {Seattle, Washington, U.S.A.},
    32     month       = nov,
    3331    year        = {2005},
    3432    pages       = {35-35},
     33    month       = nov,
    3534}
    3635
     
    5958
    6059@manual{Cpp-Transactions,
    61     keywords    = {C++, Transactional Memory},
    62     title       = {Tech. Spec. for C++ Extensions for Transactional Memory {ISO/IEC} {TS} 19841:2015},
    63     organization= {International Standard Organization},
    64     address     = {Geneva, Switzerland},
    65     year        = 2015,
    66     note        = {\href{https://www.iso.org/standard/66343.html}{https://\-www.iso.org/\-standard/\-66343.html}},
     60        keywords        = {C++, Transactional Memory},
     61        title           = {Technical Specification for C++ Extensions for Transactional Memory},
     62        organization= {International Standard ISO/IEC TS 19841:2015 },
     63        publisher   = {American National Standards Institute},
     64        address = {http://www.iso.org},
     65        year            = 2015,
    6766}
    6867
     
    110109@manual{affinityLinux,
    111110        key     = {TBB},
    112         title           = "{Linux man page - sched\_setaffinity(2)}",
    113         note    = {\href{https://man7.org/linux/man-pages/man2/sched_setaffinity.2.html}{https://\-man7.org/\-linux/man-pages/\-man2/sched\_setaffinity.2.html}},
     111        title           = "{Linux man page - sched\_setaffinity(2)}"
    114112}
    115113
    116114@manual{affinityWindows,
    117         title           = "{Windows documentation - SetThreadAffinityMask function}",
    118         note    = {\href{https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setthreadaffinitymask}{https://\-docs.microsoft.com/\-en-us/\-windows/\-win32/api/\-winbase/\-nf-winbase-setthreadaffinitymask}}
     115        title           = "{Windows (vs.85) - SetThreadAffinityMask function}"
    119116}
    120117
  • doc/papers/concurrency/examples/Fib.py

    reef8dfb rbdfc032  
    44        while True:
    55                fn = fn1 + fn2; fn2 = fn1; fn1 = fn; yield fn
     6
     7
    68
    79f1 = Fib()
     
    1214# Local Variables: #
    1315# tab-width: 4 #
    14 # compile-command: "python3.7 Fib.py" #
     16# compile-command: "python3.5 Fib.py" #
    1517# End: #
  • doc/papers/concurrency/examples/Fib2.c

    reef8dfb rbdfc032  
    11#include <stdio.h>
    22
     3void mary() {
     4        printf( "MARY\n" );
     5}
     6
    37#define FIB_INIT { 0 }
    4 typedef struct { int restart; int fn1, fn2; } Fib;
     8typedef struct { int next; int fn1, fn2; } Fib;
    59int fib( Fib * f ) {
    6         static void * states[] = { &&s0, &&s1, &&s2 };
    7         goto *states[f->restart];
    8   s0:
     10        static void * states[] = { &&s1, &&s2, &&s3 };
     11        goto *states[f->next];
     12  s1:
     13        mary();
    914        f->fn1 = 0;
    10         f->restart = 1;
     15        f->next = 1;
    1116        return f->fn1;
    12   s1:
     17  s2:
     18        mary();
    1319        f->fn2 = f->fn1;
    1420        f->fn1 = 1;
    15         f->restart = 2;
     21        f->next = 2;
    1622        return f->fn1;
    17   s2:;
     23  s3:;
     24        mary();
    1825        int fn = f->fn1 + f->fn2;
    1926        f->fn2 = f->fn1;
  • doc/papers/concurrency/examples/Fib2.py

    reef8dfb rbdfc032  
    11def Fib():
    2     fn1, fn = 1, 0
     2    fn1, fn = 0, 1
    33    while True:
    4         yield fn
     4        yield fn1
    55        fn1, fn = fn, fn1 + fn
    66
     
    1212# Local Variables: #
    1313# tab-width: 4 #
    14 # compile-command: "python3.7 Fib2.py" #
     14# compile-command: "python3.5 Fib2.py" #
    1515# End: #
  • doc/papers/concurrency/examples/Fib3.c

    reef8dfb rbdfc032  
    22
    33typedef struct {
    4         int restart, fn1, fn;
     4        int fn1, fn;
     5        void * next;
    56} Fib;
    6 #define FibCtor { 0, 1, 0 }
     7#define FibCtor { 1, 0, NULL }
    78
    89Fib * comain( Fib * f ) {
    9         static void * states[] = {&&s0, &&s1};
    10         goto *states[f->restart];
    11   s0: f->restart = 1;
     10        if ( __builtin_expect(f->next != 0, 1) ) goto *f->next;
     11        f->next = &&s1;
    1212        for ( ;; ) {
    1313                return f;
  • doc/papers/concurrency/examples/FibRefactor.py

    reef8dfb rbdfc032  
    2222# Local Variables: #
    2323# tab-width: 4 #
    24 # compile-command: "python3.7 FibRefactor.py" #
     24# compile-command: "python3.5 FibRefactor.py" #
    2525# End: #
  • doc/papers/concurrency/examples/Format.c

    reef8dfb rbdfc032  
    22
    33typedef struct {
    4         int restart, g, b;
     4        void * next;
    55        char ch;
     6        int g, b;
    67} Fmt;
    78
    89void comain( Fmt * f ) {
    9         static void * states[] = {&&s0, &&s1};
    10         goto *states[f->restart];
    11   s0: f->restart = 1;
     10        if ( __builtin_expect(f->next != 0, 1) ) goto *f->next;
     11        f->next = &&s1;
    1212        for ( ;; ) {
    1313                for ( f->g = 0; f->g < 5; f->g += 1 ) {                 // groups
    1414                        for ( f->b = 0; f->b < 4; f->b += 1 ) {         // blocks
    15                                 do {
    16                                         return;  s1: ;
    17                                 } while ( f->ch == '\n' );                              // ignore
     15                                return;
     16                          s1:;  while ( f->ch == '\n' ) return;         // ignore
    1817                                printf( "%c", f->ch );                                  // print character
    1918                        }
     
    2524
    2625int main() {
    27         Fmt fmt = { 0 };
     26        Fmt fmt = { NULL };
    2827        comain( &fmt );                                                                         // prime
    2928        for ( ;; ) {
  • doc/papers/concurrency/examples/Format.cc

    reef8dfb rbdfc032  
    66                        for ( g = 0; g < 5; g += 1 ) { // groups of 5 blocks
    77                                for ( b = 0; b < 4; b += 1 ) { // blocks of 4 characters
    8                                         for ( ;; ) { // for newline characters
     8//                                      for ( ;; ) { // for newline characters
    99                                                suspend();
    10                                                 if ( ch != '\n' ) break; // ignore newline
    11                                         }
     10//                                              if ( ch != '\n' ) break; // ignore newline
     11//                                      }
    1212//                                      cout << ch; // print character
    1313                                }
     
    3131// Local Variables: //
    3232// tab-width: 4 //
    33 // compile-command: "u++-work -O2 -nodebug Format.cc" //
     33// compile-command: "u++-work -O2 -nodebubg Format.cc" //
    3434// End: //
  • doc/papers/concurrency/examples/Format.cfa

    reef8dfb rbdfc032  
    1111                for ( g = 0; g < 5; g += 1 ) {          // groups of 5 blocks
    1212                        for ( b = 0; b < 4; b += 1 ) {  // blocks of 4 characters
    13                                 do {
     13//                              do {
    1414                                        suspend();
    15                                 } while ( ch == '\n' || ch == '\t' );
     15//                              } while ( ch == '\n' || ch == '\t' );
    1616                                sout | ch;                                      // print character
    1717                        }
  • doc/papers/concurrency/examples/Format.data

    reef8dfb rbdfc032  
    1 abcdefghijklmnop
    2 qrstuvwxyzx
    3 xxxxxxxxxxxxx
     1abcdefghijklmnopqrstuvwxyzxxxxxxxxxxxxxx
  • doc/papers/concurrency/examples/Format.py

    reef8dfb rbdfc032  
    44                        for g in range( 5 ):    # groups of 5 blocks
    55                                for b in range( 4 ): # blocks of 4 characters
    6                                         while True:
    7                                                 ch = (yield) # receive from send
    8                                                 if '\n' not in ch:
    9                                                         break
    10                                         print( ch, end='' ) # receive from send
     6                                        print( (yield), end='' ) # receive from send
    117                                print( '  ', end='' ) # block separator
    128                        print()                                 # group separator
     
    1511                        print()
    1612
    17 input = "abcdefghijklmnop\nqrstuvwx\nyzxxxxxxxxxxxxxx\n"
    18 
    1913fmt = Format()
    2014next( fmt )                                                     # prime generator
    21 for i in input:
    22         fmt.send( i );                          # send to yield
     15for i in range( 41 ):
     16        fmt.send( 'a' );                                # send to yield
    2317
    2418# Local Variables: #
    2519# tab-width: 4 #
    26 # compile-command: "python3.7 Format.py" #
     20# compile-command: "python3.5 Format.py" #
    2721# End: #
  • doc/papers/concurrency/examples/Format1.c

    reef8dfb rbdfc032  
    22
    33typedef struct {
    4         int restart, g, b;
     4        void * next;
    55        char ch;
     6        int g, b;
    67} Fmt;
    78
    89void format( Fmt * f ) {
    9         static void * states[] = {&&s0, &&s1};
    10         goto *states[f->restart];
    11   s0: f->restart = 1;
     10        if ( __builtin_expect(f->next != 0, 1) ) goto *f->next;
     11        f->next = &&s1;
    1212        for ( ;; ) {
    1313                for ( f->g = 0; f->g < 5; f->g += 1 ) {                 // groups
    1414                        for ( f->b = 0; f->b < 4; f->b += 1 ) {         // blocks
    1515                                return;
    16                           s1: if ( f->ch == '\0' ) goto fini;           // EOF ?
     16                          s1: ;
     17                                if ( f->ch == '\0' ) goto fini;                 // EOF ?
    1718                                while ( f->ch == '\n' ) return;                 // ignore
    18 //                              printf( "%c", f->ch );                                  // print character
     19                                printf( "%c", f->ch );                                  // print character
    1920                        }
    20 //                      printf( " " );                                                          // block separator
     21                        printf( " " );                                                          // block separator
    2122                }
    22 //              printf( "\n" );                                                                 // group separator
     23                printf( "\n" );                                                                 // group separator
    2324        }
    24   fini:;
    25 //      if ( f->g != 0 || f->b != 0 ) printf( "\n" );
     25  fini:
     26        if ( f->g != 0 || f->b != 0 ) printf( "\n" );
    2627}
    2728
    2829int main() {
    29         Fmt fmt = { 0 };
     30        Fmt fmt = { NULL };
    3031        format( &fmt );                                                                         // prime
    31         fmt.ch = 'a';
    32         for ( long int i = 0; i < 1000000000; i += 1 ) {
    33 //              scanf( "%c", &fmt.ch );                                                 // direct read into communication variable
    34 //        if ( feof( stdin ) ) break;
     32        for ( ;; ) {
     33                scanf( "%c", &fmt.ch );                                                 // direct read into communication variable
     34          if ( feof( stdin ) ) break;
    3535                format( &fmt );
    3636        }
    37         fmt.ch = '\0';                                                                          // sentential (EOF)
     37        fmt.ch = '\0';
    3838        format( &fmt );
    3939}
  • doc/papers/concurrency/examples/PingPong.c

    reef8dfb rbdfc032  
    22
    33typedef struct PingPong {
    4         int restart;                                                                            // style 1
     4        const char * name;
    55        int N, i;
    6         const char * name;
    76        struct PingPong * partner;
    8         void * next;                                                                            // style 2
     7        void * next;
    98} PingPong;
    10 #define PPCtor( name, N ) { 0, N, 0, name, NULL, NULL }
    11 
     9#define PPCtor( name, N ) { name, N, 0, NULL, NULL }
    1210void comain( PingPong * pp ) __attribute__(( noinline ));
    1311void comain( PingPong * pp ) {
     12        if ( __builtin_expect(pp->next != 0, 1) ) goto *pp->next;
    1413#if 0
    15         if ( __builtin_expect(pp->next != 0, 1) ) goto *pp->next;
     14        pp->next = &&here;
     15                asm( "mov  %0,%%rdi" : "=m" (pp) );
     16                asm( "mov  %rdi,%rax" );
     17#ifndef OPT
     18#ifdef PRINT
     19                asm( "add  $16, %rsp" );
     20#endif // PRINT
     21                asm( "popq %rbp" );
     22#endif // ! OPT
     23
     24#ifdef OPT
     25#ifdef PRINT
     26                asm( "popq %rbx" );
     27#endif // PRINT
     28#endif // OPT
     29                asm( "jmp  comain" );
     30  here: ;
     31#endif // 0
     32
    1633        pp->next = &&cycle;
    1734        for ( ; pp->i < pp->N; pp->i += 1 ) {
     
    3653          cycle: ;
    3754        } // for
    38 #endif // 0
    39 
    40 #if 1
    41         static void * states[] = {&&s0, &&s1};
    42         goto *states[pp->restart];
    43   s0: pp->restart = 1;
    44         for ( ; pp->i < pp->N; pp->i += 1 ) {
    45 #ifdef PRINT
    46                 printf( "%s %d\n", pp->name, pp->i );
    47 #endif // PRINT
    48                 asm( "mov  %0,%%rdi" : "=m" (pp->partner) );
    49                 asm( "mov  %rdi,%rax" );
    50 #ifndef OPT
    51 #ifdef PRINT
    52                 asm( "add  $16, %rsp" );
    53 #endif // PRINT
    54                 asm( "popq %rbp" );
    55 #endif // ! OPT
    56 
    57 #ifdef OPT
    58 #ifdef PRINT
    59                 asm( "popq %rbx" );
    60 #endif // PRINT
    61 #endif // OPT
    62                 asm( "jmp  comain" );
    63           s1: ;
    64         } // for
    65 #endif // 0
    6655}
    6756
     
    8170// Local Variables: //
    8271// tab-width: 4 //
    83 // compile-command: "gcc-9 -g -DPRINT PingPong.c" //
     72// compile-command: "gcc-8 -g -DPRINT PingPong.c" //
    8473// End: //
  • doc/papers/concurrency/examples/Pingpong.py

    reef8dfb rbdfc032  
    11def PingPong( name, N ):
    2         partner = yield                         # get partner
    3         yield                                           # resume scheduler
     2        partner = (yield)           # get partner
     3        yield                       # resume scheduler
    44        for i in range( N ):
    55                print( name )
    6                 yield partner                   # execute next
     6                yield partner           # execute next
    77        print( "end", name )
    88
    99def Scheduler():
    10         n = yield                                       # starting coroutine
    11         try:
    12                 while True:
    13                         n = next( n )           # schedule coroutine
    14         except StopIteration:
    15                 pass
     10        n = (yield)                 # starting coroutine
     11        while True:
     12                n = next( n )           # schedule coroutine
    1613
    1714pi = PingPong( "ping", 5 )
    1815po = PingPong( "pong", 5 )
    19 next( pi )                                              # prime
    20 pi.send( po )                                   # send partner
    21 next( po )                                              # prime
    22 po.send( pi )                                   # send partner
     16next( pi )                      # prime
     17pi.send( po )                   # send partner
     18next( po )                      # prime
     19po.send( pi )                   # send partner
    2320
    2421s = Scheduler();
    25 next( s )                                               # prime
     22next( s )                       # prime
    2623try:
    2724        s.send( pi )                            # start cycle
    28 except StopIteration:                   # scheduler stopped
    29         pass
     25except StopIteration:
     26        print( "scheduler stop" )
    3027print( "stop" )
    3128
    3229# Local Variables: #
    3330# tab-width: 4 #
    34 # compile-command: "python3.7 Pingpong.py" #
     31# compile-command: "python3.5 Pingpong.py" #
    3532# End: #
  • doc/papers/concurrency/examples/ProdCons.py

    reef8dfb rbdfc032  
    11def Prod( N ):
    2         cons = yield                            # get cons
    3         yield                                           # resume scheduler
     2        cons = (yield)              # get cons
     3        yield                       # resume scheduler
    44        for i in range( N ):
    55                print( "prod" )
    6                 yield cons                              # execute next
     6                yield cons              # execute next
    77        print( "end", "prod" )
    88
    99def Cons( N ):
    10         prod = yield                            # get prod
    11         yield                                           # resume scheduler
     10        prod = (yield)              # get prod
     11        yield                       # resume scheduler
    1212        for i in range( N ):
    1313                print( "cons" )
    14                 yield prod                              # execute next
     14                yield prod              # execute next
    1515        print( "end", "cons" )
    1616
    1717def Scheduler():
    18         n = yield                                       # starting coroutine
    19         try:
    20                 while True:
    21                         n = next( n )           # schedule coroutine
    22         except StopIteration:
    23                 pass
     18        n = (yield)                 # starting coroutine
     19        while True:
     20                n = next( n )           # schedule coroutine
    2421
    2522prod = Prod( 5 )
    2623cons = Cons( 5 )
    27 next( prod )                                    # prime
    28 prod.send( cons )                               # send cons
    29 next( cons )                                    # prime
    30 cons.send( prod )                               # send prod
     24next( prod )                    # prime
     25prod.send( cons )               # send cons
     26next( cons )                    # prime
     27cons.send( prod )               # send prod
    3128
    3229s = Scheduler();
    33 next( s )                                               # prime
     30next( s )                       # prime
    3431try:
    3532        s.send( prod )                          # start cycle
    36 except StopIteration:                   # scheduler stopped
    37         pass
     33except StopIteration:
     34        print( "scheduler stop" )
    3835print( "stop" )
    3936
    4037# Local Variables: #
    4138# tab-width: 4 #
    42 # compile-command: "python3.7 ProdCons.py" #
     39# compile-command: "python3.5 ProdCons.py" #
    4340# End: #
  • doc/papers/concurrency/examples/Refactor.py

    reef8dfb rbdfc032  
    2626# Local Variables: #
    2727# tab-width: 4 #
    28 # compile-command: "python3.7 Refactor.py" #
     28# compile-command: "python3.5 Refactor.py" #
    2929# End: #
  • doc/papers/concurrency/figures/FullCoroutinePhases.fig

    reef8dfb rbdfc032  
    88-2
    991200 2
    10 5 1 0 1 0 7 100 0 -1 0.000 0 0 1 0 5175.000 2437.500 4875 1875 5175 1800 5475 1875
     105 1 0 1 0 7 100 0 -1 0.000 0 0 1 0 4575.000 2437.500 4275 1875 4575 1800 4875 1875
    1111        1 1 1.00 45.00 90.00
    12 5 1 0 1 0 7 100 0 -1 0.000 0 0 1 0 5175.000 1537.500 5475 2100 5175 2175 4875 2100
     125 1 0 1 0 7 100 0 -1 0.000 0 0 1 0 4575.000 1537.500 4875 2100 4575 2175 4275 2100
    1313        1 1 1.00 45.00 90.00
    14 5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 4807.500 1642.500 4725 1425 4575 1650 4800 1875
     145 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 4207.500 1642.500 4125 1425 3975 1650 4200 1875
    1515        1 1 1.00 45.00 90.00
    16 6 1575 1575 2700 2025
    17162 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
    1817        1 1 1.00 45.00 90.00
     
    2120        1 1 1.00 45.00 90.00
    2221         2175 1575 2400 1800
     222 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
     23        1 1 1.00 45.00 90.00
     24         3300 1575 3300 1800
     252 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
     26        1 1 1.00 45.00 90.00
     27         3300 2025 3300 2250
     284 1 0 100 0 0 10 0.0000 2 105 555 2100 1200 creation\001
    23294 1 0 100 0 4 10 0.0000 2 165 300 1725 1950 ping\001
    24304 1 0 100 0 4 10 0.0000 2 135 360 2475 1950 pong\001
    25 -6
    26 6 3075 1575 4200 2025
    27 6 3075 1575 4200 2025
    28 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
    29         1 1 1.00 45.00 90.00
    30          3525 1575 3300 1800
    31 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
    32         1 1 1.00 45.00 90.00
    33          3675 1575 3900 1800
    34 4 1 0 100 0 4 10 0.0000 2 165 300 3225 1950 ping\001
    35 4 1 0 100 0 4 10 0.0000 2 135 360 3975 1950 pong\001
    36 -6
    37 -6
     314 1 0 100 0 4 10 0.0000 2 165 300 3300 1950 ping\001
     324 1 0 100 0 4 10 0.0000 2 135 360 3300 2400 pong\001
     334 1 0 100 0 0 10 0.0000 2 105 675 4575 1200 execution\001
     344 1 0 100 0 4 10 0.0000 2 165 300 4275 2025 ping\001
     354 1 0 100 0 4 10 0.0000 2 135 360 4875 2025 pong\001
     364 1 0 100 0 0 10 0.0000 2 90 420 3300 1200 starter\001
    38374 1 0 100 0 4 10 0.0000 2 165 705 2100 1500 pgm main\001
    39 4 1 0 100 0 4 10 0.0000 2 165 705 3600 1500 pgm main\001
    40 4 1 0 100 0 4 10 0.0000 2 165 300 4875 2025 ping\001
    41 4 1 0 100 0 4 10 0.0000 2 135 360 5475 2025 pong\001
    42 4 1 0 100 0 4 10 0.0000 2 165 705 5100 1500 pgm main\001
    43 4 1 0 100 0 2 10 0.0000 2 105 540 2100 1275 creator\001
    44 4 1 0 100 0 2 10 0.0000 2 105 495 3600 1275 starter\001
    45 4 1 0 100 0 2 10 0.0000 2 105 690 5175 1275 execution\001
     384 1 0 100 0 4 10 0.0000 2 165 705 3300 1500 pgm main\001
     394 1 0 100 0 4 10 0.0000 2 165 705 4500 1500 pgm main\001
  • doc/papers/concurrency/figures/RunTimeStructure.fig

    reef8dfb rbdfc032  
    88-2
    991200 2
    10 6 3255 2475 3555 2625
    11 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 3330 2550 30 30 3330 2550 3360 2580
    12 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 3435 2550 30 30 3435 2550 3465 2580
     106 3855 2775 4155 2925
     111 3 0 1 0 0 0 0 0 0.000 1 0.0000 3930 2850 30 30 3930 2850 3960 2880
     121 3 0 1 0 0 0 0 0 0.000 1 0.0000 4035 2850 30 30 4035 2850 4065 2880
    1313-6
    14 6 4155 3225 4455 3375
    15 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 4230 3300 30 30 4230 3300 4260 3330
    16 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 4335 3300 30 30 4335 3300 4365 3330
     146 4755 3525 5055 3675
     151 3 0 1 0 0 0 0 0 0.000 1 0.0000 4830 3600 30 30 4830 3600 4860 3630
     161 3 0 1 0 0 0 0 0 0.000 1 0.0000 4935 3600 30 30 4935 3600 4965 3630
    1717-6
    18 6 4050 2475 4350 2625
    19 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4125 2550 15 15 4125 2550 4140 2565
    20 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4200 2550 15 15 4200 2550 4215 2565
    21 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4275 2550 15 15 4275 2550 4290 2565
     186 4650 2775 4950 2925
     191 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4725 2850 15 15 4725 2850 4740 2865
     201 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4800 2850 15 15 4800 2850 4815 2865
     211 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4875 2850 15 15 4875 2850 4890 2865
    2222-6
    23 6 2625 2100 2925 2250
    24 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 2700 2175 15 15 2700 2175 2715 2190
    25 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 2775 2175 15 15 2775 2175 2790 2190
    26 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 2850 2175 15 15 2850 2175 2865 2190
     236 3225 2400 3525 2550
     241 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3300 2475 15 15 3300 2475 3315 2490
     251 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3375 2475 15 15 3375 2475 3390 2490
     261 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3450 2475 15 15 3450 2475 3465 2490
    2727-6
    28 6 4875 3150 5025 3450
    29 1 3 0 1 -1 -1 0 0 20 0.000 1 4.7120 4950 3225 15 15 4950 3225 4935 3240
    30 1 3 0 1 -1 -1 0 0 20 0.000 1 4.7120 4950 3300 15 15 4950 3300 4935 3315
    31 1 3 0 1 -1 -1 0 0 20 0.000 1 4.7120 4950 3375 15 15 4950 3375 4935 3390
     286 5475 3450 5625 3750
     291 3 0 1 -1 -1 0 0 20 0.000 1 4.7120 5550 3525 15 15 5550 3525 5535 3540
     301 3 0 1 -1 -1 0 0 20 0.000 1 4.7120 5550 3600 15 15 5550 3600 5535 3615
     311 3 0 1 -1 -1 0 0 20 0.000 1 4.7120 5550 3675 15 15 5550 3675 5535 3690
    3232-6
    33 6 3675 3225 3975 3375
    34 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3750 3300 15 15 3750 3300 3765 3315
    35 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3825 3300 15 15 3825 3300 3840 3315
    36 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3900 3300 15 15 3900 3300 3915 3315
     336 4275 3525 4575 3675
     341 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4350 3600 15 15 4350 3600 4365 3615
     351 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4425 3600 15 15 4425 3600 4440 3615
     361 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4500 3600 15 15 4500 3600 4515 3615
    3737-6
    38 6 2625 3825 4050 4125
    39 6 3750 3900 4050 4050
    40 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3825 3975 15 15 3825 3975 3840 3990
    41 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3900 3975 15 15 3900 3975 3915 3990
    42 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3975 3975 15 15 3975 3975 3990 3990
     386 2175 4650 7050 4950
     391 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 4860
     401 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4200 4800 150 75 4200 4800 4350 4875
     411 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3275 4800 100 100 3275 4800 3375 4800
     422 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
     43         5400 4950 5400 4725 5175 4725 5175 4950 5400 4950
     442 2 1 1 -1 -1 0 0 -1 3.000 0 0 0 0 0 5
     45         6525 4950 6300 4950 6300 4725 6525 4725 6525 4950
     464 0 -1 0 0 0 10 0.0000 2 105 450 6600 4875 cluster\001
     474 0 -1 0 0 0 10 0.0000 2 105 660 5475 4875 processor\001
     484 0 -1 0 0 0 10 0.0000 2 105 555 4425 4875 monitor\001
     494 0 -1 0 0 0 10 0.0000 2 120 270 3450 4875 task\001
     504 0 -1 0 0 0 10 0.0000 2 105 660 2325 4875 coroutine\001
    4351-6
    44 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 2850 3975 225 150 2850 3975 3075 4125
    45 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3450 3975 225 150 3450 3975 3675 4125
     526 3450 1275 3750 1425
     531 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3525 1350 15 15 3525 1350 3540 1365
     541 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3600 1350 15 15 3600 1350 3615 1365
     551 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3675 1350 15 15 3675 1350 3690 1365
    4656-6
    47 6 6075 3825 6900 4125
    48 6 6600 3900 6900 4050
    49 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 6675 3975 15 15 6675 3975 6690 3990
    50 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 6750 3975 15 15 6750 3975 6765 3990
    51 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 6825 3975 15 15 6825 3975 6840 3990
     576 5550 1275 5850 1425
     581 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 5625 1350 15 15 5625 1350 5640 1365
     591 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 5700 1350 15 15 5700 1350 5715 1365
     601 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 5775 1350 15 15 5775 1350 5790 1365
    5261-6
    53 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6300 3975 225 150 6300 3975 6525 4125
    54 -6
    55 6 6075 3225 7425 3675
     621 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 5550 2625 150 150 5550 2625 5700 2625
     631 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 5550 3225 150 150 5550 3225 5700 3225
     641 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 5550 3975 150 150 5550 3975 5700 3975
     651 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3525 2850 150 150 3525 2850 3675 2850
     661 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4200 2475 150 150 4200 2475 4350 2475
     671 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4425 2850 150 150 4425 2850 4575 2850
     681 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 2475 150 150 4650 2475 4800 2475
     691 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3525 3600 150 150 3525 3600 3675 3600
     701 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3975 3600 150 150 3975 3600 4125 3600
     711 3 0 1 0 0 0 0 0 0.000 1 0.0000 3525 3600 30 30 3525 3600 3555 3630
     721 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3750 2475 150 150 3750 2475 3900 2625
     731 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4875 3600 150 150 4875 3600 5025 3750
     741 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3975 2850 150 150 3975 2850 4125 2850
     751 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 7200 2775 150 150 7200 2775 7350 2775
     761 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 1350 225 150 4650 1350 4875 1500
     771 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 5250 1350 225 150 5250 1350 5475 1500
     781 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 1350 225 150 4050 1350 4275 1500
     792 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
     80         2400 4200 2400 3750 1950 3750 1950 4200 2400 4200
     812 2 1 1 -1 -1 0 0 -1 4.000 0 0 0 0 0 5
     82         6300 4500 6300 1800 3000 1800 3000 4500 6300 4500
     832 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
     84         5775 2850 5775 2400 5325 2400 5325 2850 5775 2850
     852 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
     86         5775 4200 5775 3750 5325 3750 5325 4200 5775 4200
    56872 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    5788        1 1 1.00 45.00 90.00
    58          6075 3450 6375 3450
     89         5175 3975 5325 3975
    59902 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    6091        1 1 1.00 45.00 90.00
    61          6525 3450 6750 3450
    62 2 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    63          7200 3675 7200 3225 6750 3225 6750 3675 7200 3675
     92         5175 3225 5325 3225
    64932 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    6594        1 1 1.00 45.00 90.00
    66          7200 3450 7425 3450
    67 -6
    68 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4950 2325 150 150 4950 2325 5100 2325
    69 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4950 2925 150 150 4950 2925 5100 2925
    70 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4950 3675 150 150 4950 3675 5100 3675
    71 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 2925 2550 150 150 2925 2550 3075 2550
    72 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3600 2175 150 150 3600 2175 3750 2175
    73 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3825 2550 150 150 3825 2550 3975 2550
    74 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 2175 150 150 4050 2175 4200 2175
    75 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3375 3300 150 150 3375 3300 3525 3300
    76 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 2925 3300 30 30 2925 3300 2955 3330
    77 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3150 2175 150 150 3150 2175 3300 2325
    78 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4275 3300 150 150 4275 3300 4425 3450
    79 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3375 2550 150 150 3375 2550 3525 2550
    80 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6600 2475 150 150 6600 2475 6750 2475
    81 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 1650 4530 30 30 1650 4530 1680 4560
    82 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 6600 2475 30 30 6600 2475 6630 2505
    83 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 2925 3300 150 150 2925 3300 3075 3300
    84 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3275 4500 100 100 3275 4500 3375 4500
    85 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 4500 150 75 4050 4500 4200 4575
    86 2 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    87          1800 3900 1800 3450 1350 3450 1350 3900 1800 3900
    88 2 2 1 1 -1 -1 0 0 -1 4.000 0 0 0 0 0 5
    89          5700 4200 5700 1500 2400 1500 2400 4200 5700 4200
    90 2 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    91          5175 2550 5175 2100 4725 2100 4725 2550 5175 2550
    92 2 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    93          5175 3900 5175 3450 4725 3450 4725 3900 5175 3900
     95         5175 2625 5325 2625
    94962 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    9597        1 1 1.00 45.00 90.00
    96          4575 3675 4725 3675
     98         5775 3975 5925 3975
    97992 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    98100        1 1 1.00 45.00 90.00
    99          4575 2925 4725 2925
     101         5775 3225 5925 3225
    1001022 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    101103        1 1 1.00 45.00 90.00
    102          4575 2325 4725 2325
     104         5775 2625 5925 2625
     1052 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2
     106         5175 3975 5175 2625
    1031072 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    104108        1 1 1.00 45.00 90.00
    105          5175 3675 5325 3675
     109         5925 3975 5925 2025
    1061102 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    107111        1 1 1.00 45.00 90.00
    108          5175 2925 5325 2925
     112         5925 3750 6225 3750
    1091132 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    110114        1 1 1.00 45.00 90.00
    111          5175 2325 5325 2325
     115         3450 2625 3225 2625
     1162 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 3
     117        1 1 1.00 45.00 90.00
     118         5925 2025 4200 2025 4200 2250
    1121192 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2
    113          4575 3675 4575 2325
     120         3225 2625 3225 3600
    1141212 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    115122        1 1 1.00 45.00 90.00
    116          5325 3675 5325 1725
     123         3075 3600 3375 3600
    1171242 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    118125        1 1 1.00 45.00 90.00
    119          5325 3450 5625 3450
     126         3675 3600 3825 3600
    1201272 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    121128        1 1 1.00 45.00 90.00
    122          2850 2325 2625 2325
    123 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 3
    124         1 1 1.00 45.00 90.00
    125          5325 1725 3600 1725 3600 1950
    126 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2
    127          2625 2325 2625 3300
     129         4125 3600 4275 3600
    1281302 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    129131        1 1 1.00 45.00 90.00
    130          2475 3300 2775 3300
     132         4575 3600 4725 3600
    1311332 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    132134        1 1 1.00 45.00 90.00
    133          3075 3300 3225 3300
     135         5025 3600 5175 3600
     1362 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
     137         5775 3450 5775 3000 5325 3000 5325 3450 5775 3450
     1382 2 1 1 -1 -1 0 0 -1 4.000 0 0 0 0 0 5
     139         8100 4500 8100 1800 6600 1800 6600 4500 8100 4500
    1341402 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    135141        1 1 1.00 45.00 90.00
    136          3525 3300 3675 3300
     142         6675 3975 6975 3975
    1371432 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    138144        1 1 1.00 45.00 90.00
    139          3975 3300 4125 3300
     145         7050 2775 6825 2775
     1462 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2
     147         6825 2775 6825 3975
    1401482 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    141149        1 1 1.00 45.00 90.00
    142          4425 3300 4575 3300
     150         7125 3975 7350 3975
    1431512 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    144          5175 3150 5175 2700 4725 2700 4725 3150 5175 3150
    145 2 2 1 1 -1 -1 0 0 -1 4.000 0 0 0 0 0 5
    146          7500 4200 7500 1500 6000 1500 6000 4200 7500 4200
     152         7800 4200 7800 3750 7350 3750 7350 4200 7800 4200
    1471532 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    148154        1 1 1.00 45.00 90.00
    149          6450 2475 6225 2475
    150 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2
    151          6225 2475 6225 3450
     155         7800 3975 8025 3975
    1521562 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 4
    153157        1 1 1.00 45.00 90.00
    154          7275 3450 7275 2025 6600 2025 6600 2250
    155 2 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    156          5250 4650 5250 4425 5025 4425 5025 4650 5250 4650
    157 2 2 1 1 -1 -1 0 0 -1 3.000 0 0 0 0 0 5
    158          6375 4650 6150 4650 6150 4425 6375 4425 6375 4650
    159 4 1 -1 0 0 0 10 0.0000 2 105 720 4950 4125 Processors\001
    160 4 1 -1 0 0 0 10 0.0000 2 120 1005 3600 2925 Blocked Tasks\001
    161 4 1 -1 0 0 0 10 0.0000 2 150 870 3600 3675 Ready Tasks\001
    162 4 1 -1 0 0 0 10 0.0000 2 135 1095 6750 1425 Other Cluster(s)\001
    163 4 1 -1 0 0 0 10 0.0000 2 105 840 4050 1425 User Cluster\001
    164 4 1 -1 0 0 0 10 0.0000 2 150 615 1575 3375 Manager\001
    165 4 1 -1 0 0 0 10 0.0000 2 105 990 1575 3225 Discrete-event\001
    166 4 1 -1 0 0 0 10 0.0000 2 135 795 1575 4050 preemption\001
    167 4 0 -1 0 0 0 10 0.0000 2 150 1365 1725 4575 generator/coroutine\001
    168 4 0 -1 0 0 0 10 0.0000 2 120 270 3450 4575 task\001
    169 4 0 -1 0 0 0 10 0.0000 2 105 450 6450 4575 cluster\001
    170 4 0 -1 0 0 0 10 0.0000 2 105 660 5325 4575 processor\001
    171 4 0 -1 0 0 0 10 0.0000 2 105 555 4275 4575 monitor\001
     158         7875 3975 7875 2325 7200 2325 7200 2550
     1594 1 -1 0 0 0 10 0.0000 2 105 720 5550 4425 Processors\001
     1604 1 -1 0 0 0 10 0.0000 2 120 1005 4200 3225 Blocked Tasks\001
     1614 1 -1 0 0 0 10 0.0000 2 150 870 4200 3975 Ready Tasks\001
     1624 1 -1 0 0 0 10 0.0000 2 135 1095 7350 1725 Other Cluster(s)\001
     1634 1 -1 0 0 0 10 0.0000 2 105 840 4650 1725 User Cluster\001
     1644 1 -1 0 0 0 10 0.0000 2 150 615 2175 3675 Manager\001
     1654 1 -1 0 0 0 10 0.0000 2 105 990 2175 3525 Discrete-event\001
     1664 1 -1 0 0 0 10 0.0000 2 135 795 2175 4350 preemption\001
  • doc/papers/concurrency/mail

    reef8dfb rbdfc032  
    1010Dear Dr Buhr,
    1111
    12 Your manuscript entitled "Concurrency in Cforall" has been received by Software:
     12Your manuscript entitled "Concurrency in Cāˆ€" has been received by Software:
    1313Practice and Experience. It will be given full consideration for publication in
    1414the journal.
     
    4141Dear Dr Buhr,
    4242
    43 Many thanks for submitting SPE-18-0205 entitled "Concurrency in Cforall" to Software: Practice and Experience.
     43Many thanks for submitting SPE-18-0205 entitled "Concurrency in Cāˆ€" to Software: Practice and Experience.
    4444
    4545In view of the comments of the referees found at the bottom of this letter, I cannot accept your paper for publication in Software: Practice and Experience. I hope that you find the referees' very detailed comments helpful.
  • doc/papers/concurrency/mail2

    reef8dfb rbdfc032  
    2222Software: Practice and Experience Editorial Office
    2323
    24 
    25 
    26 Date: Tue, 12 Nov 2019 22:25:17 +0000
    27 From: Richard Jones <onbehalfof@manuscriptcentral.com>
    28 Reply-To: R.E.Jones@kent.ac.uk
    29 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
    30 Subject: Software: Practice and Experience - Decision on Manuscript ID
    31  SPE-19-0219
    32 
    33 12-Nov-2019
    34 
    35 Dear Dr Buhr,
    36 
    37 Many thanks for submitting SPE-19-0219 entitled "Advanced Control-flow and Concurrency in Cforall" to Software: Practice and Experience. The paper has now been reviewed and the comments of the referees are included at the bottom of this letter.
    38 
    39 The decision on this paper is that it requires substantial further work is required. The referees have a number of substantial concerns. All the reviewers found the submission very hard to read; two of the reviewers state that it needs very substantial restructuring. These concerns must be addressed before your submission can be considered further.
    40 
    41 A revised version of your manuscript that takes into account the comments of the referees will be reconsidered for publication.
    42 
    43 Please note that submitting a revision of your manuscript does not guarantee eventual acceptance, and that your revision will be subject to re-review by the referees before a decision is rendered.
    44 
    45 You have 90 days from the date of this email to submit your revision. If you are unable to complete the revision within this time, please contact me to request an extension.
    46 
    47 You can upload your revised manuscript and submit it through your Author Center. Log into https://mc.manuscriptcentral.com/spe  and enter your Author Center, where you will find your manuscript title listed under "Manuscripts with Decisions".
    48 
    49 When submitting your revised manuscript, you will be able to respond to the comments made by the referee(s) in the space provided.  You can use this space to document any changes you make to the original manuscript.
    50 
    51 If you feel that your paper could benefit from English language polishing, you may wish to consider having your paper professionally edited for English language by a service such as Wiley's at http://wileyeditingservices.com. Please note that while this service will greatly improve the readability of your paper, it does not guarantee acceptance of your paper by the journal.
    52  
    53 Once again, thank you for submitting your manuscript to Software: Practice and Experience and I look forward to receiving your revision.
    54 
    55 
    56 Sincerely,
    57 
    58 Prof. Richard Jones
    59 Software: Practice and Experience
    60 R.E.Jones@kent.ac.uk
    61 
    62 
    63 Referee(s)' Comments to Author:
    64 
    65 Reviewing: 1
    66 
    67 Comments to the Author
    68 This article presents the design and rationale behind the various
    69 threading and synchronization mechanisms of C-forall, a new low-level
    70 programming language.  This paper is very similar to a companion paper
    71 which I have also received: as the papers are similar, so will these
    72 reviews be --- in particular any general comments from the other
    73 review apply to this paper also.
    74 
    75 As far as I can tell, the article contains three main ideas: an
    76 asynchronous execution / threading model; a model for monitors to
    77 provide mutual exclusion; and an implementation.  The first two ideas
    78 are drawn together in Table 1: unfortunately this is on page 25 of 30
    79 pages of text. Implementation choices and descriptions are scattered
    80 throughout the paper - and the sectioning of the paper seems almost
    81 arbitrary.
    82 
    83 The article is about its contributions.  Simply adding feature X to
    84 language Y isn't by itself a contribution, (when feature X isn't
    85 already a contribution).  The contribution can be in the design: the
    86 motivation, the space of potential design options, the particular
    87 design chosen and the rationale for that choice, or the resulting
    88 performance.  For example: why support two kinds of generators as well
    89 as user-level threads?  Why support both low and high level
    90 synchronization constructs?  Similarly I would have found the article
    91 easier to follow if it was written top down, presenting the design
    92 principles, present the space of language features, justify chosen
    93 language features (and rationale) and those excluded, and then present
    94 implementation, and performance.
    95 
    96 Then the writing of the article is often hard to follow, to say the
    97 least. Two examples: section 3 "stateful functions" - I've some idea
    98 what that is (a function with Algol's "own" or C's "static" variables?
    99 but in fact the paper has a rather more specific idea than that. The
    100 top of page 3 throws a whole lot of defintions at the reader
    101 "generator" "coroutine" "stackful" "stackless" "symmetric"
    102 "asymmetric" without every stopping to define each one --- but then in
    103 footnote "C" takes the time to explain what C's "main" function is?  I
    104 cannot imagine a reader of this paper who doesn't know what "main" is
    105 in C; especially if they understand the other concepts already
    106 presented in the paper.  The start of section 3 then does the same
    107 thing: putting up a whole lot of definitions, making distinctions and
    108 comparisons, even talking about some runtime details, but the critical
    109 definition of a monitor doesn't appear until three pages later, at the
    110 start of section 5 on p15, lines 29-34 are a good, clear, description
    111 of what a monitor actually is.  That needs to come first, rather than
    112 being buried again after two sections of comparisons, discussions,
    113 implementations, and options that are ungrounded because they haven't
    114 told the reader what they are actually talking about.  First tell the
    115 reader what something is, then how they might use it (as programmers:
    116 what are the rules and restrictions) and only then start comparison
    117 with other things, other approaches, other languages, or
    118 implementations.
    119 
    120 The description of the implementation is similarly lost in the trees
    121 without ever really seeing the wood. Figure 19 is crucial here, but
    122 it's pretty much at the end of the paper, and comments about
    123 implementations are threaded throughout the paper without the context
    124 (fig 19) to understand what's going on.   The protocol for performance
    125 testing may just about suffice for C (although is N constantly ten
    126 million, or does it vary for each benchmark) but such evaluation isn't
    127 appropriate for garbage-collected or JITTed languages like Java or Go.
    128 
    129 other comments working through the paper - these are mostly low level
    130 and are certainly not comprehensive.
    131 
    132 p1 only a subset of C-forall extensions?
    133 
    134 p1 "has features often associated with object-oriented programming
    135 languages, such as constructors, destructors, virtuals and simple
    136 inheritance."   There's no need to quibble about this. Once a language
    137 has inheritance, it's hard to claim it's not object-oriented.
    138 
    139 
    140 p2 barging? signals-as-hints?
    141 
    142 p3 start your discussion of generations with a simple example of a
    143 C-forall generator.  Fig 1(b) might do: but put it inline instead of
    144 the python example - and explain the key rules and restrictions on the
    145 construct.  Then don't even start to compare with coroutines until
    146 you've presented, described and explained your coroutines...
    147 p3 I'd probably leave out the various "C" versions unless there are
    148 key points to make you can't make in C-forall. All the alternatives
    149 are just confusing.
    150 
    151 
    152 p4 but what's that "with" in Fig 1(B)
    153 
    154 p5 start with the high level features of C-forall generators...
    155 
    156 p5 why is the paper explaining networking protocols?
    157 
    158 p7 lines 1-9 (transforming generator to coroutine - why would I do any
    159 of this? Why would I want one instead of the other (do not use "stack"
    160 in your answer!)
    161 
    162 p10 last para "A coroutine must retain its last resumer to suspend
    163 back because the resumer is on a different stack. These reverse
    164 pointers allow suspend to cycle backwards, "  I've no idea what is
    165 going on here?  why should I care?  Shouldn't I just be using threads
    166 instead?  why not?
    167 
    168 p16 for the same reasons - what reasons?
    169 
    170 p17 if the multiple-monitor entry procedure really is novel, write a
    171 paper about that, and only about that.
    172 
    173 p23 "Loose Object Definitions" - no idea what that means.  in that
    174 section: you can't leave out JS-style dynamic properties.  Even in
    175 OOLs that (one way or another) allow separate definitions of methods
    176 (like Objective-C, Swift, Ruby, C#) at any time a runtime class has a
    177 fixed definition.  Quite why the detail about bit mask implementation
    178 is here anyway, I've no idea.
    179 
    180 p25 this cluster isn't a CLU cluster then?
    181 
    182 * conclusion should conclude the paper, not the related.
    183 
    184 
    185 Reviewing: 2
    186 
    187 Comments to the Author
    188 This paper describes the concurrency features of an extension of C (whose name I will write as "C\/" here, for convenience), including much design-level discussion of the coroutine- and monitor-based features and some microbenchmarks exploring the current implementation's performance. The key message of the latter is that the system's concurrency abstractions are much lighter-weight than the threading found in mainstream C or Java implementations.
    189 
    190 There is much description of the system and its details, but nothing about (non-artificial) uses of it. Although the microbenchmark data is encouraging, arguably not enough practical experience with the system has been reported here to say much about either its usability advantages or its performance.
    191 
    192 As such, the main contribution of the paper seem to be to document the existence of the described system and to provide a detailed design rationale and (partial) tutorial. I believe that could be of interest to some readers, so an acceptable manuscript is lurking in here somewhere.
    193 
    194 Unfortunately, at present the writing style is somewhere between unclear and infuriating. It omits to define terms; it uses needlessly many terms for what are apparently (but not clearly) the same things; it interrupts itself rather than deliver the natural consequent of whatever it has just said; and so on. Section 5 is particularly bad in these regards -- see my detailed comments below. Fairly major additional efforts will be needed to turn the present text into a digestible design-and-tutorial document. I suspect that a shorter paper could do this job better than the present manuscript, which is overwrought in parts.
    195 
    196 p2: lines 4--9 are a little sloppy. It is not the languages but their popular implementations which "adopt" the 1:1 kernel threading model.
    197 
    198 line 10: "medium work" -- "medium-sized work"?
    199 
    200 line 18: "is all sequential to the compiler" -- not true in modern compilers, and in 2004 H-J Boehm wrote a tech report describing exactly why ("Threads cannot be implemented as a library", HP Labs).
    201 
    202 line 20: "knows the optimization boundaries" -- I found this vague. What's an example?
    203 
    204 line 31: this paragraph has made a lot of claims. Perhaps forward-reference to the parts of the paper that discuss each one.
    205 
    206 line 33: "so the reader can judge if" -- this reads rather passive-aggressively. Perhaps better: "... to support our argument that..."
    207 
    208 line 41: "a dynamic partitioning mechanism" -- I couldn't tell what this meant
    209 
    210 p3. Presenting concept of a "stateful function" as a new language feature seems odd. In C, functions often have local state thanks to static local variables (or globals, indeed). Of course, that has several limitations. Can you perhaps present your contributions by enumerating these limitations? See also my suggestion below about a possible framing centred on a strawman.
    211 
    212 line 2: "an old idea that is new again" -- this is too oblique
    213 
    214 lines 2--15: I found this to be a word/concept soup. Stacks, closures, generators, stackless stackful, coroutine, symmetric, asymmetric, resume/suspend versus resume/resume... there needs to be a more gradual and structured way to introduce all this, and ideally one that minimises redundancy. Maybe present it as a series of "definitions" each with its own heading, e.g. "A closure is stackless if its local state has statically known fixed size"; "A generator simply means a stackless closure." And so on. Perhaps also strongly introduce the word "activate" as a direct contrast with resume and suspend. These are just a flavour of the sort of changes that might make this paragraph into something readable.
    215 
    216 Continuing the thought: I found it confusing that by these definitinos, a stackful closure is not a stack, even though logically the stack *is* a kind of closure (it is a representation of the current thread's continuation).
    217 
    218 lines 24--27: without explaining what the boost functor types mean, I don't think the point here comes across.
    219 
    220 line 34: "semantically coupled" -- I wasn't surew hat this meant
    221 
    222 p4: the point of Figure 1 (C) was not immediately clear. It seem to be showing how one might "compile down" Figure 1 (B). Or is that Figure 1 (A)?
    223 
    224 It's right that the incidental language features of the system are not front-and-centre, but I'd appreciate some brief glossing of non-C languages features as they appear. Examples are the square bracket notation, the pipe notation and the constructor syntax. These explanations could go in the caption of the figure which first uses them, perhaps. Overall I found the figure captions to be terse, and a missed opportunity to explain clearly what was going on.
    225 
    226 p5 line 23: "This restriction is removed..." -- give us some up-front summary of your contributions and the elements of the language design that will be talked about, so that this isn't an aside. This will reduce the "twisty passages" feeling that characterises much of the paper.
    227 
    228 line 40: "a killer asymmetric generator" -- this is stylistically odd, and the sentence about failures doesn't convincigly argue that C\/ will help with them. Have you any experience writing device drivers using C\/? Or any argument that the kinds of failures can be traced to the "stack-ripping" style that one is forced to use without coroutines? Also, a typo on line 41: "device drives". And saying "Windows/Linux" is sloppy... what does the cited paper actually say?
    229 
    230 p6 lines 13--23: this paragraph is difficult to understand. It seems to be talking about a control-flow pattern roughly equivalent to tail recursion. What is the high-level point, other than that this is possible?
    231 
    232 line 34: "which they call coroutines" -- a better way to make this point is presumably that the C++20 proposal only provides a specialised kind of coroutine, namely generators, despite its use of the more general word.
    233 
    234 line 47: "... due to dynamic stack allocation, execution..." -- this sentence doesn't scan. I suggest adding "and for" in the relevant places where currently there are only commas.
    235 
    236 p8 / Figure 5 (B) -- the GNU C extension of unary "&&" needs to be explained. The whole figure needs a better explanation, in fact.
    237 
    238 p9, lines 1--10: I wasn't sure this stepping-through really added much value. What are the truly important points to note about this code?
    239 
    240 p10: similarly, lines 3--27 again are somewhere between tedious and confusing. I'm sure the motivation and details of "starter semantics" can both be stated much more pithily.
    241 
    242 line 32: "a self-resume does not overwrite the last resumer" -- is this a hack or a defensible principled decision?
    243 
    244 p11: "a common source of errors" -- among beginners or among production code? Presumably the former.
    245 
    246 line 23: "with builtin and library" -- not sure what this means
    247 
    248 lines 31--36: these can be much briefer. The only important point here seems to be that coroutines cannot be copied.
    249 
    250 p12: line 1: what is a "task"? Does it matter?
    251 
    252 line 7: calling it "heap stack" seems to be a recipe for confusion. "Stack-and-heap" might be better, and contrast with "stack-and-VLS" perhaps. When "VLS" is glossed, suggest actually expanding its initials: say "length" not "size".
    253 
    254 line 21: are you saying "cooperative threading" is the same as "non-preemptive scheduling", or that one is a special case (kind) of the other? Both are defensible, but be clear.
    255 
    256 line 27: "mutual exclusion and synchronization" -- the former is a kind of the latter, so I suggest "and other forms of synchronization".
    257 
    258 line 30: "can either be a stackless or stackful" -- stray "a", but also, this seems to be switching from generic/background terminology to C\/-specific terminology.
    259 
    260 An expositional idea occurs: start the paper with a strawman naive/limited realisation of coroutines -- say, Simon Tatham's popular "Coroutines in C" web page -- and identify point by point what the limitations are and how C\/ overcomes them. Currently the presentation is often flat (lacking motivating contrasts) and backwards (stating solutions before problems). The foregoing approach might fix both of these.
    261 
    262 page 13: line 23: it seems a distraction to mention the Python feature here.
    263 
    264 p14 line 5: it seems odd to describe these as "stateless" just because they lack shared mutable state. It means the code itself is even more stateful. Maybe the "stack ripping" argument could usefully be given here.
    265 
    266 line 16: "too restrictive" -- would be good to have a reference to justify this, or at least give a sense of what the state-of-the-art performance in transactional memory systems is (both software and hardware)
    267 
    268 line 22: "simulate monitors" -- what about just *implementing* monitors? isn't that what these systems do? or is the point more about refining them somehow into something more specialised?
    269 
    270 p15: sections 4.1 and 4.2 seem adrift and misplaced. Split them into basic parts (which go earlier) and more advanced parts (e.g. barging, which can be explained later).
    271 
    272 line 31: "acquire/release" -- misses an opportunity to contrast the monitor's "enter/exit" abstraction with the less structured acquire/release of locks.
    273 
    274 p16 line 12: the "implicit" versus "explicit" point is unclear. Is it perhaps about the contract between an opt-in *discipline* and a language-enforced *guarantee*?
    275 
    276 line 28: no need to spend ages dithering about which one is default and which one is the explicit qualifier. Tell us what you decided, briefly justify it, and move on.
    277 
    278 p17: Figure 11: since the main point seems to be to highlight bulk acquire, include a comment which identifies the line where this is happening.
    279 
    280 line 2: "impossible to statically..." -- or dynamically. Doing it dynamically would be perfectly acceptable (locking is a dynamic operation after all)
    281 
    282 "guarantees acquisition order is consistent" -- assuming it's done in a single bulk acquire.
    283 
    284 p18: section 5.3: the text here is a mess. The explanations of "internal" versus "external" scheduling are unclear, and "signals as hints" is not explained. "... can cause thread starvation" -- means including a while loop, or not doing so? "There are three signalling mechanisms.." but the text does not follow that by telling us what they are. My own scribbled attempt at unpicking the internal/external thing: "threads already in the monitor, albeit waiting, have priority over those trying to enter".
    285 
    286 p19: line 3: "empty condition" -- explain that condition variables don't store anything. So being "empty" means that the queue of waiting threads (threads waiting to be signalled that the condition has become true) is empty.
    287 
    288 line 6: "... can be transformed into external scheduling..." -- OK, but give some motivation.
    289 
    290 p20: line 6: "mechnaism"
    291 
    292 lines 16--20: this is dense and can probably only be made clear with an example
    293 
    294 p21 line 21: clarify that nested monitor deadlock was describe earlier (in 5.2). (Is the repetition necessary?)
    295 
    296 line 27: "locks, and by extension monitors" -- this is true but the "by extension" argument is faulty. It is perfectly possible to use locks as a primitive and build a compositional mechanism out of them, e.g. transactions.
    297 
    298 p22 line 2: should say "restructured"
    299 
    300 line 33: "Implementing a fast subset check..." -- make clear that the following section explains how to do this. Restructuring the sections themselves could do this, or noting in the text.
    301 
    302 p23: line 3: "dynamic member adding, eg, JavaScript" -- needs to say "as permitted in JavaScript", and "dynamically adding members" is stylistically better
    303 
    304 p23: line 18: "urgent stack" -- back-reference to where this was explained before
    305 
    306 p24 line 7: I did not understand what was more "direct" about "direct communication". Also, what is a "passive monitor" -- just a monitor, given that monitors are passive by design?
    307 
    308 line 14 / section 5.9: this table was useful and it (or something like it) could be used much earlier on to set the structure of the rest of the paper. The explanation at present is too brief, e.g. I did not really understand the point about cases 7 and 8.
    309 
    310 p25 line 2: instead of casually dropping in a terse explanation for the newly intrdouced term "virtual processor", introduce it properly. Presumably the point is to give a less ambiguous meaning to "thread" by reserving it only for C\/'s green threads.
    311 
    312 Table 1: what does "No / Yes" mean?
    313 
    314 p26 line 15: "transforms user threads into fibres" -- a reference is needed to explain what "fibres" means... guessing it's in the sense of Adya et al.
    315 
    316 line 20: "Microsoft runtime" -- means Windows?
    317 
    318 lines 21--26: don't say "interrupt" to mean "signal", especially not without clear introduction. You can use "POSIX signal" to disambiguate from condition variables' "signal".
    319 
    320 p27 line 3: "frequency is usually long" -- that's a "time period" or "interval", not a frequency
    321 
    322 line 5: the lengthy quotation is not really necessary; just paraphrase the first sentence and move on.
    323 
    324 line 20: "to verify the implementation" -- I don't think that means what is intended
    325 
    326 Tables in section 7 -- too many significant figures. How many overall runs are described? What is N in each case?
    327 
    328 p29 line 2: "to eliminate this cost" -- arguably confusing since nowadays on commodity CPUs most of the benefits of inlining are not to do with call overheads, but from later optimizations enabled as a consequence of the inlining
    329 
    330 line 41: "a hierarchy" -- are they a hierarchy? If so, this could be explained earlier. Also, to say these make up "an integrated set... of control-flow features" verges on the tautologous.
    331 
    332 p30 line 15: "a common case being web servers and XaaS" -- that's two cases
    333 
    334 
    335 Reviewing: 3
    336 
    337 Comments to the Author
    338 # Cforall review
    339 
    340 Overall, I quite enjoyed reading the paper. Cforall has some very interesting ideas. I did have some suggestions that I think would be helpful before final publication. I also left notes on various parts of the paper that I find confusing when reading, in hopes that it may be useful to you.
    341 
    342 ## Summary
    343 
    344 * Expand on the motivations for including both generator and coroutines, vs trying to build one atop the other
    345 * Expand on the motivations for having Why both symmetric and asymettric coroutines?
    346 * Comparison to async-await model adopted by other languages
    347     * C#, JS
    348     * Rust and its async/await model
    349 * Consider performance comparisons against node.js and Rust frameworks
    350 * Discuss performance of monitors vs finer-grained memory models and atomic operations found in other languages
    351 * Why both internal/external scheduling for synchronization?
    352 
    353 ## Generator/coroutines
    354 
    355 In general, this section was clear, but I thought it would be useful to provide a somewhat deeper look into why Cforall opted for the particular combination of features that it offers. I see three main differences from other languages:
    356 
    357 * Generators are not exposed as a "function" that returns a generator object, but rather as a kind of struct, with communication happening via mutable state instead of "return values". That is, the generator must be manually resumed and (if I understood) it is expected to store values that can then later be read (perhaps via methods), instead of having a `yield <Expr>` statement that yields up a value explicitly.
    358 * Both "symmetric" and "asymmetric" generators are supported, instead of only asymmetric.
    359 * Coroutines (multi-frame generators) are an explicit mechanism.
    360 
    361 In most other languages, coroutines are rather built by layering single-frame generators atop one another (e.g., using a mechanism like async-await), and symmetric coroutines are basically not supported. I'd like to see a bit more justification for Cforall including all the above mechanisms -- it seemed like symmetric coroutines were a useful building block for some of the user-space threading and custom scheduler mechanisms that were briefly mentioned later in the paper.
    362 
    363 In the discussion of coroutines, I would have expected a bit more of a comparison to the async-await mechanism offered in other languages. Certainly the semantics of async-await in JavaScript implies significantly more overhead (because each async fn is a distinct heap object). [Rust's approach avoids this overhead][zc], however, and might be worthy of a comparison (see the Performance section).
    364 
    365 ## Locks and threading
    366 
    367 ### Comparison to atomics overlooks performance
    368 
    369 There are several sections in the paper that compare against atomics -- for example, on page 15, the paper shows a simple monitor that encapsulates an integer and compares that to C++ atomics. Later, the paper compares the simplicity of monitors against the `volatile` quantifier from Java. The conclusion in section 8 also revisits this point.
    370 
    371 While I agree that monitors are simpler, they are obviously also significantly different from a performance perspective -- the paper doesn't seem to address this at all. It's plausible that (e.g.) the `Aint` monitor type described in the paper can be compiled and mapped to the specialized instructions offered by hardware, but I didn't see any mention of how this would be done. There is also no mention of the more nuanced memory ordering relations offered by C++11 and how one might achieve similar performance characteristics in Cforall (perhaps the answer is that one simply doesn't need to; I think that's defensible, but worth stating explicitly).
    372 
    373 ### Justification for external scheduling feels lacking
    374 
    375 Cforall includes both internal and external scheduling; I found the explanation for the external scheduling mechanism to be lacking in justification. Why include both mechanisms when most languages seem to make do with only internal scheduling? It would be useful to show some scenarios where external scheduling is truly more powerful.
    376 
    377 I would have liked to see some more discussion of external scheduling and how it  interacts with software engineering best practices. It seems somewhat similar to AOP in certain regards. It seems to add a bit of "extra semantics" to monitor methods, in that any method may now also become a kind of synchronization point. The "open-ended" nature of this feels like it could easily lead to subtle bugs, particularly when code refactoring occurs (which may e.g. split an existing method into two). This seems particularly true if external scheduling can occur across compilation units -- the paper suggested that this is true, but I wasn't entirely clear.
    378 
    379 I would have also appreciated a few more details on how external scheduling is implemented. It seems to me that there must be some sort of "hooks" on mutex methods so that they can detect whether some other function is waiting on them and awaken those blocked threads. I'm not sure how such hooks are inserted, particularly across compilation units. The material in Section 5.6 didn't quite clarify the matter for me. For example, it left me somewhat confused about whether the `f` and `g` functions declared were meant to be local to a translation unit, or shared with other unit.
    380 
    381 ### Presentation of monitors is somewhat confusing
    382 
    383 I found myself confused fairly often in the section on monitors. I'm just going to leave some notes here on places that I got confused in how that it could be useful to you as feedback on writing that might want to be clarified.
    384 
    385 To start, I did not realize that the `mutex_opt` notation was a keyword, I thought it was a type annotation. I think this could be called out more explicitly.
    386 
    387 Later, in section 5.2, the paper discusses `nomutex` annotations, which initially threw me, as they had not been introduced (now I realize that this paragraph is there to justify why there is no such keyword). The paragraph might be rearranged to make that clearer, perhaps by leading with the choice that Cforall made.
    388 
    389 On page 17, the paper states that "acquiring multiple monitors is safe from deadlock", but this could be stated a bit more precisely: acquiring multiple monitors in a bulk-acquire is safe from deadlock (deadlock can still result from nested acquires).
    390 
    391 On page 18, the paper states that wait states do not have to be enclosed in loops, as there is no concern of barging. This seems true but there are also other reasons to use loops (e.g., if there are multiple reasons to notify on the same condition). Thus the statement initially surprised me, as barging is only one of many reasons that I typically employ loops around waits.
    392 
    393 I did not understand the diagram in Figure 12 for some time. Initially, I thought that it was generic to all monitors, and I could not understand the state space. It was only later that I realized it was specific to your example. Updating the caption from "Monitor scheduling to "Monitor scheduling in the example from Fig 13" might have helped me quite a bit.
    394 
    395 I spent quite some time reading the boy/girl dating example (\*) and I admit I found it somewhat confusing. For example, I couldn't tell whether there were supposed to be many "girl" threads executing at once, or if there was only supposed to be one girl and one boy thread executing in a loop. Are the girl/boy threads supposed to invoke the girl/boy methods or vice versa? Surely there is some easier way to set this up? I believe that when reading the paper I convinced myself of how it was supposed to be working, but I'm writing this review some days later, and I find myself confused all over again and not able to easily figure it out.
    396 
    397 (\*) as an aside, I would consider modifying the example to some other form of matching, like customers and support personnel.
    398 
    399 ## Related work
    400 
    401 The paper offered a number of comparisons to Go, C#, Scala, and so forth, but seems to have overlooked another recent language, Rust. In many ways, Rust seems to be closest in philosophy to Cforall, so it seems like an odd omission. I already mentioned above that Rust is in the process of shipping [async-await syntax][aa], which is definitely an alternative to the generator/coroutine approach in Cforall (though one with clear pros/cons).
    402 
    403 ## Performance
    404 
    405 In the performance section in particular, you might consider comparing against some of the Rust web servers and threading systems. For example, actix is top of the [single query TechEmpower Framework benchmarks], and tokio is near the top of the [plainthreading benchmarks][pt] (hyper, the top, is more of an HTTP framework, though it is also written in Rust). It would seem worth trying to compare their "context switching" costs as well -- I believe both actix and tokio have a notion of threads that could be readily compared.
    406 
    407 Another addition that might be worth considering is to compare against node.js promises, although I think the comparison to process creation is not as clean.
    408 
    409 That said, I think that the performance comparison is not a big focus of the paper, so it may not be necessary to add anything to it.
    410 
    411 ## Authorship of this review
    412 
    413 I'm going to sign this review. This review was authored by Nicholas D. Matsakis. In the intrerest of full disclosure, I'm heavily involved in the Rust project, although I dont' think that influenced this review in particular. Feel free to reach out to me for clarifying questions.
    414 
    415 ## Links
    416 
    417 [aa]: https://blog.rust-lang.org/2019/09/30/Async-await-hits-beta.html
    418 [zc]: https://aturon.github.io/blog/2016/08/11/futures/
    419 [sq]: https://www.techempower.com/benchmarks/#section=data-r18&hw=ph&test=db
    420 [pt]: https://www.techempower.com/benchmarks/#section=data-r18&hw=ph&test=plaintext
    421 
    422 
    423 
    424 Subject: Re: manuscript SPE-19-0219
    425 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
    426 From: Richard Jones <R.E.Jones@kent.ac.uk>
    427 Date: Tue, 12 Nov 2019 22:43:55 +0000
    428 
    429 Dear Dr Buhr
    430 
    431 Your should have received a decision letter on this today. I am sorry that this
    432 has taken so long. Unfortunately SP&E receives a lot of submissions and getting
    433 reviewers is a perennial problem.
    434 
    435 Regards
    436 Richard
    437 
    438 Peter A. Buhr wrote on 11/11/2019 13:10:
    439 >     26-Jun-2019
    440 >     Your manuscript entitled "Advanced Control-flow and Concurrency in Cforall"
    441 >     has been received by Software: Practice and Experience. It will be given
    442 >     full consideration for publication in the journal.
    443 >
    444 > Hi, it has been over 4 months since submission of our manuscript SPE-19-0219
    445 > with no response.
    446 >
    447 > Currently, I am refereeing a paper for IEEE that already cites our prior SP&E
    448 > paper and the Master's thesis forming the bases of the SP&E paper under
    449 > review. Hence our work is apropos and we want to get it disseminates as soon as
    450 > possible.
    451 >
    452 > [3] A. Moss, R. Schluntz, and P. A. Buhr, "Cforall: Adding modern programming
    453 >      language features to C," Software - Practice and Experience, vol. 48,
    454 >      no. 12, pp. 2111-2146, 2018.
    455 >
    456 > [4] T. Delisle, "Concurrency in C for all," Master's thesis, University of
    457 >      Waterloo, 2018.  [Online].  Available:
    458 >      https://uwspace.uwaterloo.ca/bitstream/handle/10012/12888
    459 
    460 
    461 
    462 Date: Mon, 13 Jan 2020 05:33:15 +0000
    463 From: Richard Jones <onbehalfof@manuscriptcentral.com>
    464 Reply-To: R.E.Jones@kent.ac.uk
    465 To: pabuhr@uwaterloo.ca
    466 Subject: Revision reminder - SPE-19-0219
    467 
    468 13-Jan-2020
    469 Dear Dr Buhr
    470 SPE-19-0219
    471 
    472 This is a reminder that your opportunity to revise and re-submit your
    473 manuscript will expire 28 days from now. If you require more time please
    474 contact me directly and I may grant an extension to this deadline, otherwise
    475 the option to submit a revision online, will not be available.
    476 
    477 I look forward to receiving your revision.
    478 
    479 Sincerely,
    480 
    481 Prof. Richard Jones
    482 Editor, Software: Practice and Experience
    483 https://mc.manuscriptcentral.com/spe
    484 
    485 
    486 
    487 Date: Wed, 5 Feb 2020 04:22:18 +0000
    488 From: Aaron Thomas <onbehalfof@manuscriptcentral.com>
    489 Reply-To: speoffice@wiley.com
    490 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
    491 Subject: SPE-19-0219.R1 successfully submitted
    492 
    493 04-Feb-2020
    494 
    495 Dear Dr Buhr,
    496 
    497 Your manuscript entitled "Advanced Control-flow and Concurrency in Cforall" has
    498 been successfully submitted online and is presently being given full
    499 consideration for publication in Software: Practice and Experience.
    500 
    501 Your manuscript number is SPE-19-0219.R1.  Please mention this number in all
    502 future correspondence regarding this submission.
    503 
    504 You can view the status of your manuscript at any time by checking your Author
    505 Center after logging into https://mc.manuscriptcentral.com/spe.  If you have
    506 difficulty using this site, please click the 'Get Help Now' link at the top
    507 right corner of the site.
    508 
    509 Thank you for submitting your manuscript to Software: Practice and Experience.
    510 
    511 Sincerely,
    512 Software: Practice and Experience Editorial Office
    513 
    514 
    515 
    516 Date: Sat, 18 Apr 2020 10:42:13 +0000
    517 From: Richard Jones <onbehalfof@manuscriptcentral.com>
    518 Reply-To: R.E.Jones@kent.ac.uk
    519 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
    520 Subject: Software: Practice and Experience - Decision on Manuscript ID
    521  SPE-19-0219.R1
    522 
    523 18-Apr-2020
    524 
    525 Dear Dr Buhr,
    526 
    527 Many thanks for submitting SPE-19-0219.R1 entitled "Advanced Control-flow and Concurrency in Cforall" to Software: Practice and Experience. The paper has now been reviewed and the comments of the referees are included at the bottom of this letter.
    528 
    529 I believe that we are making progress here towards a paper that can be published in Software: Practice and Experience.  However the referees still have significant concerns about the paper. The journal's focus is on practice and experience, and one of the the reviewers' concerns remains that your submission should focus the narrative more on the perspective of the programmer than the language designer. I agree that this would strengthen your submission, and I ask you to address this as well as the referees' other comments.
    530 
    531 A revised version of your manuscript that takes into account the comments of the referee(s) will be reconsidered for publication.
    532 
    533 Please note that submitting a revision of your manuscript does not guarantee eventual acceptance, and that your revision may be subject to re-review by the referees before a decision is rendered.
    534 
    535 You have 90 days from the date of this email to submit your revision. If you are unable to complete the revision within this time, please contact me to request a short extension.
    536 
    537 You can upload your revised manuscript and submit it through your Author Center. Log into https://mc.manuscriptcentral.com/spe  and enter your Author Center, where you will find your manuscript title listed under "Manuscripts with Decisions".
    538 
    539 When submitting your revised manuscript, you will be able to respond to the comments made by the referee(s) in the space provided.  You can use this space to document any changes you make to the original manuscript.
    540 
    541 If you would like help with English language editing, or other article preparation support, Wiley Editing Services offers expert help with English Language Editing, as well as translation, manuscript formatting, and figure formatting at www.wileyauthors.com/eeo/preparation. You can also check out our resources for Preparing Your Article for general guidance about writing and preparing your manuscript at www.wileyauthors.com/eeo/prepresources.
    542 
    543 Once again, thank you for submitting your manuscript to Software: Practice and Experience and I look forward to receiving your revision.
    544 
    545 Sincerely,
    546 Richard
    547 
    548 Prof. Richard Jones
    549 Software: Practice and Experience
    550 R.E.Jones@kent.ac.uk
    551 
    552 
    553 Referee(s)' Comments to Author:
    554 
    555 Reviewing: 1
    556 
    557 Comments to the Author
    558 (A relatively short second review)
    559 
    560 I thank the authors for their revisions and comprehensive response to
    561 reviewers' comments --- many of my comments have been successfully
    562 addressed by the revisions.  Here I'll structure my comments around
    563 the main salient points in that response which I consider would
    564 benefit from further explanation.
    565 
    566 >  Table 1 is moved to the start and explained in detail.
    567 
    568 I consider this change makes a significant improvement to the paper,
    569 laying out the landscape of language features at the start, and thus
    570 addresses my main concerns about the paper.
    571 
    572 I still have a couple of issues --- perhaps the largest is that it's
    573 still not clear at this point in the paper what some of these options
    574 are, or crucially how they would be used. I don't know if it's
    575 possbile to give high-level examples or use cases to be clear about
    576 these up front - or if that would duplicate too much information from
    577 later in the paper - either way expanding out the discussion - even if
    578 just two a couple of sentences for each row - would help me more.  The
    579 point is not just to define these categories but to ensure the
    580 readers' understanding of these definitons agrees with that used in
    581 the paper.
    582 
    583 in a little more detail:
    584 
    585  * 1st para section 2 begs the question: why not support each
    586    dimension independently, and let the programmer or library designer
    587    combiine features?
    588 
    589  * "execution state" seems a relatively low-level description here.
    590   I don't think of e.g. the lambda calculus that way. Perhaps it's as
    591   good a term as any.
    592 
    593  * Why must there "be language mechanisms to create, block/unblock,
    594    and join with a thread"?  There aren't in Smalltalk (although there
    595    are in the runtime).  Especially given in Cforall those mechanisms
    596    are *implicit* on thread creation and destruction?
    597 
    598  * "Case 1 is a function that borrows storage for its state (stack
    599    frame/activation) and a thread from its invoker"
    600 
    601    this much makes perfect sense to me, but I don't understand how a
    602    non-stateful, non-theaded function can then retain
    603 
    604    "this state across callees, ie, function local-variables are
    605    retained on the stack across calls."
    606 
    607    how can it retain function-local values *across calls* when it
    608    doesn't have any functional-local state?
    609 
    610    I'm not sure if I see two separate cases here - rougly equivalent
    611    to C functions without static storage, and then C functions *with*
    612    static storage. I assumed that was the distinction between cases 1
    613    & 3; but perhpas the actual distinction is that 3 has a
    614    suspend/resume point, and so the "state" in figure 1 is this
    615    component of execution state (viz figs 1 & 2), not the state
    616    representing the cross-call variables?
    617 
    618 >    but such evaluation isn't appropriate for garbage-collected or JITTed
    619    languages like Java or Go.
    620 
    621 For JITTed languages in particular, reporting peak performance needs
    622 to "warm up" the JIT with a number of iterators before beginning
    623 measurement. Actually for JIT's its even worse: see Edd Barrett et al
    624 OOPSLA 2017.
    625    
    626 
    627 
    628 minor issues:
    629 
    630  * footnote A - I've looked at various other papers & the website to
    631    try to understand how "object-oriented" Cforall is - I'm still not
    632    sure.  This footnote says Cforall has "virtuals" - presumably
    633    virtual functions, i.e. dynamic dispatch - and inheritance: that
    634    really is OO as far as I (and most OO people) are concerned.  For
    635    example Haskell doesn't have inheritance, so it's not OO; while
    636    CLOS (the Common Lisp *Object* System) or things like Cecil and
    637    Dylan are considered OO even though they have "multiple function
    638    parameters as receivers", lack "lexical binding between a structure
    639    and set of functions", and don't have explicit receiver invocation
    640    syntax.  Python has receiver syntax, but unlike Java or Smalltalk
    641    or C++, method declarations still need to have an explicit "self"
    642    receiver parameter.  Seems to me that Go, for example, is
    643    more-or-less OO with interfaces, methods, and dynamic dispatch (yes
    644    also and an explicit receiver syntax but that's not
    645    determiniative); while Rust lacks dynamic dispatch built-in.  C is
    646    not OO as a language, but as you say given it supports function
    647    pointers with structures, it does support an OO programm style.
    648  
    649    This is why I again recommend just not buying into this fight: not
    650    making any claims about whether Cforall is OO or is not - because
    651    as I see it, the rest of the paper doesn't depend on whether
    652    Cforall is OO or not.  That said: this is just a recommendation,
    653    and I won't quibble over this any further.
    654 
    655  * is a "monitor function" the same as a "mutex function"?
    656    if so the paper should pick one term; if not, make the distinction clear.
    657 
    658 
    659  * "As stated on line 1 because state declarations from the generator
    660     type can be moved out of the coroutine type into the coroutine main"
    661 
    662     OK sure, but again: *why* would a programmer want to do that?
    663     (Other than, I guess, to show the difference between coroutines &
    664     generators?)  Perhaps another way to put this is that the first
    665     para of 3.2 gives the disadvantages of coroutines vs-a-vs
    666     generators, briefly describes the extended semantics, but never
    667     actualy says why a programmer may want those extended semantics,
    668     or how they would benefit.  I don't mean to belabour the point,
    669     but (generalist?) readers like me would generally benefit from
    670     those kinds of discussions about each feature throughout the
    671     paper: why might a programmer want to use them?
    672    
    673 
    674 > p17 if the multiple-monitor entry procedure really is novel, write a paper
    675 > about that, and only about that.
    676 
    677 > We do not believe this is a practical suggestion.
    678 
    679  * I'm honestly not trying to be snide here: I'm not an expert on
    680    monitor or concurrent implementations. Brinch Hansen's original
    681    monitors were single acquire; this draft does not cite any other
    682    previous work that I could see. I'm not suggesting that the brief
    683    mention of this mechanism necessarily be removed from this paper,
    684    but if this is novel (and a clear advance over a classical OO
    685    monitor a-la Java which only acquires the distinguished reciever)
    686    then that would be worth another paper in itself.
    687  
    688 > * conclusion should conclude the paper, not the related.
    689 > We do not understand this comment.if ithis
    690 
    691 My typo: the paper's conclusion should come at the end, after the
    692 future work section.
    693 
    694 
    695 
    696 
    697 To encourage accountability, I'm signing my reviews in 2020.
    698 For the record, I am James Noble, kjx@ecs.vuw.ac.nz.
    699 
    700 
    701 Reviewing: 2
    702 
    703 Comments to the Author
    704 I thank the authors for their detailed response. To respond to a couple of points raised  in response to my review (number 2):
    705 
    706 - on the Boehm paper and whether code is "all sequential to the compiler": I now understand the authors' position better and suspect we are in violent agreement, except for whether it's appropriate to use the rather breezy phrase "all sequential to the compiler". It would be straightforward to clarify that code not using the atomics features is optimized *as if* it were sequential, i.e. on the assumption of a lack of data races.
    707 
    708 - on the distinction between "mutual exclusion" and "synchronization": the added citation does help, in that it makes a coherent case for the definition the authors prefer. However, the text could usefully clarify that this is a matter of definition not of fact, given especially that in my assessment the authors' preferred definition is not the most common one. (Although the mention of Hoare's apparent use of this definition is one data point, countervailing ones are found in many contemporaneous or later papers, e.g. Habermann's 1972 "Synchronization of Communicating Processes" (CACM 15(3)), Reed & Kanodia's 1979 "Synchronization with eventcounts and sequencers" (CACM (22(2)) and so on.)
    709 
    710 I am glad to see that the authors have taken on board most of the straightforward improvements I suggested.
    711 
    712 However, a recurring problem of unclear writing still remains through many parts of the paper, including much of sections 2, 3 and 6. To highlight a couple of problem patches (by no means exhaustive):
    713 
    714 - section 2 (an expanded version of what was previously section 5.9) lacks examples and is generally obscure and allusory ("the most advanced feature" -- name it! "in triplets" -- there is only one triplet!; what are "execution locations"? "initialize" and "de-initialize" what? "borrowed from the invoker" is a concept in need of explaining or at least a fully explained example -- in what sense does a plain function borrow" its stack frame? "computation only" as opposed to what? in 2.2, in what way is a "request" fundamental to "synchronization"? and the "implicitly" versus "explicitly" point needs stating as elsewhere, with a concrete example e.g. Java built-in mutexes versus java.util.concurrent).
    715 
    716 - section 6: 6.2 omits the most important facts in preference for otherwise inscrutable detail: "identify the kind of parameter" (first say *that there are* kinds of parameter, and what "kinds" means!); "mutex parameters are documentation" is misleading (they are also semantically significant!) and fails to say *what* they mean; the most important thing is surely that 'mutex' is a language feature for performing lock/unlock operations at function entry/exit. So say it! The meanings of examples f3 and f4 remain unclear. Meanwhile in 6.3, "urgent" is not introduced (we are supposed to infer its meaning from Figure 12, but that Figure is incomprehensible to me), and we are told of "external scheduling"'s long history in Ada but not clearly what it actually means; 6.4's description of "waitfor" tells us it is different from an if-else chain but tries to use two *different* inputs to tell us that the behavior is different; tell us an instance where *the same* values of C1 and C2 give different behavior (I even wrote out a truth table and still don't see the semantic difference)
    717 
    718 The authors frequently use bracketed phrases, and sometimes slashes "/", in ways that are confusing and/or detrimental to readability. Page 13 line 2's "forward (backward)" is one particularly egregious example. In general I would recommend the the authors try to limit their use of parentheses and slashes as a means of forcing a clearer wording to emerge. Also, the use of "eg." is often cursory and does not explain the examples given, which are frequently a one- or two-word phrase of unclear referent.
    719 
    720 Considering the revision more broadly, none of the more extensive or creative rewrites I suggested in my previous review have been attempted, nor any equivalent efforts to improve its readability. The hoisting of the former section 5.9 is a good idea, but the newly added material accompanying it (around Table 1) suffers fresh deficiencies in clarity. Overall the paper is longer than before, even though (as my previous review stated), I believe a shorter paper is required in order to serve the likely purpose of publication. (Indeed, the authors' letter implies that a key goal of publication is to build community and gain external users.)
    721 
    722 Given this trajectory, I no longer see a path to an acceptable revision of the present submission. Instead I suggest the authors consider splitting the paper in two: one half about coroutines and stack management, the other about mutexes, monitors and the runtime. (A briefer presentation of the runtime may be helpful in the first paper also, and a brief recap of the generator and coroutine support is obviously needed in the second too.) Both of these new papers would need to be written with a strong emphasis on clarity, paying great care to issues of structure, wording, choices of example, and restraint (saying what's important, not everything that could be said). I am confident the authors could benefit from getting early feedback from others at their institution. For the performance experiments, of course these do not split evenly -- most (but not all) belong in the second of these two hypothetical papers. But the first of them would still have plenty of meat to it; for me, a clear and thorough study of the design space around coroutines is the most interesting and tantalizing prospect.
    723 
    724 I do not buy the authors' defense of the limited practical experience or "non-micro" benchmarking presented. Yes, gaining external users is hard and I am sympathetic on that point. But building something at least *somewhat* substantial with your own system should be within reach, and without it the "practice and experience" aspects of the work have not been explored. Clearly C\/ is the product of a lot of work over an extended period, so it is a surprise that no such experience is readily available for inclusion.
    725 
    726 Some smaller points:
    727 
    728 It does not seem right to state that a stack is essential to Von Neumann architectures -- since the earliest Von Neumann machines (and indeed early Fortran) did not use one.
    729 
    730 To elaborate on something another reviewer commented on: it is a surprise to find a "Future work" section *after* the "Conclusion" section. A "Conclusions and future work" section often works well.
    731 
    732 
    733 Reviewing: 3
    734 
    735 Comments to the Author
    736 This is the second round of reviewing.
    737 
    738 As in the first review, I found that the paper (and Cforall) contains
    739 a lot of really interesting ideas, but it remains really difficult to
    740 have a good sense of which idea I should use and when. This applies in
    741 different ways to different features from the language:
    742 
    743 * coroutines/generators/threads: here there is
    744   some discussion, but it can be improved.
    745 * interal/external scheduling: I didn't find any direct comparison
    746   between these features, except by way of example.
    747 
    748 I requested similar things in my previous review and I see that
    749 content was added in response to those requests. Unfortunately, I'm
    750 not sure that I can say it improved the paper's overall read. I think
    751 in some sense the additions were "too much" -- I would have preferred
    752 something more like a table or a few paragraphs highlighting the key
    753 reasons one would pick one construct or the other.
    754 
    755 In general, I do wonder if the paper is just trying to do too much.
    756 The discussion of clusters and pre-emption in particular feels quite
    757 rushed.
    758 
    759 ## Summary
    760 
    761 I make a number of suggestions below but the two most important
    762 I think are:
    763 
    764 * Recommend to shorten the comparison on coroutine/generator/threads
    765   in Section 2 to a paragraph with a few examples, or possibly a table
    766   explaining the trade-offs between the constructs
    767 * Recommend to clarify the relationship between internal/external
    768   scheduling -- is one more general but more error-prone or low-level?
    769 
    770 ## Coroutines/generators/threads
    771 
    772 There is obviously a lot of overlap between these features, and in
    773 particular between coroutines and generators. As noted in the previous
    774 review, many languages have chosen to offer *only* generators, and to
    775 build coroutines by stacks of generators invoking one another.
    776 
    777 I believe the newly introduced Section 2 of the paper is trying to
    778 motivate why each of these constructs exist, but I did not find it
    779 effective. It was dense and difficult to understand. I think the
    780 problem is that Section 2 seems to be trying to derive "from first
    781 principles" why each construct exists, but I think that a more "top
    782 down" approach would be easier to understand.
    783 
    784 In fact, the end of Section 2.1 (on page 5) contains a particular
    785 paragraph that embodies this "top down" approach. It starts,
    786 "programmers can now answer three basic questions", and thus gives
    787 some practical advice for which construct you should use and when. I
    788 think giving some examples of specific applications that this
    789 paragraph, combined with some examples of cases where each construct
    790 was needed, would be a better approach.
    791 
    792 I don't think this compariosn needs to be very long. It seems clear
    793 enough that one would
    794 
    795 * prefer generators for simple computations that yield up many values,
    796 * prefer coroutines for more complex processes that have significant
    797   internal structure,
    798 * prefer threads for cases where parallel execution is desired or
    799   needed.
    800 
    801 I did appreciate the comparison in Section 2.3 between async-await in
    802 JS/Java and generators/coroutines. I agree with its premise that those
    803 mechanisms are a poor replacement for generators (and, indeed, JS has
    804 a distinct generator mechanism, for example, in part for this reason).
    805 I believe I may have asked for this in a previous review, but having
    806 read it, I wonder if it is really necessary, since those mechanisms
    807 are so different in purpose.
    808 
    809 ## Internal vs external scheduling
    810 
    811 I find the motivation for supporting both internal and external
    812 scheduling to be fairly implicit. After several reads through the
    813 section, I came to the conclusion that internal scheduling is more
    814 expressive than external scheduling, but sometimes less convenient or
    815 clear. Is this correct? If not, it'd be useful to clarify where
    816 external scheduling is more expressive.
    817 
    818 The same is true, I think, of the `signal_block` function, which I
    819 have not encountered before; it seems like its behavior can be modeled
    820 with multiple condition variables, but that's clearly more complex.
    821 
    822 One question I had about `signal_block`: what happens if one signals
    823 but no other thread is waiting? Does it block until some other thread
    824 waits? Or is that user error?
    825 
    826 I would find it very interesting to try and capture some of the
    827 properties that make internal vs external scheduling the better
    828 choice.
    829 
    830 For example, it seems to me that external scheduling works well if
    831 there are only a few "key" operations, but that internal scheduling
    832 might be better otherwise, simply because it would be useful to have
    833 the ability to name a signal that can be referenced by many
    834 methods. Consider the bounded buffer from Figure 13: if it had
    835 multiple methods for removing elements, and not just `remove`, then
    836 the `waitfor(remove)` call in `insert` might not be sufficient.
    837 
    838 ## Comparison of external scheduling to messaging
    839 
    840 I did enjoy the section comparing external scheduling to Go's
    841 messaging mechanism, which I believe is a new addition.
    842 
    843 I believe that one difference between the Go program and the Cforall
    844 equivalent is that the Goroutine has an associated queue, so that
    845 multiple messages could be enqueued, whereas the Cforall equivalent is
    846 effectively a "bounded buffer" of length 1. Is that correct? I think
    847 this should be stated explicitly. (Presumably, one could modify the
    848 Cforall program to include an explicit vector of queued messages if
    849 desired, but you would also be reimplementing the channel
    850 abstraction.)
    851 
    852 Also, in Figure 20, I believe that there is a missing `mutex` keyword.
    853 The fiugre states:
    854 
    855 ```
    856 void main(GoRtn & gortn) with(gortn) {
    857 ```
    858 
    859 but I think it should probably be as follows:
    860 
    861 ```
    862 void main(GoRtn & mutex gortn) with(gortn) {
    863 ```
    864 
    865 Unless there is some implicit `mutex` associated with being a main
    866 function for a `monitor thread`.
    867 
    868 ## Atomic operations and race freedom
    869 
    870 I was glad to see that the paper acknowledged that Cforall still had
    871 low-level atomic operations, even if their use is discouraged in favor
    872 of higher-level alternatives.
    873 
    874 However, I still feel that the conclusion overstates the value of the
    875 contribution here when it says that "Cforall high-level race-free
    876 monitors and threads provide the core mechanisms for mutual exclusion
    877 and synchronization, without the need for volatile and atomics". I
    878 feel confident that Java programmers, for example, would be advised to
    879 stick with synchronized methods whenever possible, and it seems to me
    880 that they offer similar advantages -- but they sometimes wind up using
    881 volatiles for performance reasons.
    882 
    883 I was also confused by the term "race-free" in that sentence. In
    884 particular, I don't think that Cforall has any mechanisms for
    885 preventing *data races*, and it clearly doesn't prevent "race
    886 conditions" (which would bar all sorts of useful programs). I suppose
    887 that "race free" here might be referring to the improvements such as
    888 removing barging behavior.
    889 
    890 ## Performance comparisons
    891 
    892 In my previous review, I requested comparisons against Rust and
    893 node.js, and I see that the new version of the paper includes both,
    894 which is a good addition.
    895 
    896 One note on the Rust results: I believe that the results are comparing
    897 against the threads found in Rust's standard library, which are
    898 essentially a shallow wrapper around pthreads, and hence the
    899 performance is quite close to pthread performance (as one would
    900 expect). It would perhaps be more interesting to see a comparison
    901 built using [tokio] or [async-std], two of the more prominent
    902 user-space threading libraries that build on Rust's async-await
    903 feature (which operates quite differently than Javascript's
    904 async-await, in that it doesn't cause every aync function call to
    905 schedule a distinct task).
    906 
    907 [tokio]: https://tokio.rs/
    908 [async-std]: https://async.rs/
    909 
    910 That said, I am satisfied with the performance results as they are in
    911 the current revision.
    912 
    913 ## Minor notes and typos
    914 
    915 Several figures used the `with` keyword. I deduced that `with(foo)`
    916 permits one to write `bar` instead of `foo.bar`. It seems worth
    917 introducing. Apologies if this is stated in the paper, if so I missed
    918 it.
    919 
    920 On page 20, section 6.3, "external scheduling and vice versus" should be
    921 "external scheduling and vice versa".
    922 
    923 On page 5, section 2.3, the paper states "we content" but it should be
    924 "we contend".
    925 
    926 Reviewing: Editor
    927 
    928 A few small comments in addition to those of the referees.
    929 
    930 Page 1. I don't believe that it s fair to imply that Scala is  "research vehicle" as it is used by major players, Twitter being the most prominent example.
    931 
    932 Page 15. Must Cforall threads start after construction (e.g. see your example on page 15, line 21)? I can think of examples where it is not desirable that threads start immediately after construction, e.g. a game with N players, each of whom is expensive to create, but all of whom should be started at the same time.
    933 
    934 Page 18, line 17: is using
    935 
    936 
    937 
    938 Date: Tue, 16 Jun 2020 13:45:03 +0000
    939 From: Aaron Thomas <onbehalfof@manuscriptcentral.com>
    940 Reply-To: speoffice@wiley.com
    941 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
    942 Subject: SPE-19-0219.R2 successfully submitted
    943 
    944 16-Jun-2020
    945 
    946 Dear Dr Buhr,
    947 
    948 Your manuscript entitled "Advanced Control-flow and Concurrency in Cforall" has been successfully submitted online and is presently being given full consideration for publication in Software: Practice and Experience.
    949 
    950 Your manuscript number is SPE-19-0219.R2.  Please mention this number in all future correspondence regarding this submission.
    951 
    952 You can view the status of your manuscript at any time by checking your Author Center after logging into https://mc.manuscriptcentral.com/spe.  If you have difficulty using this site, please click the 'Get Help Now' link at the top right corner of the site.
    953 
    954 
    955 Thank you for submitting your manuscript to Software: Practice and Experience.
    956 
    957 Sincerely,
    958 
    959 Software: Practice and Experience Editorial Office
    960 
    961 
    962 
    963 Date: Wed, 2 Sep 2020 20:55:34 +0000
    964 From: Richard Jones <onbehalfof@manuscriptcentral.com>
    965 Reply-To: R.E.Jones@kent.ac.uk
    966 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
    967 Subject: Software: Practice and Experience - Decision on Manuscript ID
    968  SPE-19-0219.R2
    969 
    970 02-Sep-2020
    971 
    972 Dear Dr Buhr,
    973 
    974 Many thanks for submitting SPE-19-0219.R2 entitled "Advanced Control-flow and Concurrency in Cforall" to Software: Practice and Experience. The paper has now been reviewed and the comments of the referees are included at the bottom of this letter. I apologise for the length of time it has taken to get these.
    975 
    976 Both reviewers consider this paper to be close to acceptance. However, before I can accept this paper, I would like you address the comments of Reviewer 2, particularly with regard to the description of the adaptation Java harness to deal with warmup. I would expect to see a convincing argument that the computation has reached a steady state. I would also like you to provide the values for N for each benchmark run. This should be very straightforward for you to do. There are a couple of papers on steady state that you may wish to consult (though I am certainly not pushing my own work).
    977 
    978 1) Barrett, Edd; Bolz-Tereick, Carl Friedrich; Killick, Rebecca; Mount, Sarah and Tratt, Laurence. Virtual Machine Warmup Blows Hot and Cold. OOPSLA 2017. https://doi.org/10.1145/3133876
    979 Virtual Machines (VMs) with Just-In-Time (JIT) compilers are traditionally thought to execute programs in two phases: the initial warmup phase determines which parts of a program would most benefit from dynamic compilation, before JIT compiling those parts into machine code; subsequently the program is said to be at a steady state of peak performance. Measurement methodologies almost always discard data collected during the warmup phase such that reported measurements focus entirely on peak performance. We introduce a fully automated statistical approach, based on changepoint analysis, which allows us to determine if a program has reached a steady state and, if so, whether that represents peak performance or not. Using this, we show that even when run in the most controlled of circumstances, small, deterministic, widely studied microbenchmarks often fail to reach a steady state of peak performance on a variety of common VMs. Repeating our experiment on 3 different machines, we found that at most 43.5% of pairs consistently reach a steady state of peak performance.
    980 
    981 2) Kalibera, Tomas and Jones, Richard. Rigorous Benchmarking in Reasonable Time. ISMM  2013. https://doi.org/10.1145/2555670.2464160
    982 Experimental evaluation is key to systems research. Because modern systems are complex and non-deterministic, good experimental methodology demands that researchers account for uncertainty. To obtain valid results, they are expected to run many iterations of benchmarks, invoke virtual machines (VMs) several times, or even rebuild VM or benchmark binaries more than once. All this repetition costs time to complete experiments. Currently, many evaluations give up on sufficient repetition or rigorous statistical methods, or even run benchmarks only in training sizes. The results reported often lack proper variation estimates and, when a small difference between two systems is reported, some are simply unreliable.In contrast, we provide a statistically rigorous methodology for repetition and summarising results that makes efficient use of experimentation time. Time efficiency comes from two key observations. First, a given benchmark on a given platform is typically prone to much less non-determinism than the common worst-case of published corner-case studies. Second, repetition is most needed where most uncertainty arises (whether between builds, between executions or between iterations). We capture experimentation cost with a novel mathematical model, which we use to identify the number of repetitions at each level of an experiment necessary and sufficient to obtain a given level of precision.We present our methodology as a cookbook that guides researchers on the number of repetitions they should run to obtain reliable results. We also show how to present results with an effect size confidence interval. As an example, we show how to use our methodology to conduct throughput experiments with the DaCapo and SPEC CPU benchmarks on three recent platforms.
    983 
    984 You have 42 days from the date of this email to submit your revision. If you are unable to complete the revision within this time, please contact me to request a short extension.
    985 
    986 You can upload your revised manuscript and submit it through your Author Center. Log into https://mc.manuscriptcentral.com/spe and enter your Author Center, where you will find your manuscript title listed under "Manuscripts with Decisions".
    987 
    988 When submitting your revised manuscript, you will be able to respond to the comments made by the referee(s) in the space provided.  You can use this space to document any changes you make to the original manuscript.
    989 
    990 If you would like help with English language editing, or other article preparation support, Wiley Editing Services offers expert help with English Language Editing, as well as translation, manuscript formatting, and figure formatting at www.wileyauthors.com/eeo/preparation. You can also check out our resources for Preparing Your Article for general guidance about writing and preparing your manuscript at www.wileyauthors.com/eeo/prepresources.
    991  
    992 Once again, thank you for submitting your manuscript to Software: Practice and Experience. I look forward to receiving your revision.
    993 
    994 Sincerely,
    995 Richard
    996 
    997 Prof. Richard Jones
    998 Editor, Software: Practice and Experience
    999 R.E.Jones@kent.ac.uk
    1000 
    1001 Referee(s)' Comments to Author:
    1002 
    1003 Reviewing: 1
    1004 
    1005 Comments to the Author
    1006 Overall, I felt that this draft was an improvement on previous drafts and I don't have further changes to request.
    1007 
    1008 I appreciated the new language to clarify the relationship of external and internal scheduling, for example, as well as the new measurements of Rust tokio. Also, while I still believe that the choice between thread/generator/coroutine and so forth could be made crisper and clearer, the current draft of Section 2 did seem adequate to me in terms of specifying the considerations that users would have to take into account to make the choice.
    1009 
    1010 
    1011 Reviewing: 2
    1012 
    1013 Comments to the Author
    1014 First: let me apologise for the delay on this review. I'll blame the global pandemic combined with my institution's senior management's counterproductive decisions for taking up most of my time and all of my energy.
    1015 
    1016 At this point, reading the responses, I think we've been around the course enough times that further iteration is unlikely to really improve the paper any further, so I'm happy to recommend acceptance.    My main comments are that there were some good points in the responses to *all* the reviews and I strongly encourage the authors to incorporate those discursive responses into the final paper so they may benefit readers as well as reviewers.   I agree with the recommendations of reviewer #2 that the paper could usefully be split in to two, which I think I made to a previous revision, but I'm happy to leave that decision to the Editor.
    1017 
    1018 Finally, the paper needs to describe how the Java harness was adapted to deal with warmup; why the computation has warmed up and reached a steady state - similarly for js and Python. The tables should also give the "N" chosen for each benchmark run.
    1019  
    1020 minor points
    1021 * don't start sentences with "However"
    1022 * most downloaded isn't an "Award"
    1023 
    1024 
    1025 
    1026 Date: Thu, 1 Oct 2020 05:34:29 +0000
    1027 From: Richard Jones <onbehalfof@manuscriptcentral.com>
    1028 Reply-To: R.E.Jones@kent.ac.uk
    1029 To: pabuhr@uwaterloo.ca
    1030 Subject: Revision reminder - SPE-19-0219.R2
    1031 
    1032 01-Oct-2020
    1033 
    1034 Dear Dr Buhr
    1035 
    1036 SPE-19-0219.R2
    1037 
    1038 This is a reminder that your opportunity to revise and re-submit your manuscript will expire 14 days from now. If you require more time please contact me directly and I may grant an extension to this deadline, otherwise the option to submit a revision online, will not be available.
    1039 
    1040 If your article is of potential interest to the general public, (which means it must be timely, groundbreaking, interesting and impact on everyday society) then please e-mail ejp@wiley.co.uk explaining the public interest side of the research. Wiley will then investigate the potential for undertaking a global press campaign on the article.
    1041 
    1042 I look forward to receiving your revision.
    1043 
    1044 Sincerely,
    1045 
    1046 Prof. Richard Jones
    1047 Editor, Software: Practice and Experience
    1048 
    1049 https://mc.manuscriptcentral.com/spe
    1050 
    1051 
    1052 
    1053 Date: Tue, 6 Oct 2020 15:29:41 +0000
    1054 From: Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com>
    1055 Reply-To: speoffice@wiley.com
    1056 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
    1057 Subject: SPE-19-0219.R3 successfully submitted
    1058 
    1059 06-Oct-2020
    1060 
    1061 Dear Dr Buhr,
    1062 
    1063 Your manuscript entitled "Advanced Control-flow and Concurrency in Cforall" has been successfully submitted online and is presently being given full consideration for publication in Software: Practice and Experience.
    1064 
    1065 Your manuscript number is SPE-19-0219.R3.  Please mention this number in all future correspondence regarding this submission.
    1066 
    1067 You can view the status of your manuscript at any time by checking your Author Center after logging into https://mc.manuscriptcentral.com/spe.  If you have difficulty using this site, please click the 'Get Help Now' link at the top right corner of the site.
    1068 
    1069 
    1070 Thank you for submitting your manuscript to Software: Practice and Experience.
    1071 
    1072 Sincerely,
    1073 
    1074 Software: Practice and Experience Editorial Office
    1075 
    1076 
    1077 
    1078 Date: Thu, 15 Oct 2020 13:48:52 +0000
    1079 From: Richard Jones <onbehalfof@manuscriptcentral.com>
    1080 Reply-To: R.E.Jones@kent.ac.uk
    1081 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
    1082 Subject: Software: Practice and Experience - Decision on Manuscript ID
    1083  SPE-19-0219.R3
    1084 
    1085 15-Oct-2020
    1086 
    1087 Dear Dr Buhr,
    1088 
    1089 It is a pleasure to accept your manuscript entitled "Advanced Control-flow and Concurrency in Cforall" in its current form for publication in Software: Practice and Experience. 
    1090 
    1091 Please note although the manuscript is accepted the files will now be checked to ensure that everything is ready for publication, and you may be contacted if final versions of files for publication are required.
    1092 
    1093 Your article cannot be published until the publisher has received the appropriate signed license agreement. Within the next few days the corresponding author will receive an email from Wiley's Author Services system which will ask them to log in and will present them with the appropriate license for completion.
    1094 
    1095 Thank you for your fine contribution.
    1096 
    1097 Sincerely,
    1098 Richard
    1099 
    1100 Prof. Richard Jones
    1101 Editor, Software: Practice and Experience
    1102 R.E.Jones@kent.ac.uk
    1103 
    1104 P.S. - You can help your research get the attention it deserves! Check out Wiley's free Promotion Guide for best-practice recommendations for promoting your work at www.wileyauthors.com/eeo/guide. And learn more about Wiley Editing Services which offers professional video, design, and writing services to create shareable video abstracts, infographics, conference posters, lay summaries, and research news stories for your research at www.wileyauthors.com/eeo/promotion.
    1105 
    1106 This journal accepts artwork submissions for Cover Images. This is an optional service you can use to help increase article exposure and showcase your research. For more information, including artwork guidelines, pricing, and submission details, please visit the Journal Cover Image page at www.wileyauthors.com/eeo/covers. If you want help creating an image, Wiley Editing Services offers a professional cover image design service that creates eye-catching images, ready to be showcased on the journal cover at www.wileyauthors.com/eeo/design.
    1107 
    1108 
    1109 
    1110 Date: Fri, 16 Oct 2020 12:44:42 +0000
    1111 From: Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com>
    1112 Reply-To: speoffice@wiley.com
    1113 To: pabuhr@uwaterloo.ca
    1114 Subject: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c]
    1115 
    1116 16-Oct-2020
    1117 
    1118 Dear Dr. Buhr,
    1119 
    1120 Manuscript id: SPE-19-0219.R3
    1121 Manuscript title: Advanced Control-flow and Concurrency in Cforall
    1122 
    1123 Although your manuscript has been accepted for publication it is now being returned to your author center for you to review and make any final adjustments or corrections prior to production and publication.
    1124 
    1125 Any special instructions will be listed below:
    1126 1) Funding Information added in ScholorOne but missing in main document, Kindly add the Funding information in main document.
    1127 2) Please provide the clean version of the manuscript without any highlights or tracked changes.
    1128 3) Kindly check and make sure citations for all figures and Tables are present in the main document
    1129 
    1130 Please now log back into your Scholar One Author Center and click on the "Manuscripts Accepted for First Look" queue. In order to update the submission, click on the "submit updated manuscript" link in the "Actions" column and follow the steps as you would during a manuscript submission process.
    1131 
    1132 On the File Upload screen please upload the FINAL versions of all the files, including print quality image files. For information about image quality requirements, please refer to the guidelines at https://authorservices.wiley.com/asset/photos/electronic_artwork_guidelines.pdf.
    1133 
    1134 Instructions for uploading replacement files:
    1135 1. On the "File Upload" step, click on the "edit" button for the file you wish to replace.
    1136 2. In the "Upload a later version" section, browse to locate the replacement final version.
    1137 3. Add any comments concerning the replacement (e.g. "high res image").
    1138 4. Select whether the new file is a minor or major version (we suggest you select minor version)
    1139 5. Click upload.
    1140 6. Click 'Submit' when all the files have been uploaded and you will receive an automated email to say that submission is successful.
    1141 
    1142 Please submit your updates within the next 7 days to ensure there are no unnecessary delays in production.
    1143 
    1144 Sincerely,
    1145 Software: Practice and Experience Editorial Office
    1146 
    1147 
    1148 
    1149 From: SPE Office <speoffice@wiley.com>
    1150 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
    1151 Subject: Re: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c]
    1152 Date: Mon, 19 Oct 2020 17:04:24 +0000
    1153 
    1154 Dear Dr. Buhr,
    1155 
    1156 Thank you very much for contacting the Editorial Office.
    1157 
    1158 I would like to let you know that the files has been found in order and moved to production.
    1159 
    1160 Plesae let me know for further assistance in this regard.
    1161 
    1162 Best Regards
    1163 
    1164 Mayank Roy Chowdhury
    1165 Editorial Assistant
    1166 Software practice and Experience
    1167 ________________________________
    1168 From: Peter A. Buhr <pabuhr@uwaterloo.ca>
    1169 Sent: Sunday, October 18, 2020 2:00 PM
    1170 To: SPE Office <speoffice@wiley.com>
    1171 Cc: Thierry Delisle <tdelisle@uwaterloo.ca>
    1172 Subject: Re: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c]
    1173 
    1174        This is an external email.
    1175 
    1176     Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com> writes:
    1177 
    1178     Instructions for uploading replacement files:
    1179     1. On the "File Upload" step, click on the "edit" button for the file you wish to replace.
    1180     2. In the "Upload a later version" section, browse to locate the replacement final version.
    1181     3. Add any comments concerning the replacement (e.g. "high res image").
    1182     4. Select whether the new file is a minor or major version (we suggest you select minor version)
    1183     5. Click upload.
    1184     6. Click 'Submit' when all the files have been uploaded and you will receive an automated email to say that submission is successful.
    1185 
    1186 There was no "edit" button on the "File Upload" page, so I just upload the
    1187 final version of the PDF and source files using the mechanism on the "File
    1188 Upload" page and submitted that.
    1189 
    1190 
    1191 
    1192 Date: Tue, 20 Oct 2020 13:28:37 +0530
    1193 To: "Dr. Peter Buhr" <pabuhr@uwaterloo.ca>
    1194 From: jpcms@spi-global.com
    1195 Subject: Information: Production Editor Contact Software:Practice and Experience  | Advanced Control-flow and Concurrency in C A
    1196 
    1197 Dear Dr. Peter Buhr,
    1198 
    1199 We are in the process of preparing "Advanced Control-flow and Concurrency in C A" for publication. Your production editor, Joel Pacaanas, will support you and your article throughout the process.
    1200 
    1201 Please get in touch with your Production Editor at SPEproofs@wiley.com;EllaMae.Navor@spi-global.com if you have any questions.
    1202                
    1203 Sincerely,
    1204 Booking-in Team,
    1205 On behalf of Wiley
    1206 
    1207 Article ID: SPE_2925
    1208 Article DOI: 10.1002/SPE.2925
    1209 
    1210 
    1211 
    1212 Date: Tue, 20 Oct 2020 10:33:04 +0000
    1213 From: <cs-author@wiley.com>
    1214 To: <pabuhr@uwaterloo.ca>
    1215 Subject: In Production: Your article accepted in Software: Practice and Experience
    1216 
    1217 Dear Peter Buhr,
    1218 
    1219 Article ID: SPE2925
    1220 Article DOI: 10.1002/spe.2925
    1221 Internal Article ID: 16922213
    1222 Article: Advanced Control-flow and Concurrency in C A
    1223 Journal: Software: Practice and Experience
    1224 
    1225 Congratulations on the acceptance of your article for publication in Software: Practice and Experience.
    1226 
    1227 Your article has been received and the production process is now underway. We look forward to working with you and publishing your article. Using Wiley Author Services, you can track your article's progress.
    1228 
    1229 Please click below to login - if you are using a different email address than this one, you will need to manually assign this article to your Dashboard (see https://hub.wiley.com/docs/support/assigning-a-missing-article-to-my-dashboard-DOC-11871?utm_source=new%20user%20invitation&utm_medium=email How do I assign a missing article to My Dashboard?):
    1230 
    1231 https://authorservices.wiley.com/index.html#login?campaign=email_invitation-new
    1232 
    1233 If applicable, a list of available actions will appear below - check out your Author Services Dashboard for all actions related to your articles.
    1234 
    1235 Sign your license agreement (REQUIRED)  -- you will receive an email when this task is ready on your dashboard. Track your article's progress to publicationAccess your published articleInvite colleagues to view your published article
    1236 If you need any assistance, please click http://www.wileyauthors.com/help?utm_source=new%20user%20invitation&utm_medium=email here to view our Help section.
    1237 
    1238 Sincerely,
    1239 Wiley Author Services
    1240 
    1241 P.S. - Some journals accept artwork submissions for Cover Images. This is an optional service you can use to help increase article exposure and showcase your research. Pricing and placement options vary by journal. For more information, including artwork guidelines, pricing, and submission details, please visit the https://authorservices.wiley.com/author-resources/Journal-Authors/Promotion/journal-cover-image.html?utm_source=as&utm_medium=email&utm_term=invitation_msg&utm_content=covers&utm_campaign=2019feb?campaign=email_invitation-new" target=_blank">Journal Cover Image page. If you want help creating an image, Wiley Editing Services offers a professional https://wileyeditingservices.com/en/article-promotion/cover-image-design.html?utm_source=as&utm_medium=email&utm_term=ie&utm_content=cid&utm_campaign=prodops" target=_blank">Cover Image Design service that creates eye-catching images, ready to be showcased on the journal cover.
    1242 
    1243 
    1244 
    1245 Date: Thu, 22 Oct 2020 20:21:49 +0000
    1246 From: <cs-author@wiley.com>
    1247 To: <pabuhr@uwaterloo.ca>
    1248 Subject: You have actions to complete in Author Services
    1249 
    1250 Dear Peter Buhr,
    1251 
    1252 Article ID: SPE2925
    1253 Article DOI: 10.1002/spe.2925
    1254 Internal Article ID: 16922213
    1255 Article: Advanced Control-flow and Concurrency in C A
    1256 Journal: Software: Practice and Experience
    1257 
    1258 For the above article, you have the following open tasks:
    1259 
    1260 Sign your license agreement in order to publish your article. Simply click the Sign License button on your https://authorservices.wiley.com?campaign=email_license-notice1">Wiley Author Services Dashboard.
    1261 
    1262 Need any help? Please visit our https://authorsupport.wiley.com/s/">Author Support Center.
    1263 
    1264 Sincerely,
    1265 Wiley Author Services
    1266 
    1267 
    1268 
    1269 Date: Thu, 22 Oct 2020 23:13:07 +0000
    1270 From: <cs-author@wiley.com>
    1271 To: <pabuhr@uwaterloo.ca>
    1272 Subject: License was successfully submitted! Thank you!
    1273 
    1274 Dear Peter Buhr,                                                                 
    1275 
    1276 Article ID: SPE2925
    1277 Article DOI: 10.1002/spe.2925
    1278 Internal Article ID: 16922213
    1279 Article: Advanced Control-flow and Concurrency in C A 
    1280 Journal: Software: Practice and Experience                                                                     
    1281                                                                          
    1282 You've successfully completed license signing for your article - thank you! You can view your signed agreement at any time by visiting your https://authorservices.wiley.com?campaign=email_license-confirm">Wiley Author Services Dashboard.                                                                     
    1283 
    1284 Sincerely,                                                                                 
    1285 
    1286 Wiley Author Services
    1287 
    1288 
    1289 
    1290 From: "Pacaanas, Joel -" <jpacaanas@wiley.com>
    1291 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
    1292 CC: Thierry Delisle <tdelisle@uwaterloo.ca>
    1293 Subject: RE: Action: Proof of SPE_EV_SPE2925 for Software: Practice And Experience ready for review
    1294 Date: Thu, 5 Nov 2020 02:03:27 +0000
    1295 
    1296 Dear Dr Buhr,
    1297 
    1298 Thank you for letting me know. We will wait for your corrections then.
    1299 
    1300 Best regards,
    1301 Joel
    1302 
    1303 Joel Q. Pacaanas
    1304 Production Editor
    1305 On behalf of Wiley
    1306 Manila
    1307 We partner with global experts to further innovative research.
    1308 
    1309 E-mail: jpacaanas@wiley.com
    1310 Tel: +632 88558618
    1311 Fax: +632 5325 0768
    1312 
    1313 -----Original Message-----
    1314 From: Peter A. Buhr [mailto:pabuhr@uwaterloo.ca]
    1315 Sent: Thursday, November 5, 2020 5:57 AM
    1316 To: SPE Proofs <speproofs@wiley.com>
    1317 Cc: Thierry Delisle <tdelisle@uwaterloo.ca>
    1318 Subject: Re: Action: Proof of SPE_EV_SPE2925 for Software: Practice And Experience ready for review
    1319 
    1320        This is an external email.
    1321 
    1322     We appreciate that the COVID-19 pandemic may create conditions for you that
    1323     make it difficult for you to review your proof within standard time
    1324     frames. If you have any problems keeping to this schedule, please reach out
    1325     to me at (SPEproofs@wiley.com) to discuss alternatives.
    1326 
    1327 Hi,
    1328 
    1329 We are in the middle of reading the proofs but it will take a little more
    1330 time. I can send the proofs back by Monday Nov 9, but probably earlier.
    1331 
    1332 
    1333 
    1334 From: "Pacaanas, Joel -" <jpacaanas@wiley.com>
    1335 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
    1336 CC: "tdelisle@uwaterloo.ca" <tdelisle@uwaterloo.ca>
    1337 Subject: RE: Action: Proof of SPE_EV_SPE2925 for Software: Practice And Experience ready for review
    1338 Date: Fri, 20 Nov 2020 05:27:18 +0000
    1339 
    1340 Dear Peter,
    1341 
    1342 We have now reset the proof back to original stage. Please refer to the below editable link.
    1343 
    1344 https://wiley.eproofing.in/Proof.aspx?token=ab7739d5678447fbbe5036f3bcba2445081500061
    1345 
    1346 Since the proof was reset, your added corrections before has also been removed. Please add them back.
    1347 
    1348 Please return your corrections at your earliest convenience.
    1349 
    1350 Best regards,
    1351 Joel
    1352 
    1353 Joel Q. Pacaanas
    1354 Production Editor
    1355 On behalf of Wiley
    1356 Manila
    1357 We partner with global experts to further innovative research.
    1358 
    1359 E-mail: jpacaanas@wiley.com
    1360 Tel: +632 88558618
    1361 Fax: +632 5325 0768
    1362 
    1363 
    1364  
    1365 From: "Wiley Online Proofing" <notifications@eproofing.in>
    1366 To: pabuhr@uwaterloo.ca
    1367 Cc: SPEproofs@wiley.com
    1368 Reply-To: eproofing@wiley.com
    1369 Date: 26 Nov 2020 18:57:27 +0000
    1370 Subject: Corrections successfully submitted for SPE_EV_SPE2925, Advanced control-flow in Cforall.
    1371 
    1372 Corrections successfully submitted
    1373 
    1374 Dear Dr. Peter Buhr,
    1375 
    1376 Thank you for reviewing the proof of the Software: Practice And Experience article Advanced control-flow in Cforall.
    1377 
    1378 View Article https://wiley.eproofing.in/Proof.aspx?token=ab7739d5678447fbbe5036f3bcba2445081500061
    1379 
    1380 This is a read-only version of your article with the corrections you have marked up.
    1381 
    1382 If you encounter any problems or have questions please contact me, Joel Pacaanas at (SPEproofs@wiley.com). For the quickest response include the journal name and your article ID (found in the subject line) in all correspondence.
    1383 
    1384 Best regards,
    1385 Joel Pacaanas
  • doc/proposals/vtable.md

    reef8dfb rbdfc032  
    237237default is provided or not, the second syntax can be used to pick a
    238238parameter on instantiation.
    239 
    240 ### Extension: Object Access
    241 This requires that the resolution scope (see below) is at the type level or
    242 has explicate points with names. These are the tables and table names used
    243 here.
    244 
    245 The system already knows where to find the virtual table and the object. If
    246 the tables have particular identities, or on the user side names, then it is
    247 meaningful to check if a binding virtual table is the same* as another. The
    248 main use of this is virtual table declarations also give the type they bind
    249 and if a binding table matches a known table then the underlyind object in the
    250 trait object must be of that type.
    251 
    252 * By identity, by value would work and in some senses be more flexiable. But
    253   it would be slower and refering to further away functions would be harder.
    254 
    255 This gives one of the main new features of the hierarchical use of virtual
    256 tables (see below); the ability to recover the underlying object. Or a pointer
    257 of the approprate type it which both reflects the implementation and gives a
    258 convenent way to encode the boolean/conditional aspect of the operation which
    259 is that a different virtual table might be in use.
    260 
    261 There are two general ways to reperent this; a cast or a field access. The
    262 cast is traditional and would definitely fit if a single pointer repersents
    263 a trait object with the virtual table as part of the object. However for a
    264 double pointer field access might be more approprate. By this system though
    265 it is not the type that is used as the identifier but the virtual table. If
    266 there is one table per type than it becomes equivilant again. Otherwise the
    267 table has to be used as the identifier and the type is just a result of that
    268 which seems important for syntax.
    269239
    270240Hierarchy
     
    512482possibly like the one used to create the assertion.
    513483
    514 ### Extension: Associated Types Use
    515 If the `associated_types.md` proposal is accepted the following trait could
    516 be added:
    517 
    518     trait is_virtual(dtype T) {
    519         dtype table;
    520         // An example assertion:
    521         const table & get_virtual_table(T &);
    522     }
    523 
    524 There may be more assertions but there has to be at least one way to find
    525 the (possibly default) virtual table. It is required to construct instances
    526 of the type.
    527 
    528 Without the assotiated type it would look like this:
    529 
    530     trait is_virtual(dtype T, dtype table) {
    531         const table & get_virtual_table(T &);
    532     }
    533 
    534 Which is just a little bit longer to use but becomes more problematic if the
    535 user has to explicately provide the table's name as it doesn't really have its
    536 own type name. If it does it is probably mangled.
    537 
    538484### Virtual Tables as Types
    539485Here we consider encoding plus the implementation of functions on it to be a
     
    614560be used in only some of the declarations.
    615561
    616     trait combiner fee = {summation_instance, sum};
     562    trait combiner fee = (summation_instance, sum);
    617563    trait combiner foe = summation_instance;
    618564
  • doc/refrat/refrat.tex

    reef8dfb rbdfc032  
    1111%% Created On       : Wed Apr  6 14:52:25 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon Oct  5 09:02:53 2020
    14 %% Update Count     : 110
     13%% Last Modified On : Wed Jan 31 17:30:23 2018
     14%% Update Count     : 108
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    3030\usepackage{upquote}                                                                    % switch curled `'" to straight
    3131\usepackage{calc}
     32\usepackage{xspace}
    3233\usepackage{varioref}                                                                   % extended references
     34\usepackage{listings}                                                                   % format program code
    3335\usepackage[flushmargin]{footmisc}                                              % support label/reference in footnote
    3436\usepackage{latexsym}                                   % \Box glyph
    3537\usepackage{mathptmx}                                   % better math font with "times"
    3638\usepackage[usenames]{color}
    37 \newcommand{\CFALatin}{}
     39\input{common}                                          % common CFA document macros
     40\usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref}
     41\usepackage{breakurl}
     42\renewcommand{\UrlFont}{\small\sf}
     43
     44\usepackage[pagewise]{lineno}
     45\renewcommand{\linenumberfont}{\scriptsize\sffamily}
     46\usepackage[firstpage]{draftwatermark}
     47\SetWatermarkLightness{0.9}
     48
     49% Default underscore is too low and wide. Cannot use lstlisting "literate" as replacing underscore
     50% removes it as a variable-name character so keywords in variables are highlighted. MUST APPEAR
     51% AFTER HYPERREF.
     52\renewcommand{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}}
     53
     54\setlength{\topmargin}{-0.45in}                                                 % move running title into header
     55\setlength{\headsep}{0.25in}
     56
     57%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     58
     59\CFAStyle                                                                                               % use default CFA format-style
     60\lstnewenvironment{C++}[1][]                            % use C++ style
     61{\lstset{language=C++,moredelim=**[is][\protect\color{red}]{Ā®}{Ā®}#1}}
     62{}
     63
    3864% inline code Ā©...Ā© (copyright symbol) emacs: C-q M-)
    3965% red highlighting Ā®...Ā® (registered trademark symbol) emacs: C-q M-.
     
    4369% keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^
    4470% math escape $...$ (dollar symbol)
    45 \input{common}                                          % common CFA document macros
    46 \usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref}
    47 \usepackage{breakurl}
    48 \renewcommand{\UrlFont}{\small\sf}
    49 
    50 \usepackage[pagewise]{lineno}
    51 \renewcommand{\linenumberfont}{\scriptsize\sffamily}
    52 \usepackage[firstpage]{draftwatermark}
    53 \SetWatermarkLightness{0.9}
    54 
    55 % Default underscore is too low and wide. Cannot use lstlisting "literate" as replacing underscore
    56 % removes it as a variable-name character so keywords in variables are highlighted. MUST APPEAR
    57 % AFTER HYPERREF.
    58 \renewcommand{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}}
    59 
    60 \setlength{\topmargin}{-0.45in}                                                 % move running title into header
    61 \setlength{\headsep}{0.25in}
    6271
    6372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    6473
    65 \CFAStyle                                                                                               % use default CFA format-style
    66 \lstnewenvironment{C++}[1][]                            % use C++ style
    67 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{Ā®}{Ā®},#1}}
    68 {}
    69 
    70 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    71 
    7274% Names used in the document.
    73 \newcommand{\Version}{\input{build/version}}
     75\newcommand{\Version}{\input{../../version}}
    7476\newcommand{\Textbf}[2][red]{{\color{#1}{\textbf{#2}}}}
    7577\newcommand{\Emph}[2][red]{{\color{#1}\textbf{\emph{#2}}}}
  • doc/user/Makefile

    reef8dfb rbdfc032  
    5555
    5656${DOCUMENT} : ${BASE}.ps
    57         ps2pdf -dPDFSETTINGS=/prepress $<
     57        ps2pdf $<
    5858
    5959${BASE}.ps : ${BASE}.dvi
  • doc/user/user.tex

    reef8dfb rbdfc032  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon Oct  5 08:57:29 2020
    14 %% Update Count     : 3998
     13%% Last Modified On : Sat Jul 13 18:36:18 2019
     14%% Update Count     : 3876
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    3030\usepackage{upquote}                                                                    % switch curled `'" to straight
    3131\usepackage{calc}
     32\usepackage{xspace}
    3233\usepackage{varioref}                                                                   % extended references
    33 \usepackage[labelformat=simple,aboveskip=0pt,farskip=0pt]{subfig}
    34 \renewcommand{\thesubfigure}{\alph{subfigure})}
     34\usepackage{listings}                                                                   % format program code
    3535\usepackage[flushmargin]{footmisc}                                              % support label/reference in footnote
    3636\usepackage{latexsym}                                   % \Box glyph
    3737\usepackage{mathptmx}                                   % better math font with "times"
    3838\usepackage[usenames]{color}
    39 \newcommand{\CFALatin}{}
     39\input{common}                                          % common CFA document macros
     40\usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref}
     41\usepackage{breakurl}
     42
     43\usepackage[pagewise]{lineno}
     44\renewcommand{\linenumberfont}{\scriptsize\sffamily}
     45\usepackage[firstpage]{draftwatermark}
     46\SetWatermarkLightness{0.9}
     47
     48% Default underscore is too low and wide. Cannot use lstlisting "literate" as replacing underscore
     49% removes it as a variable-name character so keywords in variables are highlighted. MUST APPEAR
     50% AFTER HYPERREF.
     51\renewcommand{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}}
     52
     53\setlength{\topmargin}{-0.45in}                                                 % move running title into header
     54\setlength{\headsep}{0.25in}
     55
     56%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     57
     58\CFAStyle                                                                                               % use default CFA format-style
     59\lstnewenvironment{C++}[1][]                            % use C++ style
     60{\lstset{language=C++,moredelim=**[is][\protect\color{red}]{Ā®}{Ā®},#1}}
     61{}
     62
    4063% inline code Ā©...Ā© (copyright symbol) emacs: C-q M-)
    4164% red highlighting Ā®...Ā® (registered trademark symbol) emacs: C-q M-.
     
    4568% keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^
    4669% math escape $...$ (dollar symbol)
    47 \input{common}                                          % common CFA document macros
    48 \usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref}
    49 \usepackage{breakurl}
    50 
    51 \renewcommand\footnoterule{\kern -3pt\rule{0.3\linewidth}{0.15pt}\kern 2pt}
    52 
    53 \usepackage[pagewise]{lineno}
    54 \renewcommand{\linenumberfont}{\scriptsize\sffamily}
    55 \usepackage[firstpage]{draftwatermark}
    56 \SetWatermarkLightness{0.9}
    57 
    58 % Default underscore is too low and wide. Cannot use lstlisting "literate" as replacing underscore
    59 % removes it as a variable-name character so keywords in variables are highlighted. MUST APPEAR
    60 % AFTER HYPERREF.
    61 \renewcommand{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}}
    62 
    63 \setlength{\topmargin}{-0.45in}                                                 % move running title into header
    64 \setlength{\headsep}{0.25in}
    65 
    66 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    67 
    68 \CFAStyle                                                                                               % use default CFA format-style
    69 \lstnewenvironment{C++}[1][]                            % use C++ style
    70 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{Ā®}{Ā®},#1}}
    71 {}
    72 
    73 \newsavebox{\myboxA}
    74 \newsavebox{\myboxB}
    7570
    7671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    8479\newcommand{\G}[1]{{\Textbf[OliveGreen]{#1}}}
    8580\newcommand{\KWC}{K-W C\xspace}
     81
     82\newsavebox{\LstBox}
    8683
    8784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    214211Even with all its problems, C continues to be popular because it allows writing software at virtually any level in a computer system without restriction.
    215212For system programming, where direct access to hardware, storage management, and real-time issues are a requirement, C is usually the only language of choice.
    216 The TIOBE index~\cite{TIOBE} for February 2020 ranks the top six most \emph{popular} programming languages as \Index*{Java} 17.4\%, C 16.8\%, Python 9.3\%, \Index*[C++]{\CC{}} 6.2\%, \Csharp 5.9\%, Visual Basic 5.9\% = 61.5\%, where the next 50 languages are less than 2\% each, with a long tail.
    217 The top 4 rankings over the past 35 years are:
     213The TIOBE index~\cite{TIOBE} for July 2018 ranks the top five most \emph{popular} programming languages as \Index*{Java} 16\%, C 14\%, \Index*[C++]{\CC{}} 7.5\%, Python 6\%, Visual Basic 4\% = 47.5\%, where the next 50 languages are less than 4\% each, with a long tail.
     214The top 3 rankings over the past 30 years are:
    218215\begin{center}
    219216\setlength{\tabcolsep}{10pt}
    220 \begin{tabular}{@{}rcccccccc@{}}
    221                 & 2020  & 2015  & 2010  & 2005  & 2000  & 1995  & 1990  & 1985  \\ \hline
    222 Java    & 1             & 2             & 1             & 2             & 3             & -             & -             & -             \\
    223 \R{C}   & \R{2} & \R{1} & \R{2} & \R{1} & \R{1} & \R{2} & \R{1} & \R{1} \\
    224 Python  & 3             & 7             & 6             & 6             & 22    & 21    & -             & -             \\
    225 \CC             & 4             & 4             & 4             & 3             & 2             & 1             & 2             & 12    \\
     217\begin{tabular}{@{}rccccccc@{}}
     218                & 2018  & 2013  & 2008  & 2003  & 1998  & 1993  & 1988  \\ \hline
     219Java    & 1             & 2             & 1             & 1             & 16    & -             & -             \\
     220\R{C}   & \R{2} & \R{1} & \R{2} & \R{2} & \R{1} & \R{1} & \R{1} \\
     221\CC             & 3             & 4             & 3             & 3             & 2             & 2             & 5             \\
    226222\end{tabular}
    227223\end{center}
     
    256252
    257253The signature feature of \CFA is \emph{\Index{overload}able} \Index{parametric-polymorphic} functions~\cite{forceone:impl,Cormack90,Duggan96} with functions generalized using a ©forall© clause (giving the language its name):
    258 \begin{cfa}
     254\begin{lstlisting}
    259255®forall( otype T )® T identity( T val ) { return val; }
    260256int forty_two = identity( 42 ); §\C{// T is bound to int, forty\_two == 42}§
    261 \end{cfa}
     257\end{lstlisting}
    262258% extending the C type system with parametric polymorphism and overloading, as opposed to the \Index*[C++]{\CC{}} approach of object-oriented extensions.
    263259\CFA{}\hspace{1pt}'s polymorphism was originally formalized by \Index*{Glen Ditchfield}\index{Ditchfield, Glen}~\cite{Ditchfield92}, and first implemented by \Index*{Richard Bilson}\index{Bilson, Richard}~\cite{Bilson03}.
     
    278274\begin{comment}
    279275A simple example is leveraging the existing type-unsafe (©void *©) C ©bsearch© to binary search a sorted floating array:
    280 \begin{cfa}
     276\begin{lstlisting}
    281277void * bsearch( const void * key, const void * base, size_t dim, size_t size,
    282278                                int (* compar)( const void *, const void * ));
     
    287283double key = 5.0, vals[10] = { /* 10 sorted floating values */ };
    288284double * val = (double *)bsearch( &key, vals, 10, sizeof(vals[0]), comp ); §\C{// search sorted array}§
    289 \end{cfa}
     285\end{lstlisting}
    290286which can be augmented simply with a polymorphic, type-safe, \CFA-overloaded wrappers:
    291 \begin{cfa}
     287\begin{lstlisting}
    292288forall( otype T | { int ?<?( T, T ); } ) T * bsearch( T key, const T * arr, size_t size ) {
    293289        int comp( const void * t1, const void * t2 ) { /* as above with double changed to T */ }
     
    300296double * val = bsearch( 5.0, vals, 10 ); §\C{// selection based on return type}§
    301297int posn = bsearch( 5.0, vals, 10 );
    302 \end{cfa}
     298\end{lstlisting}
    303299The nested function ©comp© provides the hidden interface from typed \CFA to untyped (©void *©) C, plus the cast of the result.
    304300Providing a hidden ©comp© function in \CC is awkward as lambdas do not use C calling-conventions and template declarations cannot appear at block scope.
     
    308304\CFA has replacement libraries condensing hundreds of existing C functions into tens of \CFA overloaded functions, all without rewriting the actual computations.
    309305For example, it is possible to write a type-safe \CFA wrapper ©malloc© based on the C ©malloc©:
    310 \begin{cfa}
     306\begin{lstlisting}
    311307forall( dtype T | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); }
    312308int * ip = malloc(); §\C{// select type and size from left-hand side}§
    313309double * dp = malloc();
    314310struct S {...} * sp = malloc();
    315 \end{cfa}
     311\end{lstlisting}
    316312where the return type supplies the type/size of the allocation, which is impossible in most type systems.
    317313\end{comment}
     
    516512Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism:
    517513\begin{cfa}
    518 int Ā®``Ā®otype = 3; §\C{// make keyword an identifier}§
    519 double Ā®``Ā®forall = 3.5;
     514int Ā®`Ā®otypeĀ®`Ā® = 3; §\C{// make keyword an identifier}§
     515double Ā®`Ā®forallĀ®`Ā® = 3.5;
    520516\end{cfa}
    521517
     
    528524// include file uses the CFA keyword "with".
    529525#if ! defined( with ) §\C{// nesting ?}§
    530 #define with Ā®``Ā®with §\C{// make keyword an identifier}§
     526#define with Ā®`Ā®withĀ®`Ā® §\C{// make keyword an identifier}§
    531527#define __CFA_BFD_H__
    532528#endif
    533 Ā§{\color{red}\#\textbf{include\_next} <bfdlink.h>}§ §\C{// must have internal check for multiple expansion}§
     529
     530Ā®#include_next <bfdlink.h> §\C{// must have internal check for multiple expansion}§
     531Ā®
    534532#if defined( with ) && defined( __CFA_BFD_H__ ) §\C{// reset only if set}§
    535533#undef with
     
    578576\section{Exponentiation Operator}
    579577
    580 C, \CC, and Java (and many other programming languages) have no exponentiation operator\index{exponentiation!operator}\index{operator!exponentiation}, \ie $x^y$, and instead use a routine, like \Indexc{pow(x,y)}, to perform the exponentiation operation.
    581 \CFA extends the basic operators with the exponentiation operator Ā©?Ā®\Ā®?Ā©\index{?\\?@Ā©?Ā®\Ā®?Ā©} and Ā©?\=?Ā©\index{?\\=?@©®\Ā®=?Ā©}, as in, Ā©x Ā®\Ā® yĀ© and Ā©x Ā®\Ā®= yĀ©, which means $x^y$ and $x \leftarrow x^y$.
     578C, \CC, and Java (and many other programming languages) have no exponentiation operator\index{exponentiation!operator}\index{operator!exponentiation}, \ie $x^y$, and instead use a routine, like \Indexc{pow}, to perform the exponentiation operation.
     579\CFA extends the basic operators with the exponentiation operator Ā©?\?Ā©\index{?\\?@Ā©?\?Ā©} and Ā©?\=?Ā©\index{?\\=?@Ā©\=?Ā©}, as in, Ā©x \ yĀ© and Ā©x \= yĀ©, which means $x^y$ and $x \leftarrow x^y$.
    582580The priority of the exponentiation operator is between the cast and multiplicative operators, so that ©w * (int)x \ (int)y * z© is parenthesized as ©((w * (((int)x) \ ((int)y))) * z)©.
    583581
    584 There are exponentiation operators for integral and floating types, including the builtin \Index{complex} types.
     582As for \Index{division}, there are exponentiation operators for integral and floating types, including the builtin \Index{complex} types.
    585583Integral exponentiation\index{exponentiation!unsigned integral} is performed with repeated multiplication\footnote{The multiplication computation is $O(\log y)$.} (or shifting if the exponent is 2).
    586 Overflow for a large exponent or negative exponent returns zero.
     584Overflow from large exponents or negative exponents return zero.
    587585Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative.
    588586\begin{cfa}
     
    5915891 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i
    592590\end{cfa}
    593 Note, Ā©5 \ 32Ā© and Ā©5L \ 64Ā© overflow, and Ā©-4 \ -3Ā© is a fraction but stored in an integer so all three computations generate an integral zero.
     591Note, Ā©5 Ā®\Ā® 32Ā© and Ā©5L Ā®\Ā® 64Ā© overflow, and Ā©-4 Ā®\Ā® -3Ā© is a fraction but stored in an integer so all three computations generate an integral zero.
    594592Parenthesis are necessary for complex constants or the expression is parsed as ©1.0f+®(®2.0fi \ 3.0f®)®+2.0fi©.
    595593The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation version is available.
     
    600598OT ?Ā®\Ā®?( OT ep, unsigned long int y );
    601599\end{cfa}
    602 The user type Ā©TĀ© must define multiplication, one (Ā©1Ā©), and Ā©*Ā©.
     600The user type Ā©TĀ© must define multiplication, one, Ā©1Ā©, and, Ā©*Ā©.
    603601
    604602
     
    628626
    629627
    630 %\section{\texorpdfstring{\protect\lstinline@case@ Clause}{case Clause}}
    631 \subsection{\texorpdfstring{\LstKeywordStyle{case} Clause}{case Clause}}
    632 
    633 C restricts the Ā©caseĀ© clause of a Ā©switchĀ© statement to a single value.
    634 For multiple Ā©caseĀ© clauses associated with the same statement, it is necessary to have multiple Ā©caseĀ© clauses rather than multiple values.
    635 Requiring a Ā©caseĀ© clause for each value does not seem to be in the spirit of brevity normally associated with C.
    636 Therefore, the Ā©caseĀ© clause is extended with a list of values, as in:
     628\subsection{Loop Control}
     629
     630The Ā©forĀ©/Ā©whileĀ©/Ā©do-whileĀ© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}).
     631\begin{itemize}
     632\item
     633An empty conditional implies Ā©1Ā©.
     634\item
     635The up-to range Ā©~Ā©\index{~@Ā©~Ā©} means exclusive range [M,N).
     636\item
     637The up-to range Ā©~=Ā©\index{~=@Ā©~=Ā©} means inclusive range [M,N].
     638\item
     639The down-to range Ā©-~Ā©\index{-~@Ā©-~Ā©} means exclusive range [N,M).
     640\item
     641The down-to range Ā©-~=Ā©\index{-~=@Ā©-~=Ā©} means inclusive range [N,M].
     642\item
     643Ā©@Ā© means put nothing in this field.
     644\item
     645Ā©0Ā© is the implicit start value;
     646\item
     647Ā©1Ā© is the implicit increment value.
     648\item
     649The up-to range uses Ā©+=Ā© for increment;
     650\item
     651The down-to range uses Ā©-=Ā© for decrement.
     652\item
     653The loop index is polymorphic in the type of the start value or comparison value when start is implicitly Ā©0Ā©.
     654\end{itemize}
     655
     656\begin{figure}
    637657\begin{cquote}
    638 \begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{}}
    639 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c@{\hspace{2em}}}{\textbf{C}} \\
    640 \begin{cfa}
    641 switch ( i ) {
    642   case Ā®1, 3, 5Ā®:
    643         ...
    644   case Ā®2, 4, 6Ā®:
    645         ...
    646 }
     658\begin{tabular}{@{}l|l@{}}
     659\multicolumn{1}{c|}{loop control} & \multicolumn{1}{c}{output} \\
     660\hline
     661\begin{cfa}
     662sout | nlOff;
     663while Ā®()Ā® { sout | "empty"; break; } sout | nl;
     664do { sout | "empty"; break; } while Ā®()Ā®; sout | nl;
     665for Ā®()Ā® { sout | "empty"; break; } sout | nl;
     666for ( Ā®0Ā® ) { sout | "A"; } sout | "zero" | nl;
     667for ( Ā®1Ā® ) { sout | "A"; } sout | nl;
     668for ( Ā®10Ā® ) { sout | "A"; } sout | nl;
     669for ( Ā®1 ~= 10 ~ 2Ā® ) { sout | "B"; } sout | nl;
     670for ( Ā®10 -~= 1 ~ 2Ā® ) { sout | "C"; } sout | nl;
     671for ( Ā®0.5 ~ 5.5Ā® ) { sout | "D"; } sout | nl;
     672for ( Ā®5.5 -~ 0.5Ā® ) { sout | "E"; } sout | nl;
     673for ( Ā®i; 10Ā® ) { sout | i; } sout | nl;
     674for ( Ā®i; 1 ~= 10 ~ 2Ā® ) { sout | i; } sout | nl;
     675for ( Ā®i; 10 -~= 1 ~ 2Ā® ) { sout | i; } sout | nl;
     676for ( Ā®i; 0.5 ~ 5.5Ā® ) { sout | i; } sout | nl;
     677for ( Ā®i; 5.5 -~ 0.5Ā® ) { sout | i; } sout | nl;
     678for ( Ā®ui; 2u ~= 10u ~ 2uĀ® ) { sout | ui; } sout | nl;
     679for ( Ā®ui; 10u -~= 2u ~ 2uĀ® ) { sout | ui; } sout | nl;
     680enum { N = 10 };
     681for ( Ā®NĀ® ) { sout | "N"; } sout | nl;
     682for ( Ā®i; NĀ® ) { sout | i; } sout | nl;
     683for ( Ā®i; N -~ 0Ā® ) { sout | i; } sout | nl;
     684const int start = 3, comp = 10, inc = 2;
     685for ( Ā®i; start ~ comp ~ inc + 1Ā® ) { sout | i; } sout | nl;
     686for ( Ā®i; 1 ~ @Ā® ) { if ( i > 10 ) break;
     687        sout | i; } sout | nl;
     688for ( Ā®i; 10 -~ @Ā® ) { if ( i < 0 ) break;
     689        sout | i; } sout | nl;
     690for ( Ā®i; 2 ~ @ ~ 2Ā® ) { if ( i > 10 ) break;
     691        sout | i; } sout | nl;
     692for ( Ā®i; 2.1 ~ @ ~ @Ā® ) { if ( i > 10.5 ) break;
     693        sout | i; i += 1.7; } sout | nl;
     694for ( Ā®i; 10 -~ @ ~ 2Ā® ) { if ( i < 0 ) break;
     695        sout | i; } sout | nl;
     696for ( Ā®i; 12.1 ~ @ ~ @Ā® ) { if ( i < 2.5 ) break;
     697        sout | i; i -= 1.7; } sout | nl;
     698for ( Ā®i; 5 : j; -5 ~ @Ā® ) { sout | i | j; } sout | nl;
     699for ( Ā®i; 5 : j; -5 -~ @Ā® ) { sout | i | j; } sout | nl;
     700for ( Ā®i; 5 : j; -5 ~ @ ~ 2Ā® ) { sout | i | j; } sout | nl;
     701for ( Ā®i; 5 : j; -5 -~ @ ~ 2Ā® ) { sout | i | j; } sout | nl;
     702for ( Ā®j; -5 ~ @ : i; 5Ā® ) { sout | i | j; } sout | nl;
     703for ( Ā®j; -5 -~ @ : i; 5Ā® ) { sout | i | j; } sout | nl;
     704for ( Ā®j; -5 ~ @ ~ 2 : i; 5Ā® ) { sout | i | j; } sout | nl;
     705for ( Ā®j; -5 -~ @ ~ 2 : i; 5Ā® ) { sout | i | j; } sout | nl;
     706for ( Ā®j; -5 -~ @ ~ 2 : i; 5 : k; 1.5 ~ @Ā® ) {
     707        sout | i | j | k; } sout | nl;
     708for ( Ā®j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 5Ā® ) {
     709        sout | i | j | k; } sout | nl;
     710for ( Ā®k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 5Ā® ) {
     711        sout | i | j | k; } sout | nl;
    647712\end{cfa}
    648713&
    649714\begin{cfa}
    650 switch ( i ) {
    651   case 1: case 3 : case 5:
    652         ...
    653   case 2: case 4 : case 6:
    654         ...
    655 }
    656 \end{cfa}
    657 &
    658 \begin{cfa}
    659 
    660 // odd values
    661 
    662 // even values
    663 
    664 
     715
     716empty
     717empty
     718empty
     719zero
     720A
     721A A A A A A A A A A
     722B B B B B
     723C C C C C
     724D D D D D
     725E E E E E
     7260 1 2 3 4 5 6 7 8 9
     7271 3 5 7 9
     72810 8 6 4 2
     7290.5 1.5 2.5 3.5 4.5
     7305.5 4.5 3.5 2.5 1.5
     7312 4 6 8 10
     73210 8 6 4 2
     733
     734N N N N N N N N N N
     7350 1 2 3 4 5 6 7 8 9
     73610 9 8 7 6 5 4 3 2 1
     737
     7383 6 9
     739
     7401 2 3 4 5 6 7 8 9 10
     741
     74210 9 8 7 6 5 4 3 2 1 0
     743
     7442 4 6 8 10
     745
     7462.1 3.8 5.5 7.2 8.9
     747
     74810 8 6 4 2 0
     749
     75012.1 10.4 8.7 7 5.3 3.6
     7510 -5 1 -4 2 -3 3 -2 4 -1
     7520 -5 1 -6 2 -7 3 -8 4 -9
     7530 -5 1 -3 2 -1 3 1 4 3
     7540 -5 1 -7 2 -9 3 -11 4 -13
     7550 -5 1 -4 2 -3 3 -2 4 -1
     7560 -5 1 -6 2 -7 3 -8 4 -9
     7570 -5 1 -3 2 -1 3 1 4 3
     7580 -5 1 -7 2 -9 3 -11 4 -13
     759
     7600 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
     761
     7620 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
     763
     7640 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    665765\end{cfa}
    666766\end{tabular}
    667767\end{cquote}
    668 In addition, subranges are allowed to specify case values.\footnote{
    669 gcc has the same mechanism but awkward syntax, \lstinline@2 ...42@, because a space is required after a number, otherwise the period is a decimal point.}
    670 \begin{cfa}
    671 switch ( i ) {
    672   case Ā®1~5:Ā® §\C{// 1, 2, 3, 4, 5}§
    673         ...
    674   case Ā®10~15:Ā® §\C{// 10, 11, 12, 13, 14, 15}§
    675         ...
    676 }
    677 \end{cfa}
    678 Lists of subranges are also allowed.
    679 \begin{cfa}
    680 case Ā®1~5, 12~21, 35~42Ā®:
    681 \end{cfa}
     768\caption{Loop Control Examples}
     769\label{f:LoopControlExamples}
     770\end{figure}
    682771
    683772
     
    888977
    889978
    890 \subsection{Non-terminating and Labelled \texorpdfstring{\LstKeywordStyle{fallthrough}}{Non-terminating and Labelled fallthrough}}
    891 
    892 The Ā©fallthroughĀ© clause may be non-terminating within a Ā©caseĀ© clause or have a target label to common code from multiple case clauses.
    893 \begin{center}
    894 \begin{tabular}{@{}lll@{}}
    895 \begin{cfa}
    896 choose ( ... ) {
    897   case 3:
    898         if ( ... ) {
    899                 ... Ā®fallthru;Ā® // goto case 4
    900         } else {
    901                 ...
    902         }
    903         // implicit break
    904   case 4:
    905 
    906 
    907 
    908 
     979%\section{\texorpdfstring{\protect\lstinline@case@ Clause}{case Clause}}
     980\subsection{\texorpdfstring{\LstKeywordStyle{case} Statement}{case Statement}}
     981
     982C restricts the Ā©caseĀ© clause of a Ā©switchĀ© statement to a single value.
     983For multiple Ā©caseĀ© clauses associated with the same statement, it is necessary to have multiple Ā©caseĀ© clauses rather than multiple values.
     984Requiring a Ā©caseĀ© clause for each value does not seem to be in the spirit of brevity normally associated with C.
     985Therefore, the Ā©caseĀ© clause is extended with a list of values, as in:
     986\begin{cquote}
     987\begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{}}
     988\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c@{\hspace{2em}}}{\textbf{C}} \\
     989\begin{cfa}
     990switch ( i ) {
     991  case Ā®1, 3, 5Ā®:
     992        ...
     993  case Ā®2, 4, 6Ā®:
     994        ...
     995}
    909996\end{cfa}
    910997&
    911998\begin{cfa}
    912 choose ( ... ) {
    913   case 3:
    914         ... Ā®fallthrough common;Ā®
    915   case 4:
    916         ... Ā®fallthrough common;Ā®
    917 
    918   Ā®common:Ā® // below fallthrough
    919                           // at case-clause level
    920         ...     // common code for cases 3/4
    921         // implicit break
    922   case 4:
    923 
    924 
     999switch ( i ) {
     1000  case 1: case 3 : case 5:
     1001        ...
     1002  case 2: case 4 : case 6:
     1003        ...
     1004}
    9251005\end{cfa}
    9261006&
    9271007\begin{cfa}
    928 choose ( ... ) {
    929   case 3:
    930         choose ( ... ) {
    931           case 4:
    932                 for ( ... ) {
    933                         // multi-level transfer
    934                         ... Ā®fallthru common;Ā®
    935                 }
    936                 ...
    937         }
     1008
     1009// odd values
     1010
     1011// even values
     1012
     1013
     1014\end{cfa}
     1015\end{tabular}
     1016\end{cquote}
     1017In addition, subranges are allowed to specify case values.\footnote{
     1018gcc has the same mechanism but awkward syntax, \lstinline@2 ...42@, because a space is required after a number, otherwise the period is a decimal point.}
     1019\begin{cfa}
     1020switch ( i ) {
     1021  case Ā®1~5:Ā® §\C{// 1, 2, 3, 4, 5}§
    9381022        ...
    939   Ā®common:Ā® // below fallthrough
    940                           // at case-clause level
    941 \end{cfa}
    942 \end{tabular}
    943 \end{center}
    944 The target label must be below the Ā©fallthroughĀ© and may not be nested in a control structure, and
    945 the target label must be at the same or higher level as the containing Ā©caseĀ© clause and located at
    946 the same level as a Ā©caseĀ© clause; the target label may be case Ā©defaultĀ©, but only associated
    947 with the current Ā©switchĀ©/Ā©chooseĀ© statement.
    948 
    949 \begin{figure}
    950 \begin{tabular}{@{}l|l@{}}
    951 \multicolumn{1}{c|}{loop control} & \multicolumn{1}{c}{output} \\
    952 \hline
    953 \begin{cfa}[xleftmargin=0pt]
    954 while Ā®()Ā® { sout | "empty"; break; }
    955 do { sout | "empty"; break; } while Ā®()Ā®;
    956 for Ā®()Ā® { sout | "empty"; break; }
    957 for ( Ā®0Ā® ) { sout | "A"; } sout | "zero";
    958 for ( Ā®1Ā® ) { sout | "A"; }
    959 for ( Ā®10Ā® ) { sout | "A"; }
    960 for ( Ā®= 10Ā® ) { sout | "A"; }
    961 for ( Ā®1 ~= 10 ~ 2Ā® ) { sout | "B"; }
    962 for ( Ā®10 -~= 1 ~ 2Ā® ) { sout | "C"; }
    963 for ( Ā®0.5 ~ 5.5Ā® ) { sout | "D"; }
    964 for ( Ā®5.5 -~ 0.5Ā® ) { sout | "E"; }
    965 for ( Ā®i; 10Ā® ) { sout | i; }
    966 for ( Ā®i; = 10Ā® ) { sout | i; }
    967 for ( Ā®i; 1 ~= 10 ~ 2Ā® ) { sout | i; }
    968 for ( Ā®i; 10 -~= 1 ~ 2Ā® ) { sout | i; }
    969 for ( Ā®i; 0.5 ~ 5.5Ā® ) { sout | i; }
    970 for ( Ā®i; 5.5 -~ 0.5Ā® ) { sout | i; }
    971 for ( Ā®ui; 2u ~= 10u ~ 2uĀ® ) { sout | ui; }
    972 for ( Ā®ui; 10u -~= 2u ~ 2uĀ® ) { sout | ui; }
    973 enum { N = 10 };
    974 for ( Ā®NĀ® ) { sout | "N"; }
    975 for ( Ā®i; NĀ® ) { sout | i; }
    976 for ( Ā®i; N -~ 0Ā® ) { sout | i; }
    977 const int start = 3, comp = 10, inc = 2;
    978 for ( Ā®i; start ~ comp ~ inc + 1Ā® ) { sout | i; }
    979 for ( i; 1 ~ Ā®@Ā® ) { if ( i > 10 ) break; sout | i; }
    980 for ( i; 10 -~ Ā®@Ā® ) { if ( i < 0 ) break; sout | i; }
    981 for ( i; 2 ~ Ā®@Ā® ~ 2 ) { if ( i > 10 ) break; sout | i; }
    982 for ( i; 2.1 ~ Ā®@Ā® ~ Ā®@Ā® ) { if ( i > 10.5 ) break; sout | i; i += 1.7; }
    983 for ( i; 10 -~ Ā®@Ā® ~ 2 ) { if ( i < 0 ) break; sout | i; }
    984 for ( i; 12.1 ~ Ā®@Ā® ~ Ā®@Ā® ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; }
    985 for ( i; 5 Ā®:Ā® j; -5 ~ @ ) { sout | i | j; }
    986 for ( i; 5 Ā®:Ā® j; -5 -~ @ ) { sout | i | j; }
    987 for ( i; 5 Ā®:Ā® j; -5 ~ @ ~ 2 ) { sout | i | j; }
    988 for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 ) { sout | i | j; }
    989 for ( i; 5 Ā®:Ā® j; -5 ~ @ ) { sout | i | j; }
    990 for ( i; 5 Ā®:Ā® j; -5 -~ @ ) { sout | i | j; }
    991 for ( i; 5 Ā®:Ā® j; -5 ~ @ ~ 2 ) { sout | i | j; }
    992 for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 ) { sout | i | j; }
    993 for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 Ā®:Ā® k; 1.5 ~ @ ) { sout | i | j | k; }
    994 for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 Ā®:Ā® k; 1.5 ~ @ ) { sout | i | j | k; }
    995 for ( i; 5 Ā®:Ā® k; 1.5 ~ @ Ā®:Ā® j; -5 -~ @ ~ 2 ) { sout | i | j | k; }
    996 \end{cfa}
    997 &
    998 \begin{cfa}
    999 empty
    1000 empty
    1001 empty
    1002 zero
    1003 A
    1004 A A A A A A A A A A
    1005 A A A A A A A A A A A
    1006 B B B B B
    1007 C C C C C
    1008 D D D D D
    1009 E E E E E
    1010 0 1 2 3 4 5 6 7 8 9
    1011 0 1 2 3 4 5 6 7 8 9 10
    1012 1 3 5 7 9
    1013 10 8 6 4 2
    1014 0.5 1.5 2.5 3.5 4.5
    1015 5.5 4.5 3.5 2.5 1.5
    1016 2 4 6 8 10
    1017 10 8 6 4 2
    1018 
    1019 N N N N N N N N N N
    1020 0 1 2 3 4 5 6 7 8 9
    1021 10 9 8 7 6 5 4 3 2 1
    1022 
    1023 3 6 9
    1024 1 2 3 4 5 6 7 8 9 10
    1025 10 9 8 7 6 5 4 3 2 1 0
    1026 2 4 6 8 10
    1027 2.1 3.8 5.5 7.2 8.9
    1028 10 8 6 4 2 0
    1029 12.1 10.4 8.7 7. 5.3 3.6
    1030 0 -5 1 -4 2 -3 3 -2 4 -1
    1031 0 -5 1 -6 2 -7 3 -8 4 -9
    1032 0 -5 1 -3 2 -1 3 1 4 3
    1033 0 -5 1 -7 2 -9 3 -11 4 -13
    1034 0 -5 1 -4 2 -3 3 -2 4 -1
    1035 0 -5 1 -6 2 -7 3 -8 4 -9
    1036 0 -5 1 -3 2 -1 3 1 4 3
    1037 0 -5 1 -7 2 -9 3 -11 4 -13
    1038 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    1039 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    1040 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    1041 \end{cfa}
    1042 \end{tabular}
    1043 \caption{Loop Control Examples}
    1044 \label{f:LoopControlExamples}
    1045 \end{figure}
     1023  case Ā®10~15:Ā® §\C{// 10, 11, 12, 13, 14, 15}§
     1024        ...
     1025}
     1026\end{cfa}
     1027Lists of subranges are also allowed.
     1028\begin{cfa}
     1029case Ā®1~5, 12~21, 35~42Ā®:
     1030\end{cfa}
     1031
    10461032
    10471033% for ()  => for ( ;; )
     
    10541040
    10551041
    1056 \subsection{Loop Control}
    1057 
    1058 The Ā©forĀ©/Ā©whileĀ©/Ā©do-whileĀ© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}).
    1059 \begin{itemize}
    1060 \item
    1061 The loop index is polymorphic in the type of the comparison value N (when the start value is implicit) or the start value M.
    1062 \item
    1063 An empty conditional implies comparison value of Ā©1Ā© (true).
    1064 \item
    1065 A comparison N is implicit up-to exclusive range [0,N©®)®©.
    1066 \item
    1067 A comparison Ā©=Ā© N is implicit up-to inclusive range [0,N©®]®©.
    1068 \item
    1069 The up-to range M Ā©~Ā©\index{~@Ā©~Ā©} N means exclusive range [M,N©®)®©.
    1070 \item
    1071 The up-to range M Ā©~=Ā©\index{~=@Ā©~=Ā©} N means inclusive range [M,N©®]®©.
    1072 \item
    1073 The down-to range M Ā©-~Ā©\index{-~@Ā©-~Ā©} N means exclusive range [N,M©®)®©.
    1074 \item
    1075 The down-to range M Ā©-~=Ā©\index{-~=@Ā©-~=Ā©} N means inclusive range [N,M©®]®©.
    1076 \item
    1077 Ā©0Ā© is the implicit start value;
    1078 \item
    1079 Ā©1Ā© is the implicit increment value.
    1080 \item
    1081 The up-to range uses operator Ā©+=Ā© for increment;
    1082 \item
    1083 The down-to range uses operator Ā©-=Ā© for decrement.
    1084 \item
    1085 Ā©@Ā© means put nothing in this field.
    1086 \item
    1087 Ā©:Ā© means start another index.
    1088 \end{itemize}
    1089 
    1090 
    10911042%\subsection{\texorpdfstring{Labelled \protect\lstinline@continue@ / \protect\lstinline@break@}{Labelled continue / break}}
    10921043\subsection{\texorpdfstring{Labelled \LstKeywordStyle{continue} / \LstKeywordStyle{break} Statement}{Labelled continue / break Statement}}
     
    10981049for ©break©, the target label can also be associated with a ©switch©, ©if© or compound (©{}©) statement.
    10991050\VRef[Figure]{f:MultiLevelExit} shows ©continue© and ©break© indicating the specific control structure, and the corresponding C program using only ©goto© and labels.
    1100 The innermost loop has 8 exit points, which cause continuation or termination of one or more of the 7 \Index{nested control-structure}s.
     1051The innermost loop has 7 exit points, which cause continuation or termination of one or more of the 7 \Index{nested control-structure}s.
    11011052
    11021053\begin{figure}
    1103 \centering
    1104 \begin{lrbox}{\myboxA}
    1105 \begin{cfa}[tabsize=3]
    1106 Ā®Compound:Ā® {
    1107         Ā®Try:Ā® try {
    1108                 Ā®For:Ā® for ( ... ) {
    1109                         Ā®While:Ā® while ( ... ) {
    1110                                 Ā®Do:Ā® do {
    1111                                         Ā®If:Ā® if ( ... ) {
    1112                                                 Ā®Switch:Ā® switch ( ... ) {
    1113                                                         case 3:
    1114                                                                 Ā®break CompoundĀ®;
    1115                                                                 Ā®break TryĀ®;
    1116                                                                 Ā®break ForĀ®;      /* or */  Ā®continue ForĀ®;
    1117                                                                 Ā®break WhileĀ®;  /* or */  Ā®continue WhileĀ®;
    1118                                                                 Ā®break DoĀ®;      /* or */  Ā®continue DoĀ®;
    1119                                                                 Ā®break IfĀ®;
    1120                                                                 Ā®break SwitchĀ®;
    1121                                                         } // switch
    1122                                                 } else {
    1123                                                         ... Ā®break IfĀ®; ...     // terminate if
    1124                                                 } // if
    1125                                 } while ( ... ); // do
    1126                         } // while
    1127                 } // for
    1128         } Ā®finallyĀ® { // always executed
    1129         } // try
     1054\begin{tabular}{@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}}
     1055\multicolumn{1}{@{\hspace{\parindentlnth}}c@{\hspace{\parindentlnth}}}{\textbf{\CFA}}   & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}}      \\
     1056\begin{cfa}
     1057Ā®LC:Ā® {
     1058        ... §declarations§ ...
     1059        Ā®LS:Ā® switch ( ... ) {
     1060          case 3:
     1061                Ā®LIF:Ā® if ( ... ) {
     1062                        Ā®LF:Ā® for ( ... ) {
     1063                                Ā®LW:Ā® while ( ... ) {
     1064                                        ... break Ā®LCĀ®; ...
     1065                                        ... break Ā®LSĀ®; ...
     1066                                        ... break Ā®LIFĀ®; ...
     1067                                        ... continue Ā®LF;Ā® ...
     1068                                        ... break Ā®LFĀ®; ...
     1069                                        ... continue Ā®LWĀ®; ...
     1070                                        ... break Ā®LWĀ®; ...
     1071                                } // while
     1072                        } // for
     1073                } else {
     1074                        ... break Ā®LIFĀ®; ...
     1075                } // if
     1076        } // switch
    11301077} // compound
    11311078\end{cfa}
    1132 \end{lrbox}
    1133 
    1134 \begin{lrbox}{\myboxB}
    1135 \begin{cfa}[tabsize=3]
     1079&
     1080\begin{cfa}
    11361081{
    1137 
    1138                 Ā®ForC:Ā® for ( ... ) {
    1139                         Ā®WhileC:Ā® while ( ... ) {
    1140                                 Ā®DoC:Ā® do {
    1141                                         if ( ... ) {
    1142                                                 switch ( ... ) {
    1143                                                         case 3:
    1144                                                                 Ā®goto CompoundĀ®;
    1145                                                                 Ā®goto TryĀ®;
    1146                                                                 Ā®goto ForBĀ®;      /* or */  Ā®goto ForCĀ®;
    1147                                                                 Ā®goto WhileBĀ®;  /* or */  Ā®goto WhileCĀ®;
    1148                                                                 Ā®goto DoBĀ®;      /* or */  Ā®goto DoCĀ®;
    1149                                                                 Ā®goto IfĀ®;
    1150                                                                 Ā®goto SwitchĀ®;
    1151                                                         } Ā®Switch:Ā® ;
    1152                                                 } else {
    1153                                                         ... Ā®goto IfĀ®; ...      // terminate if
    1154                                                 } Ā®If:Ā®;
    1155                                 } while ( ... ); Ā®DoB:Ā® ;
    1156                         } Ā®WhileB:Ā® ;
    1157                 } Ā®ForB:Ā® ;
    1158 
    1159 
    1160 } Ā®Compound:Ā® ;
    1161 \end{cfa}
    1162 \end{lrbox}
    1163 
    1164 \subfloat[\CFA]{\label{f:CFibonacci}\usebox\myboxA}
    1165 \hspace{2pt}
    1166 \vrule
    1167 \hspace{2pt}
    1168 \subfloat[C]{\label{f:CFAFibonacciGen}\usebox\myboxB}
     1082        ... §declarations§ ...
     1083        switch ( ... ) {
     1084          case 3:
     1085                if ( ... ) {
     1086                        for ( ... ) {
     1087                                while ( ... ) {
     1088                                        ... goto Ā®LCĀ®; ...
     1089                                        ... goto Ā®LSĀ®; ...
     1090                                        ... goto Ā®LIFĀ®; ...
     1091                                        ... goto Ā®LFCĀ®; ...
     1092                                        ... goto Ā®LFBĀ®; ...
     1093                                        ... goto Ā®LWCĀ®; ...
     1094                                        ... goto Ā®LWBĀ®; ...
     1095                                  Ā®LWCĀ®: ; } Ā®LWB:Ā® ;
     1096                          Ā®LFC:Ā® ; } Ā®LFB:Ā® ;
     1097                } else {
     1098                        ... goto Ā®LIFĀ®; ...
     1099                } Ā®L3:Ā® ;
     1100        } Ā®LS:Ā® ;
     1101} Ā®LC:Ā® ;
     1102\end{cfa}
     1103&
     1104\begin{cfa}
     1105
     1106
     1107
     1108
     1109
     1110
     1111
     1112// terminate compound
     1113// terminate switch
     1114// terminate if
     1115// continue loop
     1116// terminate loop
     1117// continue loop
     1118// terminate loop
     1119
     1120
     1121
     1122// terminate if
     1123
     1124
     1125
     1126\end{cfa}
     1127\end{tabular}
    11691128\caption{Multi-level Exit}
    11701129\label{f:MultiLevelExit}
     
    14211380try {
    14221381        f(...);
    1423 } catch( E e ; §boolean-predicate§ ) {          §\C{// termination handler}§
     1382} catch( E e ; §boolean-predicate§ ) {          §\C[8cm]{// termination handler}§
    14241383        // recover and continue
    1425 } catchResume( E e ; §boolean-predicate§ ) { §\C{// resumption handler}§
     1384} catchResume( E e ; §boolean-predicate§ ) { §\C{// resumption handler}\CRT§
    14261385        // repair and return
    14271386} finally {
     
    34863445For implicit formatted input, the common case is reading a sequence of values separated by whitespace, where the type of an input constant must match with the type of the input variable.
    34873446\begin{cquote}
    3488 \begin{lrbox}{\myboxA}
     3447\begin{lrbox}{\LstBox}
    34893448\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    34903449int x;   double y   char z;
     
    34923451\end{lrbox}
    34933452\begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{3em}}l@{}}
    3494 \multicolumn{1}{@{}l@{}}{\usebox\myboxA} \\
     3453\multicolumn{1}{@{}l@{}}{\usebox\LstBox} \\
    34953454\multicolumn{1}{c@{\hspace{2em}}}{\textbf{\CFA}}        & \multicolumn{1}{c@{\hspace{2em}}}{\textbf{\CC}}       & \multicolumn{1}{c}{\textbf{Python}}   \\
    34963455\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     
    65886547hence, names in these include files are not mangled\index{mangling!name} (see~\VRef{s:Interoperability}).
    65896548All other C header files must be explicitly wrapped in ©extern "C"© to prevent name mangling.
    6590 This approach is different from \Index*[C++]{\CC{}} where the name-mangling issue is handled internally in C header-files through checks for preprocessor variable Ā©__cplusplusĀ©, which adds appropriate Ā©extern "C"Ā© qualifiers.
     6549For \Index*[C++]{\CC{}}, the name-mangling issue is often handled internally in many C header-files through checks for preprocessor variable Ā©__cplusplusĀ©, which adds appropriate Ā©extern "C"Ā© qualifiers.
    65916550
    65926551
     
    66026561The storage-management routines extend their C equivalents by overloading, alternate names, providing shallow type-safety, and removing the need to specify the allocation size for non-array types.
    66036562
    6604 C storage management provides the following capabilities:
     6563Storage management provides the following capabilities:
    66056564\begin{description}
    6606 \item[filled]
    6607 after allocation with a specified character or value.
     6565\item[fill]
     6566after allocation the storage is filled with a specified character.
    66086567\item[resize]
    6609 an existing allocation to decreased or increased its size.
    6610 In either case, new storage may or may not be allocated and, if there is a new allocation, as much data from the existing allocation is copied into the new allocation.
     6568an existing allocation is decreased or increased in size.
     6569In either case, new storage may or may not be allocated and, if there is a new allocation, as much data from the existing allocation is copied.
    66116570For an increase in storage size, new storage after the copied data may be filled.
    6612 \item[align]
    6613 an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
     6571\item[alignment]
     6572an allocation starts on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
    66146573\item[array]
    66156574the allocation size is scaled to the specified number of array elements.
    66166575An array may be filled, resized, or aligned.
    66176576\end{description}
    6618 \VRef[Table]{t:AllocationVersusCapabilities} shows allocation routines supporting different combinations of storage-management capabilities.
    6619 \begin{table}
    6620 \centering
    6621 \begin{minipage}{0.75\textwidth}
    6622 \begin{tabular}{@{}r|l|l|l|l|l@{}}
     6577The table shows allocation routines supporting different combinations of storage-management capabilities:
     6578\begin{center}
     6579\begin{tabular}{@{}r|r|l|l|l|l@{}}
    66236580\multicolumn{1}{c}{}&           & \multicolumn{1}{c|}{fill}     & resize        & alignment     & array \\
    66246581\hline
    66256582C               & Ā©mallocĀ©                      & no                    & no            & no            & no    \\
    66266583                & Ā©callocĀ©                      & yes (0 only)  & no            & no            & yes   \\
    6627                 & Ā©reallocĀ©                     & copy                  & yes           & no            & no    \\
     6584                & Ā©reallocĀ©                     & no/copy               & yes           & no            & no    \\
    66286585                & Ā©memalignĀ©            & no                    & no            & yes           & no    \\
    6629                 & Ā©aligned_allocĀ©\footnote{Same as Ā©memalignĀ© but size is an integral multiple of alignment, which is universally ignored.}
    6630                                                         & no                    & no            & yes           & no    \\
    66316586                & Ā©posix_memalignĀ©      & no                    & no            & yes           & no    \\
    6632                 & Ā©vallocĀ©                      & no                    & no            & yes (page size)& no   \\
    6633                 & Ā©pvallocĀ©\footnote{Same as Ā©vallocĀ© but rounds size to multiple of page size.}
    6634                                                         & no                    & no            & yes (page size)& no   \\
    66356587\hline
    6636 \CFA    & Ā©cmemalignĀ©           & yes (0 only)  & no            & yes           & yes   \\
    6637                 & Ā©reallocĀ©                     & copy                  & yes           & yes           & no    \\
    6638                 & Ā©allocĀ©                       & no                    & yes           & no            & yes   \\
    6639                 & Ā©alloc_setĀ©           & yes                   & yes           & no            & yes   \\
    6640                 & Ā©alloc_alignĀ©         & no                    & yes           & yes           & yes   \\
    6641                 & Ā©alloc_align_setĀ©     & yes                   & yes           & yes           & yes   \\
     6588C11             & Ā©aligned_allocĀ©       & no                    & no            & yes           & no    \\
     6589\hline
     6590\CFA    & Ā©allocĀ©                       & no/copy/yes   & no/yes        & no            & yes   \\
     6591                & Ā©align_allocĀ©         & no/yes                & no            & yes           & yes   \\
    66426592\end{tabular}
    6643 \end{minipage}
    6644 \caption{Allocation Routines versus Storage-Management Capabilities}
    6645 \label{t:AllocationVersusCapabilities}
    6646 \end{table}
    6647 
    6648 \CFA memory management extends the type safety of all allocations by using the type of the left-hand-side type to determine the allocation size and return a matching type for the new storage.
    6649 Type-safe allocation is provided for all C allocation routines and new \CFA allocation routines, \eg in
    6650 \begin{cfa}
    6651 int * ip = (int *)malloc( sizeof(int) );                §\C{// C}§
    6652 int * ip = malloc();                                                    §\C{// \CFA type-safe version of C malloc}§
    6653 int * ip = alloc();                                                             Ā§\C{// \CFA type-safe uniform alloc}§
    6654 \end{cfa}
    6655 the latter two allocations determine the allocation size from the type of Ā©pĀ© (Ā©intĀ©) and cast the pointer to the allocated storage to Ā©int *Ā©.
    6656 
    6657 \CFA memory management extends allocation safety by implicitly honouring all alignment requirements, \eg in
    6658 \begin{cfa}
    6659 struct S { int i; } __attribute__(( aligned( 128 ) )); // cache-line alignment
    6660 S * sp = malloc();                                                              §\C{// honour type alignment}§
    6661 \end{cfa}
    6662 the storage allocation is implicitly aligned to 128 rather than the default 16.
    6663 The alignment check is performed at compile time so there is no runtime cost.
    6664 
    6665 \CFA memory management extends the resize capability with the notion of \newterm{sticky properties}.
    6666 Hence, initial allocation capabilities are remembered and maintained when resize requires copying.
    6667 For example, an initial alignment and fill capability are preserved during a resize copy so the copy has the same alignment and extended storage is filled.
    6668 Without sticky properties it is dangerous to use Ā©reallocĀ©, resulting in an idiom of manually performing the reallocation to maintain correctness.
    6669 \begin{cfa}
    6670 
    6671 \end{cfa}
    6672 
    6673 \CFA memory management extends allocation to support constructors for initialization of allocated storage, \eg in
    6674 \begin{cfa}
    6675 struct S { int i; };                                                    §\C{// cache-line aglinment}§
    6676 void ?{}( S & s, int i ) { s.i = i; }
    6677 // assume ?|? operator for printing an S
    6678 
    6679 S & sp = *Ā®newĀ®( 3 );                                                   Ā§\C{// call constructor after allocation}§
    6680 sout | sp.i;
    6681 Ā®deleteĀ®( &sp );
    6682 
    6683 S * spa = Ā®anewĀ®( 10, 5 );                                              §\C{// allocate array and initialize each array element}§
    6684 for ( i; 10 ) sout | spa[i] | nonl;
    6685 sout | nl;
    6686 Ā®adeleteĀ®( 10, spa );
    6687 \end{cfa}
    6688 Allocation routines Ā©newĀ©/Ā©anewĀ© allocate a variable/array and initialize storage using the allocated type's constructor.
    6689 Note, the matching deallocation routines Ā©deleteĀ©/Ā©adeleteĀ©.
     6593\end{center}
     6594It is impossible to resize with alignment because the underlying Ā©reallocĀ© allocates storage if more space is needed, and it does not honour alignment from the original allocation.
    66906595
    66916596\leavevmode
    66926597\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     6598// C unsafe allocation
    66936599extern "C" {
    6694         // C unsafe allocation
    6695         void * malloc( size_t size );§\indexc{malloc}§
    6696         void * calloc( size_t dim, size_t size );§\indexc{calloc}§
    6697         void * realloc( void * ptr, size_t size );§\indexc{realloc}§
    6698         void * memalign( size_t align, size_t size );§\indexc{memalign}§
    6699         void * aligned_alloc( size_t align, size_t size );§\indexc{aligned_alloc}§
    6700         int posix_memalign( void ** ptr, size_t align, size_t size );§\indexc{posix_memalign}§
    6701         void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize );§\indexc{cmemalign}§ // CFA
    6702 
    6703         // C unsafe initialization/copy
    6704         void * memset( void * dest, int c, size_t size );§\indexc{memset}§
    6705         void * memcpy( void * dest, const void * src, size_t size );§\indexc{memcpy}§
    6706 }
    6707 
    6708 void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap
     6600void * malloc( size_t size );§\indexc{memset}§
     6601void * calloc( size_t dim, size_t size );§\indexc{calloc}§
     6602void * realloc( void * ptr, size_t size );§\indexc{realloc}§
     6603void * memalign( size_t align, size_t size );§\indexc{memalign}§
     6604int posix_memalign( void ** ptr, size_t align, size_t size );§\indexc{posix_memalign}§
     6605
     6606// C unsafe initialization/copy
     6607void * memset( void * dest, int c, size_t size );
     6608void * memcpy( void * dest, const void * src, size_t size );
     6609}
    67096610
    67106611forall( dtype T | sized(T) ) {
    6711         // §\CFA§ safe equivalents, i.e., implicit size specification
     6612// §\CFA§ safe equivalents, i.e., implicit size specification
    67126613        T * malloc( void );
    67136614        T * calloc( size_t dim );
    67146615        T * realloc( T * ptr, size_t size );
    67156616        T * memalign( size_t align );
    6716         T * cmemalign( size_t align, size_t dim  );
    67176617        T * aligned_alloc( size_t align );
    67186618        int posix_memalign( T ** ptr, size_t align );
    67196619
    6720         // §\CFA§ safe general allocation, fill, resize, alignment, array
    6721         T * alloc( void );§\indexc{alloc}§                                      §\C[3.5in]{// variable, T size}§
    6722         T * alloc( size_t dim );                                                        §\C{// array[dim], T size elements}§
    6723         T * alloc( T ptr[], size_t dim );                                       Ā§\C{// realloc array[dim], T size elements}§
    6724 
    6725         T * alloc_set( char fill );§\indexc{alloc_set}§         Ā§\C{// variable, T size, fill bytes with value}§
    6726         T * alloc_set( T fill );                                                        §\C{// variable, T size, fill with value}§
    6727         T * alloc_set( size_t dim, char fill );                         Ā§\C{// array[dim], T size elements, fill bytes with value}§
    6728         T * alloc_set( size_t dim, T fill );                            §\C{// array[dim], T size elements, fill elements with value}§
    6729         T * alloc_set( size_t dim, const T fill[] );            §\C{// array[dim], T size elements, fill elements with array}§
    6730         T * alloc_set( T ptr[], size_t dim, char fill );        §\C{// realloc array[dim], T size elements, fill bytes with value}§
    6731 
    6732         T * alloc_align( size_t align );                                        §\C{// aligned variable, T size}§
    6733         T * alloc_align( size_t align, size_t dim );            §\C{// aligned array[dim], T size elements}§
    6734         T * alloc_align( T ptr[], size_t align );                       Ā§\C{// realloc new aligned array}§
    6735         T * alloc_align( T ptr[], size_t align, size_t dim ); §\C{// realloc new aligned array[dim]}§
    6736 
    6737         T * alloc_align_set( size_t align, char fill );         Ā§\C{// aligned variable, T size, fill bytes with value}§
    6738         T * alloc_align_set( size_t align, T fill );            §\C{// aligned variable, T size, fill with value}§
    6739         T * alloc_align_set( size_t align, size_t dim, char fill ); §\C{// aligned array[dim], T size elements, fill bytes with value}§
    6740         T * alloc_align_set( size_t align, size_t dim, T fill ); §\C{// aligned array[dim], T size elements, fill elements with value}§
    6741         T * alloc_align_set( size_t align, size_t dim, const T fill[] ); §\C{// aligned array[dim], T size elements, fill elements with array}§
    6742         T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); §\C{// realloc new aligned array[dim], fill new bytes with value}§
    6743 
    6744         // §\CFA§ safe initialization/copy, i.e., implicit size specification
    6745         T * memset( T * dest, char fill );§\indexc{memset}§
     6620// §\CFA§ safe general allocation, fill, resize, array
     6621        T * alloc( void );§\indexc{alloc}§
     6622        T * alloc( char fill );
     6623        T * alloc( size_t dim );
     6624        T * alloc( size_t dim, char fill );
     6625        T * alloc( T ptr[], size_t dim );
     6626        T * alloc( T ptr[], size_t dim, char fill );
     6627
     6628// §\CFA§ safe general allocation, align, fill, array
     6629        T * align_alloc( size_t align );
     6630        T * align_alloc( size_t align, char fill );
     6631        T * align_alloc( size_t align, size_t dim );
     6632        T * align_alloc( size_t align, size_t dim, char fill );
     6633
     6634// §\CFA§ safe initialization/copy, i.e., implicit size specification
     6635        T * memset( T * dest, char c );§\indexc{memset}§
    67466636        T * memcpy( T * dest, const T * src );§\indexc{memcpy}§
    67476637
    6748         // §\CFA§ safe initialization/copy, i.e., implicit size specification, array types
    6749         T * amemset( T dest[], char fill, size_t dim );
     6638// §\CFA§ safe initialization/copy array
     6639        T * amemset( T dest[], char c, size_t dim );
    67506640        T * amemcpy( T dest[], const T src[], size_t dim );
    67516641}
    67526642
    6753 // §\CFA§ allocation/deallocation and constructor/destructor, non-array types
    6754 forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p );§\indexc{new}§
    6755 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void delete( T * ptr );§\indexc{delete}§
    6756 forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } )
     6643// §\CFA§ allocation/deallocation and constructor/destructor
     6644forall( dtype T | sized(T), ttype Params | { void ?{}( T *, Params ); } ) T * new( Params p );§\indexc{new}§
     6645forall( dtype T | { void ^?{}( T * ); } ) void delete( T * ptr );§\indexc{delete}§
     6646forall( dtype T, ttype Params | { void ^?{}( T * ); void delete( Params ); } )
    67576647  void delete( T * ptr, Params rest );
    67586648
    6759 // §\CFA§ allocation/deallocation and constructor/destructor, array types
    6760 forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p );§\indexc{anew}§
    6761 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );§\indexc{adelete}§
    6762 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } )
     6649// §\CFA§ allocation/deallocation and constructor/destructor, array
     6650forall( dtype T | sized(T), ttype Params | { void ?{}( T *, Params ); } ) T * anew( size_t dim, Params p );§\indexc{anew}§
     6651forall( dtype T | sized(T) | { void ^?{}( T * ); } ) void adelete( size_t dim, T arr[] );§\indexc{adelete}§
     6652forall( dtype T | sized(T) | { void ^?{}( T * ); }, ttype Params | { void adelete( Params ); } )
    67636653  void adelete( size_t dim, T arr[], Params rest );
    67646654\end{cfa}
  • driver/Makefile.am

    reef8dfb rbdfc032  
    2828        @test -z "$(CFA_BINDIR)" || $(MKDIR_P) "$(CFA_BINDIR)"
    2929        @echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) cfa '$(CFA_BINDIR)/$(CFA_NAME)'"; \
    30         chmod u+w $(CFA_BINDIR);\
    3130        $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) cfa $(CFA_BINDIR)/$(CFA_NAME) || exit $$?
    3231
  • driver/cc1.cc

    reef8dfb rbdfc032  
    1010// Created On       : Fri Aug 26 14:23:51 2005
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Nov 17 14:27:08 2020
    13 // Update Count     : 414
     12// Last Modified On : Sun Oct 20 08:14:33 2019
     13// Update Count     : 385
    1414//
    1515
     
    2424#include <unistd.h>                                                                             // execvp, fork, unlink
    2525#include <sys/wait.h>                                                                   // wait
    26 #include <fcntl.h>                                                                              // creat
     26#include <fcntl.h>
    2727
    2828
     
    3838static string o_file;
    3939static string bprefix;
    40 static string lang;                                                                             // -x flag
    4140
    4241
     
    5958
    6059
    61 static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );               // "__CFA_FLAG__=" suffix
     60static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );               // "N__=" suffix
    6261
    6362static void checkEnv1( const char * args[], int & nargs ) { // stage 1
     
    7473                        if ( prefix( val, "-compiler=" ) ) {
    7574                                compiler_path = val.substr( 10 );
    76                         } else if ( prefix( val, "-x=" ) ) {
    77                                 lang = val.substr( 3 );
    7875                        } // if
    7976                } // if
     
    9794                        } else if ( val == "-CFA" ) {
    9895                                CFA_flag = true;
    99                         } else if ( val == "-save-temps" || val == "--save-temps" ) {
     96                        } else if ( val == "-save-temps" ) {
    10097                                save_temps = true;
    10198                        } else if ( prefix( val, "-o=" ) ) {            // output file for -CFA
     
    103100                        } else if ( prefix( val, "-B=" ) ) {            // location of cfa-cpp
    104101                                bprefix = val.substr( 3 );
    105                         } else if ( prefix( val, "-x=" ) ) {            // ignore
    106102                        } else {                                                                        // normal flag for cfa-cpp
    107103                                args[nargs++] = ( *new string( arg.substr( arg.find_first_of( "=" ) + 1 ) ) ).c_str();
     
    111107} // checkEnv2
    112108
    113 #define CFA_SUFFIX ".ifa"
    114 
    115 static char tmpname[] = P_tmpdir "/CFAXXXXXX" CFA_SUFFIX;
     109
     110static char tmpname[] = P_tmpdir "/CFAXXXXXX.ifa";
    116111static int tmpfilefd = -1;
    117112static bool startrm = false;
     
    171166                        if ( arg == "-quiet" ) {
    172167                        } else if ( arg == "-imultilib" || arg == "-imultiarch" ) {
    173                                 i += 1;                                                                 // and argument
     168                                i += 1;                                                                 // and the argument
    174169                        } else if ( prefix( arg, "-A" ) ) {
    175170                        } else if ( prefix( arg, "-D__GNU" ) ) {
     
    178173                                //********
    179174                        } else if ( arg == "-D" && prefix( argv[i + 1], "__GNU" ) ) {
    180                                 i += 1;                                                                 // and argument
     175                                i += 1;                                                                 // and the argument
    181176
    182177                                // strip flags controlling cpp step
     
    185180                                cpp_flag = true;
    186181                        } else if ( arg == "-D" && string( argv[i + 1] ) == "__CPP__" ) {
    187                                 i += 1;                                                                 // and argument
     182                                i += 1;                                                                 // and the argument
    188183                                cpp_flag = true;
    189184
     
    195190                                cpp_out = argv[i];
    196191                        } else {
    197                                 args[nargs++] = argv[i];                                // pass flag along
     192                                args[nargs++] = argv[i];                                // pass the flag along
    198193                                // CPP flags with an argument
    199194                                if ( arg == "-D" || arg == "-U" || arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" ||
     
    201196                                         arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" || arg == "-isysroot" ) {
    202197                                        i += 1;
    203                                         args[nargs++] = argv[i];                        // pass argument along
     198                                        args[nargs++] = argv[i];                        // pass the argument along
    204199                                        #ifdef __DEBUG_H__
    205200                                        cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
    206201                                        #endif // __DEBUG_H__
    207202                                } else if ( arg == "-MD" || arg == "-MMD" ) {
    208                                         // gcc frontend generates the dependency file-name after the -MD/-MMD flag, but it is necessary to
    209                                         // prefix that file name with -MF.
    210203                                        args[nargs++] = "-MF";                          // insert before file
    211204                                        i += 1;
    212                                         args[nargs++] = argv[i];                        // pass argument along
     205                                        args[nargs++] = argv[i];                        // pass the argument along
    213206                                        #ifdef __DEBUG_H__
    214207                                        cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
     
    254247
    255248                args[0] = compiler_path.c_str();
    256                 if ( lang.size() == 0 ) {
    257                         suffix( cpp_in, args, nargs );                          // check suffix
    258                 } else {
    259                         args[nargs++] = "-x";
    260                         args[nargs++] = ( *new string( lang.c_str() ) ).c_str();
    261                 } // if
     249                suffix( cpp_in, args, nargs );                                  // check suffix
    262250                args[nargs++] = cpp_in;
    263251                if ( o_flag ) {                                                                 // location for output
     
    282270        // Run the C preprocessor and save the output in the given file.
    283271
    284         if ( fork() == 0 ) {                                                            // child process ?
     272        if ( fork() == 0 ) {                                                             // child process ?
    285273                // -o xxx.ii cannot be used to write the output file from cpp because no output file is created if cpp detects
    286274                // an error (e.g., cannot find include file). Whereas, output is always generated, even when there is an error,
     
    292280
    293281                args[0] = compiler_path.c_str();
    294                 if ( lang.size() == 0 ) {
    295                         suffix( cpp_in, args, nargs );                          // check suffix
    296                 } else {
    297                         args[nargs++] = "-x";
    298                         args[nargs++] = ( *new string( lang.c_str() ) ).c_str();
    299                 } // if
     282                suffix( cpp_in, args, nargs );                                  // check suffix
    300283                args[nargs++] = cpp_in;                                                 // input to cpp
    301284                args[nargs] = nullptr;                                                  // terminate argument list
     
    322305
    323306        if ( WIFSIGNALED(code) ) {                                                      // child failed ?
    324                 rmtmpfile();                                                                    // remove tmpname
    325307                cerr << "CC1 Translator error: stage 1, child failed " << WTERMSIG(code) << endl;
    326308                exit( EXIT_FAILURE );
    327309        } // if
    328310
    329         exit( WEXITSTATUS( code ) );                                            // bad cpp result stops top-level gcc
     311        exit( WEXITSTATUS(code) );                                                      // bad cpp result stops top-level gcc
    330312} // Stage1
    331313
     
    375357                        } else if ( arg == "-fno-diagnostics-color" ) {
    376358                                color_arg = Color_Auto;
    377                         } // if
     359                        }
    378360
    379361                        if ( arg == "-quiet" || arg == "-version" || arg == "-fpreprocessed" ||
    380                                  // Currently CFA does not suppose precompiled .h files.
    381                                  prefix( arg, "--output-pch" ) ) {
     362                                // Currently CFA does not suppose precompiled .h files.
     363                                prefix( arg, "--output-pch" ) ) {
    382364
    383365                                // strip inappropriate flags with an argument
     
    392374
    393375                        } else {
    394                                 args[nargs++] = argv[i];                                // pass flag along
     376                                args[nargs++] = argv[i];                                // pass the flag along
    395377                                if ( arg == "-o" ) {
    396378                                        i += 1;
    397379                                        cpp_out = argv[i];
    398                                         args[nargs++] = argv[i];                        // pass argument along
     380                                        args[nargs++] = argv[i];                        // pass the argument along
    399381                                        #ifdef __DEBUG_H__
    400382                                        cerr << "arg:\"" << argv[i] << "\"" << endl;
     
    443425                        } // if
    444426
    445                         cfa_cpp_out = cfa_cpp_out.substr( 0, dot ) + CFA_SUFFIX;
     427                        cfa_cpp_out = cfa_cpp_out.substr( 0, dot ) + ".ifa";
    446428                        if ( creat( cfa_cpp_out.c_str(), 0666 ) == -1 ) {
    447429                                perror( "CC1 Translator error: stage 2, creat" );
     
    464446        // output.  Otherwise, run the cfa-cpp preprocessor on the temporary file and save the result into the output file.
    465447
    466         if ( fork() == 0 ) {                                                            // child runs CFA preprocessor
     448        if ( fork() == 0 ) {                                                            // child runs CFA
    467449                cargs[0] = ( *new string( bprefix + "cfa-cpp" ) ).c_str();
    468450                cargs[ncargs++] = cpp_in;
     
    522504        #endif // __DEBUG_H__
    523505
    524         if ( fork() == 0 ) {                                                            // child runs gcc
     506        if ( fork() == 0 ) {                                                            // child runs CFA
    525507                args[0] = compiler_path.c_str();
    526508                args[nargs++] = "-S";                                                   // only compile and put assembler output in specified file
  • driver/cfa.cc

    reef8dfb rbdfc032  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Nov 17 14:27:28 2020
    13 // Update Count     : 440
     12// Last Modified On : Fri Jan 31 16:48:03 2020
     13// Update Count     : 421
    1414//
    1515
    1616#include <iostream>
    17 #include <cstdio>                                                                               // perror
    18 #include <cstdlib>                                                                              // putenv, exit
    19 #include <climits>                                                                              // PATH_MAX
    20 #include <string>                                                                               // STL version
    21 #include <algorithm>                                                                    // find
    22 
    23 #include <unistd.h>                                                                             // execvp
     17#include <cstdio>      // perror
     18#include <cstdlib>     // putenv, exit
     19#include <climits>     // PATH_MAX
     20#include <unistd.h>    // execvp
     21#include <string>      // STL version
     22#include <string.h>    // strcmp
     23#include <algorithm>   // find
     24
    2425#include <sys/types.h>
    2526#include <sys/stat.h>
     
    3334using std::to_string;
    3435
    35 //#define __DEBUG_H__
    36 
    37 #define xstr(s) str(s)
    38 #define str(s) #s
    39 
    40 static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );               // "__CFA_FLAG__=" suffix
    41 
    42 static void Putenv( char * argv[], string arg ) {
     36// #define __DEBUG_H__
     37
     38// "N__=" suffix
     39static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );
     40
     41void Putenv( char * argv[], string arg ) {
    4342        // environment variables must have unique names
    4443        static int flags = 0;
     
    5049} // Putenv
    5150
    52 static bool prefix( const string & arg, const string & pre ) { // check if string has prefix
     51// check if string has prefix
     52bool prefix( const string & arg, const string & pre ) {
    5353        return arg.substr( 0, pre.size() ) == pre;
    5454} // prefix
    5555
    56 static inline bool ends_with(const string & str, const string & sfix) {
     56inline bool ends_with(const string & str, const string & sfix) {
    5757        if (sfix.size() > str.size()) return false;
    5858        return std::equal(str.rbegin(), str.rbegin() + sfix.size(), sfix.rbegin(), sfix.rend());
     
    6060
    6161// check if string has suffix
    62 static bool suffix( const string & arg ) {
     62bool suffix( const string & arg ) {
    6363        enum { NumSuffixes = 3 };
    6464        static const string suffixes[NumSuffixes] = { "cfa", "hfa", "ifa" };
     
    7070} // suffix
    7171
     72
    7273static inline bool dirExists( const string & path ) {   // check if directory exists
    7374    struct stat info;
     
    7879static inline string dir(const string & path) {
    7980        return path.substr(0, path.find_last_of('/'));
    80 } // dir
     81}
    8182
    8283// Different path modes
     
    117118}
    118119
     120
     121#define xstr(s) str(s)
     122#define str(s) #s
    119123
    120124int main( int argc, char * argv[] ) {
     
    154158        PathMode path = FromProc();
    155159
    156         const char * args[argc + 100];                                          // cfa command line values, plus some space for additional flags
     160        const char *args[argc + 100];                                           // cfa command line values, plus some space for additional flags
    157161        int sargs = 1;                                                                          // starting location for arguments in args list
    158162        int nargs = sargs;                                                                      // number of arguments in args list; 0 => command name
    159163
    160         const char * libs[argc + 20];                                           // non-user libraries must come separately, plus some added libraries and flags
     164        const char *libs[argc + 20];                                            // non-user libraries must come separately, plus some added libraries and flags
    161165        int nlibs = 0;
    162166
     
    176180
    177181                        if ( arg == "-Xlinker" || arg == "-o" ) {
    178                                 args[nargs++] = argv[i];                                // pass flag along
     182                                args[nargs++] = argv[i];                                // pass argument along
    179183                                i += 1;
    180184                                if ( i == argc ) continue;                              // next argument available ?
    181185                                args[nargs++] = argv[i];                                // pass argument along
    182186                                if ( arg == "-o" ) o_file = i;                  // remember file
     187                        } else if ( arg == "-XCFA" ) {                          // CFA pass through
     188                                i += 1;
     189                                if ( i == argc ) continue;                              // next argument available ?
     190                                Putenv( argv, argv[i] );
    183191
    184192                                // CFA specific arguments
    185193
    186                         } else if ( strncmp(arg.c_str(), "-XCFA", 5) == 0 ) { // CFA pass through
    187                                 if ( arg.size() == 5 ) {
    188                                         i += 1;
    189                                         if ( i == argc ) continue;                      // next argument available ?
    190                                         Putenv( argv, argv[i] );
    191                                 } else if ( arg[5] == ',' ) {                   // CFA specific arguments
    192                                         Putenv( argv, argv[i] + 6 );
    193                                 } else {                                                                // CFA specific arguments
    194                                         args[nargs++] = argv[i];
    195                                 } // if
    196194                        } else if ( arg == "-CFA" ) {
    197195                                CFA_flag = true;                                                // strip the -CFA flag
     
    202200                        } else if ( arg == "-nodebug" ) {
    203201                                debug = false;                                                  // strip the nodebug flag
     202                        } else if ( arg == "-nolib" ) {
     203                                nolib = true;                                                   // strip the nodebug flag
    204204                        } else if ( arg == "-quiet" ) {
    205205                                quiet = true;                                                   // strip the quiet flag
    206206                        } else if ( arg == "-noquiet" ) {
    207207                                quiet = false;                                                  // strip the noquiet flag
    208                         } else if ( arg == "-no-include-stdhdr" ) {
    209                                 noincstd_flag = true;                                   // strip the no-include-stdhdr flag
    210                         } else if ( arg == "-nolib" ) {
    211                                 nolib = true;                                                   // strip the nolib flag
    212208                        } else if ( arg == "-help" ) {
    213209                                help = true;                                                    // strip the help flag
    214210                        } else if ( arg == "-nohelp" ) {
    215211                                help = false;                                                   // strip the nohelp flag
     212                        } else if ( arg == "-no-include-stdhdr" ) {
     213                                noincstd_flag = true;                                   // strip the no-include-stdhdr flag
    216214                        } else if ( arg == "-cfalib") {
    217215                                compiling_libs = true;
     
    227225                        } else if ( arg == "-v" ) {
    228226                                verbose = true;                                                 // verbosity required
    229                                 args[nargs++] = argv[i];                                // pass flag along
     227                                args[nargs++] = argv[i];                                // pass argument along
    230228                        } else if ( arg == "-g" ) {
    231229                                debugging = true;                                               // symbolic debugging required
    232                                 args[nargs++] = argv[i];                                // pass flag along
    233                         } else if ( arg == "-save-temps" || arg == "--save-temps" ) {
    234                                 args[nargs++] = argv[i];                                // pass flag along
     230                                args[nargs++] = argv[i];                                // pass argument along
     231                        } else if ( arg == "-save-temps" ) {
     232                                args[nargs++] = argv[i];                                // pass argument along
    235233                                Putenv( argv, arg );                                    // save cfa-cpp output
    236234                        } else if ( prefix( arg, "-x" ) ) {                     // file suffix ?
    237235                                string lang;
    238                                 args[nargs++] = argv[i];                                // pass flag along
     236                                args[nargs++] = argv[i];                                // pass argument along
    239237                                if ( arg.length() == 2 ) {                              // separate argument ?
    240238                                        i += 1;
     
    245243                                        lang = arg.substr( 2 );
    246244                                } // if
    247                                 if ( x_flag ) {
    248                                         cerr << argv[0] << " warning, only one -x flag per compile, ignoring subsequent flag." << endl;
    249                                 } else {
    250                                         x_flag = true;
    251                                         Putenv( argv, string( "-x=" ) + lang );
    252                                 } // if
     245                                x_flag = lang != "none";
    253246                        } else if ( prefix( arg, "-std=" ) || prefix( arg, "--std=" ) ) {
    254247                                std_flag = true;                                                // -std=XX provided
    255                                 args[nargs++] = argv[i];                                // pass flag along
     248                                args[nargs++] = argv[i];                                // pass argument along
    256249                        } else if ( arg == "-w" ) {
    257                                 args[nargs++] = argv[i];                                // pass flag along
     250                                args[nargs++] = argv[i];                                // pass argument along
    258251                                Putenv( argv, arg );
    259252                        } else if ( prefix( arg, "-W" ) ) {                     // check before next tests
    260253                                if ( arg == "-Werror" || arg == "-Wall" ) {
    261                                         args[nargs++] = argv[i];                        // pass flag along
     254                                        args[nargs++] = argv[i];                        // pass argument along
    262255                                        Putenv( argv, argv[i] );
    263256                                } else {
     
    273266                                bprefix = arg.substr(2);                                // strip the -B flag
    274267                        } else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) {
    275                                 args[nargs++] = argv[i];                                // pass flag along
     268                                args[nargs++] = argv[i];                                // pass argument along
    276269                                if ( arg == "-E" || arg == "-M" || arg == "-MM" ) {
    277270                                        cpp_flag = true;                                        // cpp only
    278271                                } // if
    279272                                link = false;                           // no linkage required
    280                         } else if ( arg == "-D" || arg == "-U" || arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" ||
    281                                                 arg == "-include" || arg == "-imacros" || arg == "-idirafter" || arg == "-iprefix" ||
    282                                                 arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" || arg == "-isysroot" ) {
    283                                 args[nargs++] = argv[i];                                // pass flag along
    284                                 i += 1;
    285                                 args[nargs++] = argv[i];                                // pass argument along
    286273                        } else if ( arg[1] == 'l' ) {
    287274                                // if the user specifies a library, load it after user code
     
    315302
    316303        #ifdef __x86_64__
    317         args[nargs++] = "-mcx16";                                                       // allow double-wide CAS
     304        args[nargs++] = "-mcx16";                                                       // allow double-wide CAA
    318305        #endif // __x86_64__
    319306
     
    335322        string libbase;
    336323        switch(path) {
    337           case Installed:
     324        case Installed:
    338325                args[nargs++] = "-I" CFA_INCDIR;
    339326                // do not use during build
     
    345332                libbase = CFA_LIBDIR;
    346333                break;
    347           case BuildTree:
    348           case Distributed:
     334        case BuildTree:
     335        case Distributed:
    349336                args[nargs++] = "-I" TOP_SRCDIR "libcfa/src";
    350337                // do not use during build
     
    380367        string libdir = libbase + arch + "-" + config;
    381368
    382         if ( path != Distributed ) {
     369        if (path != Distributed) {
    383370                if ( ! nolib && ! dirExists( libdir ) ) {
    384371                        cerr << argv[0] << " internal error, configuration " << config << " not installed." << endl;
     
    398385        } // if
    399386
    400         string preludedir;
    401387        switch(path) {
    402           case Installed   : preludedir = libdir; break;
    403           case BuildTree   : preludedir = libdir + "/prelude"; break;
    404           case Distributed : preludedir = dir(argv[0]); break;
    405         } // switch
    406 
    407         Putenv( argv, "--prelude-dir=" + preludedir );
    408         args[nargs++] = "-include";
    409         args[nargs++] = (*new string(preludedir + "/defines.hfa")).c_str();
     388        case Installed   : Putenv( argv, "--prelude-dir=" + libdir ); break;
     389        case BuildTree   : Putenv( argv, "--prelude-dir=" + libdir + "/prelude" ); break;
     390        case Distributed : Putenv( argv, "--prelude-dir=" + dir(argv[0]) ); break;
     391        }
    410392
    411393        for ( int i = 0; i < nlibs; i += 1 ) {                          // copy non-user libraries after all user libraries
     
    429411                args[nargs++] = "-lcfathread";
    430412                args[nargs++] = "-Wl,--pop-state";
    431                 args[nargs++] = "-Wl,--push-state,--no-as-needed";
    432413                args[nargs++] = "-lcfa";
    433                 args[nargs++] = "-Wl,--pop-state";
    434414                args[nargs++] = "-pthread";
    435                 #if defined(  __x86_64__ ) || defined( __ARM_ARCH )
    436                 args[nargs++] = "-latomic";                                             // allow double-wide CAS
    437                 #endif // __x86_64__
    438415                args[nargs++] = "-ldl";
     416                args[nargs++] = "-lrt";
    439417                args[nargs++] = "-lm";
    440418        } // if
     
    474452        if ( bprefix.length() == 0 ) {
    475453                switch(path) {
    476                   case Installed   : bprefix = installlibdir; break;
    477                   case BuildTree   : bprefix = srcdriverdir ; break;
    478                   case Distributed : bprefix = dir(argv[0]) ; break;
    479                 } // switch
    480         } // if
    481         if ( bprefix[bprefix.length() - 1] != '/' ) bprefix += '/';
    482         Putenv( argv, string("-B=") + bprefix );
     454                case Installed   : bprefix = installlibdir; break;
     455                case BuildTree   : bprefix = srcdriverdir ; break;
     456                case Distributed : bprefix = dir(argv[0]) ; break;
     457                }
     458                if ( bprefix[bprefix.length() - 1] != '/' ) bprefix += '/';
     459                Putenv( argv, string("-B=") + bprefix );
     460        } // if
    483461
    484462        args[nargs++] = "-Xlinker";                                                     // used by backtrace
     
    502480                args[nargs++] = "-Wno-cast-function-type";
    503481                #endif // HAVE_CAST_FUNCTION_TYPE
    504                 if ( ! std_flag && ! x_flag ) {
    505                         args[nargs++] = "-std=gnu11";                           // default c11, if none specified
     482                if ( ! std_flag ) {                                                             // default c11, if none specified
     483                        args[nargs++] = "-std=gnu11";
    506484                } // if
    507485                args[nargs++] = "-fgnu89-inline";
     
    553531        // execute the command and return the result
    554532
    555         execvp( args[0], (char * const *)args );                        // should not return
     533        execvp( args[0], (char *const *)args );                         // should not return
    556534        perror( "CFA Translator error: execvp" );
    557535        exit( EXIT_FAILURE );
  • libcfa/configure.ac

    reef8dfb rbdfc032  
    33
    44AC_PREREQ([2.68])
    5 AC_INIT([cfa-cc],[1.0.0],[cforall@plg.uwaterloo.ca])
     5AC_INIT([cfa-cc],[1.0.0.0],[cforall@plg.uwaterloo.ca])
    66AC_CONFIG_AUX_DIR([automake])
    77AC_CONFIG_MACRO_DIRS([automake])
    88AM_SILENT_RULES([yes])
    99
    10 m4_include([../tools/build/cfa.m4])
     10m4_include([../automake/cfa.m4])
    1111
    1212AM_INIT_AUTOMAKE([subdir-objects])
     
    3030        [  --enable-distcc     whether or not to enable distributed compilation],
    3131        enable_distcc=$enableval, enable_distcc=no)
    32 
    33 AC_ARG_WITH(bwlimit,
    34         [  --with-bwlimit=RATE     RATE the maximum rate at which rsync will be limited when using distributed builds],
    35         DIST_BWLIMIT=$withval, DIST_BWLIMIT=0)
    3632
    3733echo -n "checking for distributated build... "
     
    5955AC_SUBST(CFADIR_HASH)
    6056AC_SUBST(CFA_VERSION)
    61 AC_SUBST(DIST_BWLIMIT)
    6257
    6358#==============================================================================
     
    105100AM_CONDITIONAL([BUILDLIB], [test "x${CONFIG_BUILDLIB}" = "xyes"])
    106101
    107 AM_T='$(T)'
    108 AC_SUBST(AM_T)
    109 
    110102#==============================================================================
    111103#Trasforming cc1 will break compilation
     
    117109
    118110# Checks for programs.
    119 LT_INIT([disable-static])
     111LT_INIT
    120112
    121113AC_PROG_CXX
     
    126118AC_PROG_MAKE_SET
    127119
    128 
    129 
    130 #io_uring 5.4 and earlier uses defines
    131 #io_uring 5.5 uses enum values
    132 #io_uring 5.6 and later uses probes
    133 
    134 AH_TEMPLATE([CFA_HAVE_LINUX_IO_URING_H],[Defined if io_uring support is present when compiling libcfathread.])
    135 AH_TEMPLATE([CFA_HAVE_IORING_OP_NOP],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_NOP.])
    136 AH_TEMPLATE([CFA_HAVE_IORING_OP_READV],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_READV.])
    137 AH_TEMPLATE([CFA_HAVE_IORING_OP_WRITEV],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_WRITEV.])
    138 AH_TEMPLATE([CFA_HAVE_IORING_OP_FSYNC],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_FSYNC.])
    139 AH_TEMPLATE([CFA_HAVE_IORING_OP_READ_FIXED],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_READ_FIXED.])
    140 AH_TEMPLATE([CFA_HAVE_IORING_OP_WRITE_FIXED],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_WRITE_FIXED.])
    141 AH_TEMPLATE([CFA_HAVE_IORING_OP_POLL_ADD],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_POLL_ADD.])
    142 AH_TEMPLATE([CFA_HAVE_IORING_OP_POLL_REMOVE],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_POLL_REMOVE.])
    143 AH_TEMPLATE([CFA_HAVE_IORING_OP_SYNC_FILE_RANGE],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_SYNC_FILE_RANGE.])
    144 AH_TEMPLATE([CFA_HAVE_IORING_OP_SENDMSG],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_SENDMSG.])
    145 AH_TEMPLATE([CFA_HAVE_IORING_OP_RECVMSG],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_RECVMSG.])
    146 AH_TEMPLATE([CFA_HAVE_IORING_OP_TIMEOUT],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_TIMEOUT.])
    147 AH_TEMPLATE([CFA_HAVE_IORING_OP_TIMEOUT_REMOVE],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_TIMEOUT_REMOVE.])
    148 AH_TEMPLATE([CFA_HAVE_IORING_OP_ACCEPT],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_ACCEPT.])
    149 AH_TEMPLATE([CFA_HAVE_IORING_OP_ASYNC_CANCEL],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_ASYNC_CANCEL.])
    150 AH_TEMPLATE([CFA_HAVE_IORING_OP_LINK_TIMEOUT],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_LINK_TIMEOUT.])
    151 AH_TEMPLATE([CFA_HAVE_IORING_OP_CONNECT],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_CONNECT.])
    152 AH_TEMPLATE([CFA_HAVE_IORING_OP_FALLOCATE],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_FALLOCATE.])
    153 AH_TEMPLATE([CFA_HAVE_IORING_OP_OPENAT],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_OPENAT.])
    154 AH_TEMPLATE([CFA_HAVE_IORING_OP_CLOSE],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_CLOSE.])
    155 AH_TEMPLATE([CFA_HAVE_IORING_OP_FILES_UPDATE],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_FILES_UPDATE.])
    156 AH_TEMPLATE([CFA_HAVE_IORING_OP_STATX],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_STATX.])
    157 AH_TEMPLATE([CFA_HAVE_IORING_OP_READ],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_READ.])
    158 AH_TEMPLATE([CFA_HAVE_IORING_OP_WRITE],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_WRITE.])
    159 AH_TEMPLATE([CFA_HAVE_IORING_OP_FADVISE],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_FADVISE.])
    160 AH_TEMPLATE([CFA_HAVE_IORING_OP_MADVISE],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_MADVISE.])
    161 AH_TEMPLATE([CFA_HAVE_IORING_OP_SEND],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_SEND.])
    162 AH_TEMPLATE([CFA_HAVE_IORING_OP_RECV],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_RECV.])
    163 AH_TEMPLATE([CFA_HAVE_IORING_OP_OPENAT2],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_OPENAT2.])
    164 AH_TEMPLATE([CFA_HAVE_IORING_OP_EPOLL_CTL],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_EPOLL_CTL.])
    165 AH_TEMPLATE([CFA_HAVE_IORING_OP_SPLICE],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_SPLICE.])
    166 AH_TEMPLATE([CFA_HAVE_IORING_OP_PROVIDE_BUFFERS],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_PROVIDE_BUFFERS.])
    167 AH_TEMPLATE([CFA_HAVE_IORING_OP_REMOVE_BUFFER],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_REMOVE_BUFFER.])
    168 AH_TEMPLATE([CFA_HAVE_IORING_OP_TEE],[Defined if io_uring support is present when compiling libcfathread and supports the operation IORING_OP_TEE.])
    169 AH_TEMPLATE([CFA_HAVE_IOSQE_FIXED_FILE],[Defined if io_uring support is present when compiling libcfathread and supports the flag FIXED_FILE.])
    170 AH_TEMPLATE([CFA_HAVE_IOSQE_IO_DRAIN],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_DRAIN.])
    171 AH_TEMPLATE([CFA_HAVE_IOSQE_ASYNC],[Defined if io_uring support is present when compiling libcfathread and supports the flag ASYNC.])
    172 AH_TEMPLATE([CFA_HAVE_IOSQE_IO_LINK],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_LINK.])
    173 AH_TEMPLATE([CFA_HAVE_IOSQE_IO_HARDLINK],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_HARDLINK.])
    174 AH_TEMPLATE([CFA_HAVE_SPLICE_F_FD_IN_FIXED],[Defined if io_uring support is present when compiling libcfathread and supports the flag SPLICE_F_FD_IN_FIXED.])
    175 AH_TEMPLATE([CFA_HAVE_IORING_SETUP_ATTACH_WQ],[Defined if io_uring support is present when compiling libcfathread and supports the flag IORING_SETUP_ATTACH_WQ.])
    176 AH_TEMPLATE([CFA_HAVE_PREADV2],[Defined if preadv2 support is present when compiling libcfathread.])
    177 AH_TEMPLATE([CFA_HAVE_PWRITEV2],[Defined if pwritev2 support is present when compiling libcfathread.])
    178 AH_TEMPLATE([CFA_HAVE_PWRITEV2],[Defined if pwritev2 support is present when compiling libcfathread.])
    179 AH_TEMPLATE([CFA_HAVE_STATX],[Defined if statx support is present when compiling libcfathread.])
    180 AH_TEMPLATE([CFA_HAVE_OPENAT2],[Defined if openat2 support is present when compiling libcfathread.])
    181 AH_TEMPLATE([__CFA_NO_STATISTICS__],[Defined if libcfathread was compiled without support for statistics.])
    182 
    183 define(ioring_ops, [IORING_OP_NOP,IORING_OP_READV,IORING_OP_WRITEV,IORING_OP_FSYNC,IORING_OP_READ_FIXED,IORING_OP_WRITE_FIXED,IORING_OP_POLL_ADD,IORING_OP_POLL_REMOVE,IORING_OP_SYNC_FILE_RANGE,IORING_OP_SENDMSG,IORING_OP_RECVMSG,IORING_OP_TIMEOUT,IORING_OP_TIMEOUT_REMOVE,IORING_OP_ACCEPT,IORING_OP_ASYNC_CANCEL,IORING_OP_LINK_TIMEOUT,IORING_OP_CONNECT,IORING_OP_FALLOCATE,IORING_OP_OPENAT,IORING_OP_CLOSE,IORING_OP_FILES_UPDATE,IORING_OP_STATX,IORING_OP_READ,IORING_OP_WRITE,IORING_OP_FADVISE,IORING_OP_MADVISE,IORING_OP_SEND,IORING_OP_RECV,IORING_OP_OPENAT2,IORING_OP_EPOLL_CTL,IORING_OP_SPLICE,IORING_OP_PROVIDE_BUFFERS,IORING_OP_REMOVE_BUFFER,IORING_OP_TEE])
    184 define(ioring_flags, [IOSQE_FIXED_FILE,IOSQE_IO_DRAIN,IOSQE_ASYNC,IOSQE_IO_LINK,IOSQE_IO_HARDLINK,SPLICE_F_FD_IN_FIXED,IORING_SETUP_ATTACH_WQ])
    185 
    186 define(ioring_from_decls, [
    187         m4_foreach([op], [ioring_ops], [
    188                 AC_CHECK_DECL(op, [AC_DEFINE([CFA_HAVE_]op)], [], [[#include <linux/io_uring.h>]])
    189         ])
    190 ])
    191 
    192 AC_CHECK_HEADERS([linux/io_uring.h], [
    193         AC_DEFINE(CFA_HAVE_LINUX_IO_URING_H)
    194         AC_CHECK_HEADER([liburing.h], [
    195                 AC_CHECK_LIB([uring], [io_uring_get_probe], [
    196                         m4_foreach([op], [ioring_ops], [
    197                                 AC_CHECK_DECL(op, [
    198                                         AC_RUN_IFELSE([
    199                                                 AC_LANG_PROGRAM(
    200                                                         [[#include <liburing.h>]],
    201                                                         [[int main() {]]
    202                                                         [[      struct io_uring_probe *probe = io_uring_get_probe();]]
    203                                                         [[      if(io_uring_opcode_supported(probe, ]]op[[))]]
    204                                                         [[              return 0;]]
    205                                                         [[      else]]
    206                                                         [[              return 1;]]
    207                                                         [[}]]
    208                                                 )
    209                                         ],[
    210                                                 AC_DEFINE([CFA_HAVE_]op)
    211                                         ],[
    212                                                 AC_MSG_FAILURE([Check support for] op [ with liburing failed])
    213                                         ])
    214                                 ], [], [[#include <linux/io_uring.h>]])
    215                         ])
    216                 ], [
    217                         ioring_from_decls
    218                 ])
    219         ], [
    220                 ioring_from_decls
    221         ])
    222 
    223         # check support for various io_uring flags
    224         m4_foreach([op], [ioring_flags], [
    225                 AC_CHECK_DECL(op, [AC_DEFINE([CFA_HAVE_]op)], [], [[#include <linux/io_uring.h>]])
    226         ])
    227 ])
    228 AC_CHECK_FUNC([preadv2], [AC_DEFINE([CFA_HAVE_PREADV2])])
    229 AC_CHECK_FUNC([pwritev2], [AC_DEFINE([CFA_HAVE_PWRITEV2])])
    230 
    231120AC_CONFIG_FILES([
    232121        Makefile
     
    234123        prelude/Makefile
    235124        ])
    236 AC_CONFIG_FILES([src/concurrency/io/call.cfa], [python3 ${srcdir}/src/concurrency/io/call.cfa.in > src/concurrency/io/call.cfa])
    237 
    238 AC_CONFIG_HEADERS(prelude/defines.hfa)
    239125
    240126AC_OUTPUT()
  • libcfa/prelude/Makefile.am

    reef8dfb rbdfc032  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon Feb  3 21:27:18 2020
    14 ## Update Count     : 208
     13## Last Modified On : Wed Dec 14 15:00:35 2016
     14## Update Count     : 205
    1515###############################################################################
    1616
     
    2121# put into lib for now
    2222cfalibdir = ${CFA_LIBDIR}
    23 cfalib_DATA = gcc-builtins.cf builtins.cf extras.cf prelude.cfa bootloader.c defines.hfa
    24 
    25 EXTRA_DIST = bootloader.cf builtins.c builtins.def extras.c extras.regx extras.regx2 prelude-gen.cc prototypes.awk prototypes.c prototypes.sed sync-builtins.cf
     23cfalib_DATA = gcc-builtins.cf builtins.cf extras.cf prelude.cfa bootloader.c
    2624
    2725CC = @LOCAL_CFACC@
     
    3836extras.cf : ${srcdir}/extras.regx ${srcdir}/extras.c
    3937        ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -f ${srcdir}/extras.regx > extras.cf
    40         ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -zo -f ${srcdir}/extras.regx2 | tr '\0' '\n' >> extras.cf
    4138
    4239# create forward declarations for gcc builtins
     
    7067
    7168MOSTLYCLEANFILES = bootloader.c builtins.cf extras.cf gcc-builtins.c gcc-builtins.cf prelude.cfa
    72 DISTCLEANFILES = $(DEPDIR)/builtins.Po
    7369MAINTAINERCLEANFILES = ${addprefix ${libdir}/,${cfalib_DATA}} ${addprefix ${libdir}/,${lib_LIBRARIES}}
    7470
    7571if ENABLE_DISTCC
    7672distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ gcc-builtins.cf builtins.cf extras.cf prelude.cfa bootloader.c $(srcdir)/../../tools/build/push2dist.sh
    77         ${AM_V_GEN}$(srcdir)/../../tools/build/push2dist.sh @CFADIR_HASH@ @DIST_BWLIMIT@
     73        ${AM_V_GEN}$(srcdir)/../../tools/build/push2dist.sh @CFADIR_HASH@
    7874        @echo "Dummy file to track distribution to remote hosts" > ${@}
    7975
  • libcfa/prelude/bootloader.cf

    reef8dfb rbdfc032  
    11extern "C" { static inline int invoke_main(int argc, char* argv[], char* envp[]); }
    2 int cfa_args_argc;
    3 char ** cfa_args_argv;
    4 char ** cfa_args_envp;
    52
    63int main(int argc, char* argv[], char* envp[]) {
    7         cfa_args_argc = argc;
    8         cfa_args_argv = argv;
    9         cfa_args_envp = envp;
    104        return invoke_main(argc, argv, envp);
    115}
  • libcfa/prelude/builtins.c

    reef8dfb rbdfc032  
    99// Author           : Peter A. Buhr
    1010// Created On       : Fri Jul 21 16:21:03 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct 27 14:42:00 2020
    13 // Update Count     : 111
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Nov 21 16:31:39 2019
     13// Update Count     : 101
    1414//
    15 
    16 #define __cforall_builtins__
    1715
    1816// type that wraps a pointer and a destructor-like function - used in generating implicit destructor calls for struct members in user-defined functions
     
    5149void abort( const char fmt[], ... ) __attribute__ (( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
    5250
    53 forall(dtype T)
    54 static inline T & identity(T & i) {
    55         return i;
    56 }
    57 
    58 // generator support
    59 struct $generator {
    60         inline int;
    61 };
    62 
    63 static inline void  ?{}($generator & this) { ((int&)this) = 0; }
    64 static inline void ^?{}($generator &) {}
    65 
    66 trait is_generator(dtype T) {
    67       void main(T & this);
    68       $generator * get_generator(T & this);
    69 };
    70 
    71 forall(dtype T | is_generator(T))
    72 static inline T & resume(T & gen) {
    73         main(gen);
    74         return gen;
    75 }
    76 
    7751// implicit increment, decrement if += defined, and implicit not if != defined
    7852
     
    9670// universal typed pointer constant
    9771static inline forall( dtype DT ) DT * intptr( uintptr_t addr ) { return (DT *)addr; }
    98 static inline forall( ftype FT ) FT * intptr( uintptr_t addr ) { return (FT *)addr; }
    99 
    100 #if defined(__SIZEOF_INT128__)
    101 // constructor for 128-bit numbers (all constants are unsigned as +/- are operators)
    102 static inline void ?{}( unsigned int128 & this, unsigned long int h, unsigned long int l ) {
    103         this = (unsigned int128)h << 64 | (unsigned int128)l;
    104 } // ?{}
    105 #endif // __SIZEOF_INT128__
    10672
    10773// exponentiation operator implementation
  • libcfa/prelude/extras.regx

    reef8dfb rbdfc032  
    2424typedef.* char32_t;
    2525typedef.* wchar_t;
     26extern.*\*malloc\(.*\).*
     27extern.* free\(.*\).*
     28extern.* exit\(.*\).*
     29extern.* atexit\(.*\).*
     30extern.* abort\(.*\).*
     31extern.* printf\(.*\).*
  • libcfa/prelude/prototypes.awk

    reef8dfb rbdfc032  
    1010# Created On       : Sat May 16 07:57:37 2015
    1111# Last Modified By : Peter A. Buhr
    12 # Last Modified On : Sat Feb  8 09:46:58 2020
    13 # Update Count     : 36
     12# Last Modified On : Thu Jun  6 20:46:28 2019
     13# Update Count     : 34
    1414#
    1515
     
    1717
    1818BEGIN {
    19         FS = "[( )]"
     19  FS = "[( )]"
    2020        # order so string search is longest string
    2121        i=-1
     
    8484
    8585/BT_FN/ {
    86         for (i = 1; i <= NF; i += 1 ) {
    87                 if ( match($i, "BT_FN") != 0 ) {
    88                         prototypes[$i] = $i
    89                 }
     86        for (i = 1; i <= NF; i++) {
     87          if( match($i, "BT_FN") != 0 ) {
     88                prototypes[$i] = $i
     89          }
    9090        }
    91 }
     91  }
    9292
    9393END {
     
    103103
    104104        for ( prototype in prototypes ) {
    105                 # printf( "//\"%s\"\n", prototype )
    106                 if ( index( "BT_LAST", prototype ) == 1 ) {
    107                         continue
     105          # printf( "//\"%s\"\n", prototype )
     106          if ( index( "BT_LAST", prototype ) == 1 ) {
     107                continue
     108          } # if
     109
     110          printf( "#define %s(NAME) FUNC_SIMPLE(", prototype )
     111
     112          if ( sub( "BT_FN_", "", prototype ) == 0 ) {
     113                printf( "\n********** BAD MACRO NAME \"%s\" **********\n", prototype )
     114                exit 0
     115          } # if
     116
     117          # generate function return type as macro
     118          for ( t = 0; t < N; t += 1 ) {                                        # find longest match
     119                type = types[t];
     120                if ( index( prototype, type ) == 1 ) {          # found match
     121                  printf( "BT_%s, NAME", type )
     122                  sub( type, "", prototype )
     123                  break;
    108124                } # if
     125          } # for
    109126
    110                 printf( "#define %s(NAME) FUNC_SIMPLE(", prototype )
    111 
    112                 if ( sub( "BT_FN_", "", prototype ) == 0 ) {
    113                         printf( "\n********** BAD MACRO NAME \"%s\" **********\n", prototype )
     127          # generate function parameter types as macro
     128          if ( index( prototype, "VAR" ) != 2 ) {                       # C-style empty parameters ?
     129                for ( p = 0; length( prototype ) > 0; p += 1 ) { # until all parameters types are removed
     130                  sub( "_", "", prototype)                              # remove "_"
     131                  printf( ", ", type )
     132                  temp = prototype
     133                  for ( t = 0; t < N; t += 1 ) {                        # find longest match
     134                        type = types[t];
     135                        if ( index( prototype, type ) == 1 ) { # found match
     136                          printf( "BT_%s", type )
     137                          sub( type, "", prototype )
     138                          break;
     139                        } # if
     140                  } # for
     141                  if ( temp == prototype ) {                            # no match found for parameter in macro table
     142                        printf( "\n********** MISSING TYPE \"%s\" **********\n", prototype )
    114143                        exit 0
    115                 } # if
    116 
    117                 # generate function return type as macro
    118                 for ( t = 0; t < N; t += 1 ) {                                  # find longest match
    119                         type = types[t];
    120                         if ( index( prototype, type ) == 1 ) {          # found match
    121                                 printf( "BT_%s, NAME", type )
    122                                 sub( type, "", prototype )
    123                                 break;
    124                         } # if
     144                  } # if
    125145                } # for
    126 
    127                 # generate function parameter types as macro
    128                 if ( index( prototype, "VAR" ) != 2 ) {                 # C-style empty parameters ?
    129                         for ( p = 0; length( prototype ) > 0; p += 1 ) { # until all parameters types are removed
    130                                 sub( "_", "", prototype)                                # remove "_"
    131                                 printf( ", ", type )
    132                                 temp = prototype
    133                                 for ( t = 0; t < N; t += 1 ) {                  # find longest match
    134                                         type = types[t];
    135                                         if ( index( prototype, type ) == 1 ) { # found match
    136                                                 printf( "BT_%s", type )
    137                                                 sub( type, "", prototype )
    138                                                 break;
    139                                         } # if
    140                                 } # for
    141                                 if ( temp == prototype ) {                              # no match found for parameter in macro table
    142                                         printf( "\n********** MISSING TYPE \"%s\" **********\n", prototype )
    143                                         exit 0
    144                                 } # if
    145                         } # for
    146                 } # if
    147                 printf( ")\n" )
     146          } # if
     147          printf( ")\n" )
    148148        } # for
    149149
  • libcfa/src/Makefile.am

    reef8dfb rbdfc032  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Wed Dec  9 22:46:14 2020
    14 ## Update Count     : 250
     13## Last Modified On : Mon Jul 15 22:43:27 2019
     14## Update Count     : 241
    1515###############################################################################
    1616
     
    1919ACLOCAL_AMFLAGS  = -I automake
    2020
    21 include $(top_srcdir)/../tools/build/cfa.make
     21include $(srcdir)/../../src/cfa.make
    2222
    2323libdir = ${CFA_LIBDIR}
     
    3131# AM_CFAFLAGS for only cfa source
    3232# use -no-include-stdhdr to prevent rebuild cycles
    33 # The built sources must not depend on the installed inst_headers_src
    34 AM_CFAFLAGS = -quiet -cfalib -I$(srcdir)/stdhdr -I$(srcdir)/concurrency $(if $(findstring ${gdbwaittarget}, ${@}), -XCFA --gdb) @CONFIG_CFAFLAGS@
    35 AM_CFLAGS = -g -Wall -Wno-unused-function -fPIC -fexceptions -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@
     33# The built sources must not depend on the installed headers
     34AM_CFAFLAGS = -quiet -cfalib -I$(srcdir)/stdhdr $(if $(findstring ${gdbwaittarget}, ${@}), -XCFA --gdb) @CONFIG_CFAFLAGS@
     35AM_CFLAGS = -g -Wall -Wno-unused-function -fPIC -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@
    3636AM_CCASFLAGS = -g -Wall -Wno-unused-function @ARCH_FLAGS@ @CONFIG_CFLAGS@
    3737CFACC = @CFACC@
     
    3939#----------------------------------------------------------------------------------------------------------------
    4040if BUILDLIB
    41 inst_headers_nosrc = \
    42         bitmanip.hfa \
    43         clock.hfa \
    44         exception.hfa \
    45         exception.h \
    46         gmp.hfa \
    47         math.hfa \
    48         time_t.hfa \
    49         bits/align.hfa \
    50         bits/containers.hfa \
    51         bits/debug.hfa \
    52         bits/defs.hfa \
    53         bits/locks.hfa \
    54         bits/collection.hfa \
    55         bits/stack.hfa \
    56         bits/queue.hfa \
    57         bits/sequence.hfa \
    58         concurrency/iofwd.hfa \
    59         containers/list.hfa \
    60         containers/stackLockFree.hfa \
    61         vec/vec.hfa \
    62         vec/vec2.hfa \
    63         vec/vec3.hfa \
    64         vec/vec4.hfa
     41headers_nosrc = math.hfa gmp.hfa time_t.hfa bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa
     42headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \
     43          containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa \
     44          vec/vec.hfa vec/vec2.hfa vec/vec3.hfa vec/vec4.hfa
    6545
    66 inst_headers_src = \
    67         common.hfa \
    68         fstream.hfa \
    69         heap.hfa \
    70         iostream.hfa \
    71         iterator.hfa \
    72         limits.hfa \
    73         memory.hfa \
    74         parseargs.hfa \
    75         rational.hfa \
    76         stdlib.hfa \
    77         time.hfa \
    78         containers/maybe.hfa \
    79         containers/pair.hfa \
    80         containers/result.hfa \
    81         containers/vector.hfa
    82 
    83 libsrc = ${inst_headers_src} ${inst_headers_src:.hfa=.cfa} \
    84         assert.cfa \
    85         bits/algorithm.hfa \
    86         bits/debug.cfa \
    87         exception.c \
    88         interpose.cfa \
    89         lsda.h \
    90         startup.cfa \
    91         startup.hfa \
    92         virtual.c \
    93         virtual.h
     46libsrc = startup.cfa interpose.cfa bits/debug.cfa assert.cfa exception.c virtual.c heap.cfa ${headers:.hfa=.cfa}
    9447
    9548# not all platforms support concurrency, add option do disable it
    96 inst_thread_headers_nosrc = \
    97         bits/random.hfa \
    98         concurrency/clib/cfathread.h \
    99         concurrency/invoke.h \
    100         concurrency/future.hfa \
    101         concurrency/kernel/fwd.hfa
    102 
    103 inst_thread_headers_src = \
    104         concurrency/coroutine.hfa \
    105         concurrency/exception.hfa \
    106         concurrency/kernel.hfa \
    107         concurrency/locks.hfa \
    108         concurrency/monitor.hfa \
    109         concurrency/mutex.hfa \
    110         concurrency/thread.hfa
    111 
    112 thread_libsrc = ${inst_thread_headers_src} ${inst_thread_headers_src:.hfa=.cfa} \
    113         bits/signal.hfa \
    114         concurrency/alarm.cfa \
    115         concurrency/alarm.hfa \
    116         concurrency/clib/cfathread.cfa \
    117         concurrency/CtxSwitch-@ARCHITECTURE@.S \
    118         concurrency/invoke.c \
    119         concurrency/io.cfa \
    120         concurrency/io/setup.cfa \
    121         concurrency/io/types.hfa \
    122         concurrency/io/call.cfa \
    123         concurrency/iofwd.hfa \
    124         concurrency/kernel_private.hfa \
    125         concurrency/kernel/startup.cfa \
    126         concurrency/preemption.cfa \
    127         concurrency/preemption.hfa \
    128         concurrency/ready_queue.cfa \
    129         concurrency/ready_subqueue.hfa \
    130         concurrency/snzi.hfa \
    131         concurrency/stats.cfa \
    132         concurrency/stats.hfa \
    133         concurrency/stats.hfa
    134 
     49thread_headers_nosrc = concurrency/invoke.h
     50thread_headers = concurrency/coroutine.hfa concurrency/thread.hfa concurrency/kernel.hfa concurrency/monitor.hfa concurrency/mutex.hfa
     51thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/preemption.cfa ${thread_headers:.hfa=.cfa}
    13552else
    136 inst_headers_src =
    137 inst_thread_headers_src =
    138 inst_headers_nosrc =
    139 inst_thread_headers_nosrc =
     53headers =
     54thread_headers =
     55headers_nosrc =
     56thread_headers_nosrc =
    14057libsrc =
    14158endif
     
    18097
    18198prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@
    182         ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@}
     99        ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA -l ${<} -c -o ${@}
    183100
    184101prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@
    185102        ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \
    186         $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@}
     103        $(CFACOMPILE) -quiet -XCFA -l ${<} -c -o ${@}
    187104
    188105#----------------------------------------------------------------------------------------------------------------
    189 libcfa_la_SOURCES = ${libsrc}
    190 nodist_libcfa_la_SOURCES = prelude.cfa
     106libcfa_la_SOURCES = prelude.cfa ${libsrc}
    191107libcfa_la_LDFLAGS = -version-info @CFA_VERSION@
    192108
     
    197113
    198114cfa_includedir = $(CFA_INCDIR)
    199 nobase_cfa_include_HEADERS = ${stdhdr} ${inst_headers_src} ${inst_headers_nosrc} ${inst_thread_headers_src} ${inst_thread_headers_nosrc}
    200 EXTRA_DIST = stdhdr
     115nobase_cfa_include_HEADERS = ${stdhdr} ${headers} ${headers_nosrc} ${thread_headers} ${thread_headers_nosrc}
    201116
    202117#----------------------------------------------------------------------------------------------------------------
     
    204119        -rm -rf ${CFA_INCDIR} ${CFA_LIBDIR}
    205120
    206 distclean-local:
    207         find ${builddir} -path '*.Plo' -delete
    208 
    209121
    210122# $(AM_V_CFA)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
  • libcfa/src/assert.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 13:00:18 2020
    13 // Update Count     : 6
     12// Last Modified On : Thu Nov 21 17:09:26 2019
     13// Update Count     : 5
    1414//
    1515
     
    2626
    2727        // called by macro assert in assert.h
    28         void __assert_fail( const char assertion[], const char file[], unsigned int line, const char function[] ) {
     28        void __assert_fail( const char *assertion, const char *file, unsigned int line, const char *function ) {
    2929                __cfaabi_bits_print_safe( STDERR_FILENO, CFA_ASSERT_FMT ".\n", assertion, __progname, function, line, file );
    3030                abort();
     
    3232
    3333        // called by macro assertf
    34         void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) {
     34        void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) {
    3535                __cfaabi_bits_acquire();
    3636                __cfaabi_bits_print_nolock( STDERR_FILENO, CFA_ASSERT_FMT ": ", assertion, __progname, function, line, file );
  • libcfa/src/bits/containers.hfa

    reef8dfb rbdfc032  
    1717#include "bits/align.hfa"
    1818#include "bits/defs.hfa"
    19 #include <stdio.h>
     19
    2020//-----------------------------------------------------------------------------
    2121// Array
     
    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
     
    146146        static inline forall( dtype T | is_node(T) ) {
    147147                void ?{}( __queue(T) & this ) with( this ) {
    148                         (this.head){ 1p };
    149                         (this.tail){ &this.head };
    150                         verify(*this.tail == 1p);
     148                        head{ 0p };
     149                        tail{ &head };
    151150                }
    152151
    153152                void append( __queue(T) & this, T * val ) with( this ) {
    154                         verify(this.tail != 0p);
    155                         verify(*this.tail == 1p);
    156                         *this.tail = val;
    157                         this.tail = &get_next( *val );
    158                         *this.tail = 1p;
    159                 }
    160 
    161                 T * peek( __queue(T) & this ) {
    162                         verify(*this.tail == 1p);
    163                         T * front = this.head;
    164                         if( front != 1p ) {
    165                                 verify(*this.tail == 1p);
    166                                 return front;
    167                         }
    168                         verify(*this.tail == 1p);
    169                         return 0p;
     153                        verify(tail != 0p);
     154                        *tail = val;
     155                        tail = &get_next( *val );
    170156                }
    171157
    172158                T * pop_head( __queue(T) & this ) {
    173                         verify(*this.tail == 1p);
    174                         T * _head = this.head;
    175                         if( _head != 1p ) {
    176                                 this.head = get_next( *_head );
    177                                 if( get_next( *_head ) == 1p ) {
     159                        T * head = this.head;
     160                        if( head ) {
     161                                this.head = get_next( *head );
     162                                if( !get_next( *head ) ) {
    178163                                        this.tail = &this.head;
    179164                                }
    180                                 get_next( *_head ) = 0p;
    181                                 verify(*this.tail == 1p);
    182                                 verify( get_next(*_head) == 0p );
    183                                 return _head;
    184                         }
    185                         verify(*this.tail == 1p);
    186                         return 0p;
     165                                get_next( *head ) = 0p;
     166                        }
     167                        return head;
    187168                }
    188169
     
    193174                        (*it) = get_next( *val );
    194175
    195                         if( this.tail == &get_next( *val ) ) {
    196                                 this.tail = it;
     176                        if( tail == &get_next( *val ) ) {
     177                                tail = it;
    197178                        }
    198179
    199180                        get_next( *val ) = 0p;
    200181
    201                         verify( (this.head == 1p) == (&this.head == this.tail) );
    202                         verify( *this.tail == 1p );
     182                        verify( (head == 0p) == (&head == tail) );
     183                        verify( *tail == 0p );
    203184                        return val;
    204185                }
    205186
    206187                int ?!=?( const __queue(T) & this, __attribute__((unused)) zero_t zero ) {
    207                         return this.head != 1p;
     188                        return this.head != 0;
    208189                }
    209190        }
     
    239220        forall(dtype T )
    240221        static inline [void] ?{}( __dllist(T) & this, * [T * & next, T * & prev] ( T & ) __get ) {
    241                 (this.head){ 0p };
     222                this.head{ 0p };
    242223                this.__get = __get;
    243224        }
     
    248229                void push_front( __dllist(T) & this, T & node ) with( this ) {
    249230                        verify(__get);
    250                         if ( this.head ) {
    251                                 __get( node ).next = this.head;
    252                                 __get( node ).prev = __get( *this.head ).prev;
     231                        if ( head ) {
     232                                __get( node ).next = head;
     233                                __get( node ).prev = __get( *head ).prev;
    253234                                // inserted node must be consistent before it is seen
    254235                                // prevent code movement across barrier
    255236                                asm( "" : : : "memory" );
    256                                 __get( *this.head ).prev = &node;
     237                                __get( *head ).prev = &node;
    257238                                T & _prev = *__get( node ).prev;
    258239                                __get( _prev ).next = &node;
     
    264245                        // prevent code movement across barrier
    265246                        asm( "" : : : "memory" );
    266                         this.head = &node;
     247                        head = &node;
    267248                }
    268249
    269250                void remove( __dllist(T) & this, T & node ) with( this ) {
    270251                        verify(__get);
    271                         if ( &node == this.head ) {
    272                                 if ( __get( *this.head ).next == this.head ) {
    273                                         this.head = 0p;
     252                        if ( &node == head ) {
     253                                if ( __get( *head ).next == head ) {
     254                                        head = 0p;
    274255                                } else {
    275                                         this.head = __get( *this.head ).next;
     256                                        head = __get( *head ).next;
    276257                                }
    277258                        }
     
    285266                        return this.head != 0;
    286267                }
    287 
    288                 void move_to_front( __dllist(T) & src, __dllist(T) & dst, T & node ) {
    289                         remove    (src, node);
    290                         push_front(dst, node);
    291                 }
    292268        }
    293269        #undef next
  • libcfa/src/bits/debug.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Thu Mar 30 12:30:01 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 17 11:07:13 2020
    13 // Update Count     : 12
     12// Last Modified On : Thu Nov 21 17:16:30 2019
     13// Update Count     : 10
    1414//
    1515
     16extern "C" {
    1617#include <stdio.h>
    1718#include <stdlib.h>
     
    2021#include <stdarg.h>
    2122#include <unistd.h>
     23}
    2224
    2325enum { buffer_size = 4096 };
     
    2527
    2628extern "C" {
    27         void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) {
     29
     30        void __cfaabi_bits_write( int fd, const char *in_buffer, int len ) {
    2831                // ensure all data is written
    2932                for ( int count = 0, retcode; count < len; count += retcode ) {
  • libcfa/src/bits/debug.hfa

    reef8dfb rbdfc032  
    99// Author           : Thierry Delisle
    1010// Created On       : Mon Nov 28 12:27:26 2016
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Apr 27 10:15:00 2020
    13 // Update Count     : 10
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Nov 21 17:06:58 2019
     13// Update Count     : 8
    1414//
    1515
    1616#pragma once
    17 
    18 #include <assert.h>
    1917
    2018#ifdef __CFA_DEBUG__
     
    2321        #define __cfaabi_dbg_ctx __PRETTY_FUNCTION__
    2422        #define __cfaabi_dbg_ctx2 , __PRETTY_FUNCTION__
    25         #define __cfaabi_dbg_ctx_param const char caller[]
    26         #define __cfaabi_dbg_ctx_param2 , const char caller[]
    27         #define __cfaabi_dbg_ctx_fwd caller
    28         #define __cfaabi_dbg_ctx_fwd2 , caller
     23        #define __cfaabi_dbg_ctx_param const char * caller
     24        #define __cfaabi_dbg_ctx_param2 , const char * caller
    2925#else
    3026        #define __cfaabi_dbg_debug_do(...)
     
    3430        #define __cfaabi_dbg_ctx_param
    3531        #define __cfaabi_dbg_ctx_param2
    36         #define __cfaabi_dbg_ctx_fwd
    37         #define __cfaabi_dbg_ctx_fwd2
    3832#endif
    3933
     
    4236#endif
    4337        #include <stdarg.h>
     38        #include <stdio.h>
    4439
    45         extern void __cfaabi_bits_write( int fd, const char buffer[], int len );
     40        extern void __cfaabi_bits_write( int fd, const char *buffer, int len );
    4641        extern void __cfaabi_bits_acquire();
    4742        extern void __cfaabi_bits_release();
     
    5045        extern void __cfaabi_bits_print_vararg( int fd, const char fmt[], va_list arg );
    5146        extern void __cfaabi_bits_print_buffer( int fd, char buffer[], int buffer_size, const char fmt[], ... ) __attribute__(( format(printf, 4, 5) ));
    52 
    53 #if defined(__CFA_DEBUG_PRINT__) \
    54                 || defined(__CFA_DEBUG_PRINT_IO__) || defined(__CFA_DEBUG_PRINT_IO_CORE__) \
    55                 || defined(__CFA_DEBUG_PRINT_MONITOR__) || defined(__CFA_DEBUG_PRINT_PREEMPTION__) \
    56                 || defined(__CFA_DEBUG_PRINT_RUNTIME_CORE__) || defined(__CFA_DEBUG_PRINT_EXCEPTION__) \
    57                 || defined(__CFA_DEBUG_PRINT_READY_QUEUE__)
    58         #include <stdio.h>
    59         #include <unistd.h>
    60 #endif
    6147#ifdef __cforall
    6248}
    6349#endif
    6450
    65 // Deprecated: Use the versions with the new module names.
    6651#ifdef __CFA_DEBUG_PRINT__
    6752        #define __cfaabi_dbg_write( buffer, len )         __cfaabi_bits_write( STDERR_FILENO, buffer, len )
    6853        #define __cfaabi_dbg_acquire()                    __cfaabi_bits_acquire()
    6954        #define __cfaabi_dbg_release()                    __cfaabi_bits_release()
    70         #define __cfaabi_dbg_print_safe(...)              __cfaabi_bits_print_safe   ( STDERR_FILENO, __VA_ARGS__ )
    71         #define __cfaabi_dbg_print_nolock(...)            __cfaabi_bits_print_nolock ( STDERR_FILENO, __VA_ARGS__ )
    72         #define __cfaabi_dbg_print_buffer(...)            __cfaabi_bits_print_buffer ( STDERR_FILENO, __VA_ARGS__ )
    73         #define __cfaabi_dbg_print_buffer_decl(...)       char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( STDERR_FILENO, __dbg_text, __dbg_len );
    74         #define __cfaabi_dbg_print_buffer_local(...)      __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_dbg_write( STDERR_FILENO, __dbg_text, __dbg_len );
     55        #define __cfaabi_dbg_print_safe(...)              __cfaabi_bits_print_safe   (__VA_ARGS__)
     56        #define __cfaabi_dbg_print_nolock(...)            __cfaabi_bits_print_nolock (__VA_ARGS__)
     57        #define __cfaabi_dbg_print_buffer(...)            __cfaabi_bits_print_buffer (__VA_ARGS__)
     58        #define __cfaabi_dbg_print_buffer_decl(...)       char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( __dbg_text, __dbg_len );
     59        #define __cfaabi_dbg_print_buffer_local(...)      __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_dbg_write( __dbg_text, __dbg_len );
    7560#else
    7661        #define __cfaabi_dbg_write(...)               ((void)0)
     
    8469#endif
    8570
    86 // Debug print functions and statements:
    87 // Most are wrappers around the bits printing function but are not always used.
    88 // If they are used depends if the group (first argument) is active or not. The group must be one
    89 // defined belowe. The other arguments depend on the wrapped function.
    90 #define __cfadbg_write(group, buffer, len) \
    91         __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_write(STDERR_FILENO, buffer, len))
    92 #define __cfadbg_acquire(group) \
    93         __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_acquire())
    94 #define __cfadbg_release(group) \
    95         __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_release())
    96 #define __cfadbg_print_safe(group, ...) \
    97         __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_print_safe(STDERR_FILENO, __VA_ARGS__))
    98 #define __cfadbg_print_nolock(group, ...) \
    99         __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_print_nolock(STDERR_FILENO, __VA_ARGS__))
    100 #define __cfadbg_print_buffer(group, ...) \
    101         __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_print_buffer(STDERR_FILENO, __VA_ARGS__))
    102 #define __cfadbg_print_buffer_decl(group, ...) \
    103         __CFADBG_PRINT_GROUP_##group(char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( __dbg_text, __dbg_len ))
    104 #define __cfadbg_print_buffer_local(group, ...) \
    105         __CFADBG_PRINT_GROUP_##group(__dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write(STDERR_FILENO, __dbg_text, __dbg_len))
    106 
    107 // The debug print groups:
    108 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_IO__)
    109 #       define __CFADBG_PRINT_GROUP_io(...) __VA_ARGS__
    110 #else
    111 #       define __CFADBG_PRINT_GROUP_io(...) ((void)0)
    112 #endif
    113 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_IO__) || defined(__CFA_DEBUG_PRINT_IO_CORE__)
    114 #       define __CFADBG_PRINT_GROUP_io_core(...) __VA_ARGS__
    115 #else
    116 #       define __CFADBG_PRINT_GROUP_io_core(...) ((void)0)
    117 #endif
    118 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_MONITOR__)
    119 #       define __CFADBG_PRINT_GROUP_monitor(...) __VA_ARGS__
    120 #else
    121 #       define __CFADBG_PRINT_GROUP_monitor(...) ((void)0)
    122 #endif
    123 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_PREEMPTION__)
    124 #       define __CFADBG_PRINT_GROUP_preemption(...) __VA_ARGS__
    125 #else
    126 #       define __CFADBG_PRINT_GROUP_preemption(...) ((void)0)
    127 #endif
    128 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_RUNTIME_CORE__)
    129 #       define __CFADBG_PRINT_GROUP_runtime_core(...) __VA_ARGS__
    130 #else
    131 #       define __CFADBG_PRINT_GROUP_runtime_core(...) ((void)0)
    132 #endif
    133 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_READY_QUEUE__)
    134 #       define __CFADBG_PRINT_GROUP_ready_queue(...) __VA_ARGS__
    135 #else
    136 #       define __CFADBG_PRINT_GROUP_ready_queue(...) ((void)0)
    137 #endif
    138 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_EXCEPTION__)
    139 #       define __CFADBG_PRINT_GROUP_exception(...) __VA_ARGS__
    140 #else
    141 #       define __CFADBG_PRINT_GROUP_exception(...) ((void)0)
    142 #endif
    143 
    14471// Local Variables: //
    14572// mode: c //
  • libcfa/src/bits/defs.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Thu Nov  9 13:24:10 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Oct 24 10:53:15 2020
    13 // Update Count     : 21
     12// Last Modified On : Tue Jan 28 22:38:27 2020
     13// Update Count     : 9
    1414//
    1515
    1616#pragma once
    1717
     18#include <stdbool.h>
     19#include <stddef.h>
    1820#include <stdint.h>
    19 #include <assert.h>
    2021
    2122#define likely(x)   __builtin_expect(!!(x), 1)
     
    2930#define __cfa_anonymous_object(x) inline struct x
    3031#else
    31 #define __cfa_anonymous_object(x) struct x __cfa_anonymous_object
     32#define __cfa_anonymous_object(x) x __cfa_anonymous_object
    3233#endif
    3334
     
    4849#endif
    4950
    50 static inline long long int rdtscl(void) {
    51         #if defined( __i386 ) || defined( __x86_64 )
    52         unsigned int lo, hi;
    53         __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    54         return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
    55         #elif defined( __aarch64__ ) || defined( __arm__ )
    56         // https://github.com/google/benchmark/blob/v1.1.0/src/cycleclock.h#L116
    57         long long int virtual_timer_value;
    58         asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
    59         return virtual_timer_value;
    60         #else
    61                 #error unsupported hardware architecture
    62         #endif
     51static inline long long rdtscl(void) {
     52    unsigned int lo, hi;
     53    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
     54    return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
    6355}
  • libcfa/src/bits/locks.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Oct 31 15:14:38 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Aug 12 14:18:07 2020
    13 // Update Count     : 13
     12// Last Modified On : Sat Aug 11 15:42:24 2018
     13// Update Count     : 10
    1414//
    1515
     
    2727
    2828// pause to prevent excess processor bus usage
    29 #if defined( __i386 ) || defined( __x86_64 )
     29#if defined( __sparc )
     30        #define Pause() __asm__ __volatile__ ( "rd %ccr,%g0" )
     31#elif defined( __i386 ) || defined( __x86_64 )
    3032        #define Pause() __asm__ __volatile__ ( "pause" : : : )
    3133#elif defined( __ARM_ARCH )
    32         #define Pause() __asm__ __volatile__ ( "YIELD" : : : )
     34        #define Pause() __asm__ __volatile__ ( "nop" : : : )
    3335#else
    3436        #error unsupported architecture
     
    5254
    5355                #ifdef __CFA_DEBUG__
    54                         void __cfaabi_dbg_record_lock(__spinlock_t & this, const char prev_name[]);
     56                        void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name);
    5557                #else
    56                         #define __cfaabi_dbg_record_lock(x, y)
     58                        #define __cfaabi_dbg_record(x, y)
    5759                #endif
    5860        }
     61
     62        extern void yield( unsigned int );
    5963
    6064        static inline void ?{}( __spinlock_t & this ) {
     
    6468        // Lock the spinlock, return false if already acquired
    6569        static inline bool try_lock  ( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) {
    66                 disable_interrupts();
    6770                bool result = (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0);
    6871                if( result ) {
    69                         __cfaabi_dbg_record_lock( this, caller );
    70                 } else {
    71                         enable_interrupts_noPoll();
     72                        disable_interrupts();
     73                        __cfaabi_dbg_record( this, caller );
    7274                }
    7375                return result;
     
    8183                #endif
    8284
    83                 disable_interrupts();
    8485                for ( unsigned int i = 1;; i += 1 ) {
    8586                        if ( (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0) ) break;
     
    9798                        #endif
    9899                }
    99                 __cfaabi_dbg_record_lock( this, caller );
     100                disable_interrupts();
     101                __cfaabi_dbg_record( this, caller );
    100102        }
    101103
    102104        static inline void unlock( __spinlock_t & this ) {
     105                enable_interrupts_noPoll();
    103106                __atomic_clear( &this.lock, __ATOMIC_RELEASE );
    104                 enable_interrupts_noPoll();
    105107        }
    106108
     
    110112        #endif
    111113
    112         extern "C" {
    113                 char * strerror(int);
    114         }
    115         #define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); }
    116 
    117114        struct __bin_sem_t {
     115                bool                    signaled;
    118116                pthread_mutex_t         lock;
    119117                pthread_cond_t          cond;
    120                 int                     val;
    121118        };
    122119
    123120        static inline void ?{}(__bin_sem_t & this) with( this ) {
    124                 // Create the mutex with error checking
    125                 pthread_mutexattr_t mattr;
    126                 pthread_mutexattr_init( &mattr );
    127                 pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP);
    128                 pthread_mutex_init(&lock, &mattr);
    129 
    130                 pthread_cond_init (&cond, (const pthread_condattr_t *)0p);  // workaround trac#208: cast should not be required
    131                 val = 0;
     121                signaled = false;
     122                pthread_mutex_init(&lock, NULL);
     123                pthread_cond_init (&cond, NULL);
    132124        }
    133125
    134126        static inline void ^?{}(__bin_sem_t & this) with( this ) {
    135                 CHECKED( pthread_mutex_destroy(&lock) );
    136                 CHECKED( pthread_cond_destroy (&cond) );
     127                pthread_mutex_destroy(&lock);
     128                pthread_cond_destroy (&cond);
    137129        }
    138130
    139131        static inline void wait(__bin_sem_t & this) with( this ) {
    140132                verify(__cfaabi_dbg_in_kernel());
    141                 CHECKED( pthread_mutex_lock(&lock) );
    142                         while(val < 1) {
     133                pthread_mutex_lock(&lock);
     134                        if(!signaled) {   // this must be a loop, not if!
    143135                                pthread_cond_wait(&cond, &lock);
    144136                        }
    145                         val -= 1;
    146                 CHECKED( pthread_mutex_unlock(&lock) );
     137                        signaled = false;
     138                pthread_mutex_unlock(&lock);
    147139        }
    148140
    149         static inline bool post(__bin_sem_t & this) with( this ) {
    150                 bool needs_signal = false;
     141        static inline void post(__bin_sem_t & this) with( this ) {
     142                verify(__cfaabi_dbg_in_kernel());
    151143
    152                 CHECKED( pthread_mutex_lock(&lock) );
    153                         if(val < 1) {
    154                                 val += 1;
    155                                 pthread_cond_signal(&cond);
    156                                 needs_signal = true;
    157                         }
    158                 CHECKED( pthread_mutex_unlock(&lock) );
     144                pthread_mutex_lock(&lock);
     145                        bool needs_signal = !signaled;
     146                        signaled = true;
     147                pthread_mutex_unlock(&lock);
    159148
    160                 return needs_signal;
    161         }
    162 
    163         #undef CHECKED
    164 
    165         struct $thread;
    166         extern void park( void );
    167         extern void unpark( struct $thread * this );
    168         static inline struct $thread * active_thread ();
    169 
    170         // Semaphore which only supports a single thread
    171         struct single_sem {
    172                 struct $thread * volatile ptr;
    173         };
    174 
    175         static inline {
    176                 void  ?{}(single_sem & this) {
    177                         this.ptr = 0p;
    178                 }
    179 
    180                 void ^?{}(single_sem &) {}
    181 
    182                 bool wait(single_sem & this) {
    183                         for() {
    184                                 struct $thread * expected = this.ptr;
    185                                 if(expected == 1p) {
    186                                         if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    187                                                 return false;
    188                                         }
    189                                 }
    190                                 else {
    191                                         /* paranoid */ verify( expected == 0p );
    192                                         if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    193                                                 park();
    194                                                 return true;
    195                                         }
    196                                 }
    197 
    198                         }
    199                 }
    200 
    201                 bool post(single_sem & this) {
    202                         for() {
    203                                 struct $thread * expected = this.ptr;
    204                                 if(expected == 1p) return false;
    205                                 if(expected == 0p) {
    206                                         if(__atomic_compare_exchange_n(&this.ptr, &expected, 1p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    207                                                 return false;
    208                                         }
    209                                 }
    210                                 else {
    211                                         if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    212                                                 unpark( expected );
    213                                                 return true;
    214                                         }
    215                                 }
    216                         }
    217                 }
    218         }
    219 
    220         // Synchronozation primitive which only supports a single thread and one post
    221         // Similar to a binary semaphore with a 'one shot' semantic
    222         // is expected to be discarded after each party call their side
    223         struct oneshot {
    224                 // Internal state :
    225                 //     0p     : is initial state (wait will block)
    226                 //     1p     : fulfilled (wait won't block)
    227                 // any thread : a thread is currently waiting
    228                 struct $thread * volatile ptr;
    229         };
    230 
    231         static inline {
    232                 void  ?{}(oneshot & this) {
    233                         this.ptr = 0p;
    234                 }
    235 
    236                 void ^?{}(oneshot &) {}
    237 
    238                 // Wait for the post, return immidiately if it already happened.
    239                 // return true if the thread was parked
    240                 bool wait(oneshot & this) {
    241                         for() {
    242                                 struct $thread * expected = this.ptr;
    243                                 if(expected == 1p) return false;
    244                                 /* paranoid */ verify( expected == 0p );
    245                                 if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    246                                         park();
    247                                         /* paranoid */ verify( this.ptr == 1p );
    248                                         return true;
    249                                 }
    250                         }
    251                 }
    252 
    253                 // Mark as fulfilled, wake thread if needed
    254                 // return true if a thread was unparked
    255                 bool post(oneshot & this) {
    256                         struct $thread * got = __atomic_exchange_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
    257                         if( got == 0p ) return false;
    258                         unpark( got );
    259                         return true;
    260                 }
    261         }
    262 
    263         // base types for future to build upon
    264         // It is based on the 'oneshot' type to allow multiple futures
    265         // to block on the same instance, permitting users to block a single
    266         // thread on "any of" [a given set of] futures.
    267         // does not support multiple threads waiting on the same future
    268         struct future_t {
    269                 // Internal state :
    270                 //     0p      : is initial state (wait will block)
    271                 //     1p      : fulfilled (wait won't block)
    272                 //     2p      : in progress ()
    273                 //     3p      : abandoned, server should delete
    274                 // any oneshot : a context has been setup to wait, a thread could wait on it
    275                 struct oneshot * volatile ptr;
    276         };
    277 
    278         static inline {
    279                 void  ?{}(future_t & this) {
    280                         this.ptr = 0p;
    281                 }
    282 
    283                 void ^?{}(future_t &) {}
    284 
    285                 void reset(future_t & this) {
    286                         // needs to be in 0p or 1p
    287                         __atomic_exchange_n( &this.ptr, 0p, __ATOMIC_SEQ_CST);
    288                 }
    289 
    290                 // check if the future is available
    291                 bool available( future_t & this ) {
    292                         return this.ptr == 1p;
    293                 }
    294 
    295                 // Prepare the future to be waited on
    296                 // intented to be use by wait, wait_any, waitfor, etc. rather than used directly
    297                 bool setup( future_t & this, oneshot & wait_ctx ) {
    298                         /* paranoid */ verify( wait_ctx.ptr == 0p );
    299                         // The future needs to set the wait context
    300                         for() {
    301                                 struct oneshot * expected = this.ptr;
    302                                 // Is the future already fulfilled?
    303                                 if(expected == 1p) return false; // Yes, just return false (didn't block)
    304 
    305                                 // The future is not fulfilled, try to setup the wait context
    306                                 /* paranoid */ verify( expected == 0p );
    307                                 if(__atomic_compare_exchange_n(&this.ptr, &expected, &wait_ctx, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    308                                         return true;
    309                                 }
    310                         }
    311                 }
    312 
    313                 // Stop waiting on a future
    314                 // When multiple futures are waited for together in "any of" pattern
    315                 // futures that weren't fulfilled before the thread woke up
    316                 // should retract the wait ctx
    317                 // intented to be use by wait, wait_any, waitfor, etc. rather than used directly
    318                 void retract( future_t & this, oneshot & wait_ctx ) {
    319                         // Remove the wait context
    320                         struct oneshot * got = __atomic_exchange_n( &this.ptr, 0p, __ATOMIC_SEQ_CST);
    321 
    322                         // got == 0p: future was never actually setup, just return
    323                         if( got == 0p ) return;
    324 
    325                         // got == wait_ctx: since fulfil does an atomic_swap,
    326                         // if we got back the original then no one else saw context
    327                         // It is safe to delete (which could happen after the return)
    328                         if( got == &wait_ctx ) return;
    329 
    330                         // got == 1p: the future is ready and the context was fully consumed
    331                         // the server won't use the pointer again
    332                         // It is safe to delete (which could happen after the return)
    333                         if( got == 1p ) return;
    334 
    335                         // got == 2p: the future is ready but the context hasn't fully been consumed
    336                         // spin until it is safe to move on
    337                         if( got == 2p ) {
    338                                 while( this.ptr != 1p ) Pause();
    339                                 return;
    340                         }
    341 
    342                         // got == any thing else, something wen't wrong here, abort
    343                         abort("Future in unexpected state");
    344                 }
    345 
    346                 // Mark the future as abandoned, meaning it will be deleted by the server
    347                 bool abandon( future_t & this ) {
    348                         /* paranoid */ verify( this.ptr != 3p );
    349 
    350                         // Mark the future as abandonned
    351                         struct oneshot * got = __atomic_exchange_n( &this.ptr, 3p, __ATOMIC_SEQ_CST);
    352 
    353                         // If the future isn't already fulfilled, let the server delete it
    354                         if( got == 0p ) return false;
    355 
    356                         // got == 2p: the future is ready but the context hasn't fully been consumed
    357                         // spin until it is safe to move on
    358                         if( got == 2p ) {
    359                                 while( this.ptr != 1p ) Pause();
    360                                 got = 1p;
    361                         }
    362 
    363                         // The future is completed delete it now
    364                         /* paranoid */ verify( this.ptr != 1p );
    365                         free( &this );
    366                         return true;
    367                 }
    368 
    369                 // from the server side, mark the future as fulfilled
    370                 // delete it if needed
    371                 bool fulfil( future_t & this ) {
    372                         for() {
    373                                 struct oneshot * expected = this.ptr;
    374                                 // was this abandoned?
    375                                 #if defined(__GNUC__) && __GNUC__ >= 7
    376                                         #pragma GCC diagnostic push
    377                                         #pragma GCC diagnostic ignored "-Wfree-nonheap-object"
    378                                 #endif
    379                                         if( expected == 3p ) { free( &this ); return false; }
    380                                 #if defined(__GNUC__) && __GNUC__ >= 7
    381                                         #pragma GCC diagnostic pop
    382                                 #endif
    383 
    384                                 /* paranoid */ verify( expected != 1p ); // Future is already fulfilled, should not happen
    385                                 /* paranoid */ verify( expected != 2p ); // Future is bein fulfilled by someone else, this is even less supported then the previous case.
    386 
    387                                 // If there is a wait context, we need to consume it and mark it as consumed after
    388                                 // If there is no context then we can skip the in progress phase
    389                                 struct oneshot * want = expected == 0p ? 1p : 2p;
    390                                 if(__atomic_compare_exchange_n(&this.ptr, &expected, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    391                                         if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return false; }
    392                                         bool ret = post( *expected );
    393                                         __atomic_store_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
    394                                         return ret;
    395                                 }
    396                         }
    397 
    398                 }
    399 
    400                 // Wait for the future to be fulfilled
    401                 bool wait( future_t & this ) {
    402                         oneshot temp;
    403                         if( !setup(this, temp) ) return false;
    404 
    405                         // Wait context is setup, just wait on it
    406                         bool ret = wait( temp );
    407 
    408                         // Wait for the future to tru
    409                         while( this.ptr == 2p ) Pause();
    410                         // Make sure the state makes sense
    411                         // Should be fulfilled, could be in progress but it's out of date if so
    412                         // since if that is the case, the oneshot was fulfilled (unparking this thread)
    413                         // and the oneshot should not be needed any more
    414                         __attribute__((unused)) struct oneshot * was = this.ptr;
    415                         /* paranoid */ verifyf( was == 1p, "Expected this.ptr to be 1p, was %p\n", was );
    416 
    417                         // Mark the future as fulfilled, to be consistent
    418                         // with potential calls to avail
    419                         // this.ptr = 1p;
    420                         return ret;
    421                 }
     149                if (needs_signal)
     150                        pthread_cond_signal(&cond);
    422151        }
    423152#endif
  • libcfa/src/bits/signal.hfa

    reef8dfb rbdfc032  
    1919#include "bits/defs.hfa"
    2020
     21extern "C" {
    2122#include <errno.h>
    2223#define __USE_GNU
     
    2526#include <stdlib.h>
    2627#include <string.h>
     28}
    2729
    2830// Short hands for signal context information
     
    5254                        sig, handler, flags, errno, strerror( errno )
    5355                );
    54                 _Exit( EXIT_FAILURE );
     56                _exit( EXIT_FAILURE );
    5557        } // if
    5658}
  • libcfa/src/common.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed Jul 11 17:54:36 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 15 08:51:29 2020
    13 // Update Count     : 14
     12// Last Modified On : Thu Jul 12 08:02:18 2018
     13// Update Count     : 5
    1414//
    1515
     
    6767
    6868static inline {
    69         char min( char t1, char t2 ) { return t1 < t2 ? t1 : t2; } // optimization
    70         intptr_t min( intptr_t t1, intptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
    71         uintptr_t min( uintptr_t t1, uintptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
    7269        forall( otype T | { int ?<?( T, T ); } )
    7370        T min( T t1, T t2 ) { return t1 < t2 ? t1 : t2; }
    7471
    75         char max( char t1, char t2 ) { return t1 > t2 ? t1 : t2; } // optimization
    76         intptr_t max( intptr_t t1, intptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
    77         uintptr_t max( uintptr_t t1, uintptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
    7872        forall( otype T | { int ?>?( T, T ); } )
    7973        T max( T t1, T t2 ) { return t1 > t2 ? t1 : t2; }
  • libcfa/src/concurrency/CtxSwitch-i386.S

    reef8dfb rbdfc032  
    1010// Created On       : Tue Dec 6 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep  6 18:23:37 2020
    13 // Update Count     : 5
     12// Last Modified On : Fri Jul 21 22:29:25 2017
     13// Update Count     : 1
     14//
     15// This  library is free  software; you  can redistribute  it and/or  modify it
     16// under the terms of the GNU Lesser General Public License as published by the
     17// Free Software  Foundation; either  version 2.1 of  the License, or  (at your
     18// option) any later version.
     19//
     20// This library is distributed in the  hope that it will be useful, but WITHOUT
     21// ANY  WARRANTY;  without even  the  implied  warranty  of MERCHANTABILITY  or
     22// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
     23// for more details.
     24//
     25// You should  have received a  copy of the  GNU Lesser General  Public License
     26// along  with this library.
    1427//
    1528
    16 // The context switch routine requires the initial the stack of a thread to
    17 // look like the thread has saved its context in the normal manner.
     29// This context switch routine depends on the fact that the stack of a new
     30// thread has been set up to look like the thread has saved its context in
     31// the normal manner.
     32//
     33// void CtxSwitch( machine_context *from, machine_context *to );
    1834
    19 // Offsets must synchronized with the __stack_context_t in invoke.h.
     35// Offsets in the context structure. This needs to be synchronized with the
     36// high level code a little better.
    2037
    2138#define PTR_BYTE        4
    2239#define SP_OFFSET       ( 0 * PTR_BYTE )
    2340#define FP_OFFSET       ( 1 * PTR_BYTE )
     41#define PC_OFFSET       ( 2 * PTR_BYTE )
    2442
    25 // Context switch between coroutines/tasks.
    26 //   void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) ;
    27 // Arguments "from" in register 4(%esp), "to" in register 20(%esp)
    28 
    29         .file "CtxSwitch-i386.S"
    3043        .text
    3144        .align 2
    32         .global __cfactx_switch
    33         .type __cfactx_switch, @function
    34 __cfactx_switch:
     45        .globl CtxSwitch
     46        .type  CtxSwitch, @function
     47CtxSwitch:
    3548
    3649        // Copy the "from" context argument from the stack to register eax
    37         // Return address is at 0(%esp), with parameters following.
     50        // Return address is at 0(%esp), with parameters following
    3851
    3952        movl 4(%esp),%eax
     
    5063        movl %ebp,FP_OFFSET(%eax)
    5164
    52         // Copy the "to" context argument from the stack to register eax. Having
    53         // pushed 3 words (= 12 bytes) on the stack, the argument is now at
    54         // 8 + 12 = 20(%esp).
     65        // Copy the "to" context argument from the stack to register eax
     66        // Having pushed three words (= 12 bytes) on the stack, the
     67        // argument is now at 8 + 12 = 20(%esp)
    5568
    5669        movl 20(%esp),%eax
     
    7083
    7184        ret
    72         .size __cfactx_switch, .-__cfactx_switch
     85        .size  CtxSwitch, .-CtxSwitch
    7386
    7487// Local Variables: //
  • libcfa/src/concurrency/CtxSwitch-x86_64.S

    reef8dfb rbdfc032  
    77// CtxSwitch-x86_64.S --
    88//
    9 // Author           : Peter A. Buhr
    10 // Created On       : Mon Aug 10 08:10:26 2020
     9// Author           : Thierry Delisle
     10// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Oct 24 14:36:25 2020
    13 // Update Count     : 10
     12// Last Modified On : Fri Jul 21 22:28:11 2017
     13// Update Count     : 1
     14//
     15// This  library is free  software; you  can redistribute  it and/or  modify it
     16// under the terms of the GNU Lesser General Public License as published by the
     17// Free Software  Foundation; either  version 2.1 of  the License, or  (at your
     18// option) any later version.
     19//
     20// This library is distributed in the  hope that it will be useful, but WITHOUT
     21// ANY  WARRANTY;  without even  the  implied  warranty  of MERCHANTABILITY  or
     22// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
     23// for more details.
     24//
     25// You should  have received a  copy of the  GNU Lesser General  Public License
     26// along  with this library.
    1427//
    1528
    16 // The context switch routine requires the initial the stack of a thread to
    17 // look like the thread has saved its context in the normal manner.
     29// This context switch routine depends on the fact that the stack of a new
     30// thread has been set up to look like the thread has saved its context in
     31// the normal manner.
     32//
     33// void CtxSwitch( machine_context *from, machine_context *to );
    1834
    19 // Offsets must synchronized with the __stack_context_t in invoke.h.
     35// Offsets in the context structure. This needs to be synchronized with the
     36// high level code a little better.
    2037
    2138#define PTR_BYTE        8
     
    2340#define FP_OFFSET       ( 1 * PTR_BYTE )
    2441
    25 // Context switch between coroutines/tasks.
    26 //   void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) ;
    27 // Arguments "from" in register rdi, "to" in register rsi.
    28 
    29         .file "CtxSwitch-x86_64.S"
     42//-----------------------------------------------------------------------------
     43// Regular context switch routine which enables switching from one context to anouther
    3044        .text
    3145        .align 2
    32         .global __cfactx_switch
    33         .type __cfactx_switch, @function
    34 __cfactx_switch:
     46        .globl CtxSwitch
     47        .type  CtxSwitch, @function
     48CtxSwitch:
    3549
    3650        // Save volatile registers on the stack.
     
    6377
    6478        ret
    65         .size __cfactx_switch, .-__cfactx_switch
     79        .size  CtxSwitch, .-CtxSwitch
    6680
    67 // Stub to create new stacks which can be context switched to
    68 //   void __cfactx_invoke_stub( void );
    69 
     81//-----------------------------------------------------------------------------
     82// Stub used to create new stacks which are ready to be context switched to
    7083        .text
    7184        .align 2
    72         .global __cfactx_invoke_stub
    73         .type __cfactx_invoke_stub, @function
    74 __cfactx_invoke_stub:
    75         movq %rbx, %rdi                                         // move main and this to first two arguments
     85        .globl CtxInvokeStub
     86        .type    CtxInvokeStub, @function
     87CtxInvokeStub:
     88        movq %rbx, %rdi
    7689        movq %r12, %rsi
    77         jmp *%r13                                                       // jmp to invoke
    78         .size __cfactx_invoke_stub, .-__cfactx_invoke_stub
     90        jmp *%r13
     91        .size  CtxInvokeStub, .-CtxInvokeStub
    7992
    8093// Local Variables: //
    81 // mode: asm //
     94// mode: c //
    8295// tab-width: 4 //
    8396// End: //
  • libcfa/src/concurrency/alarm.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Fri Jun 2 11:31:25 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 17 16:11:35 2020
    13 // Update Count     : 75
     12// Last Modified On : Sun Jan  5 08:41:36 2020
     13// Update Count     : 69
    1414//
    1515
    1616#define __cforall_thread__
    1717
     18extern "C" {
    1819#include <errno.h>
    1920#include <stdio.h>
     21#include <string.h>
    2022#include <unistd.h>
    21 #include <string.h>
    2223#include <sys/time.h>
     24}
    2325
    2426#include "alarm.hfa"
    25 #include "kernel/fwd.hfa"
     27#include "kernel_private.hfa"
    2628#include "preemption.hfa"
    2729
     
    4547//=============================================================================================
    4648
    47 void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period) with( this ) {
     49void ?{}( alarm_node_t & this, thread_desc * thrd, Time alarm, Duration period ) with( this ) {
    4850        this.thrd = thrd;
    4951        this.alarm = alarm;
    5052        this.period = period;
     53        next = 0;
    5154        set = false;
    52         type = User;
     55        kernel_alarm = false;
    5356}
    5457
    55 void ?{}( alarm_node_t & this, processor * proc, Time alarm, Duration period ) with( this ) {
     58void ?{}( alarm_node_t & this, processor   * proc, Time alarm, Duration period ) with( this ) {
    5659        this.proc = proc;
    5760        this.alarm = alarm;
    5861        this.period = period;
     62        next = 0;
    5963        set = false;
    60         type = Kernel;
    61 }
    62 void ?{}( alarm_node_t & this, Alarm_Callback callback, Time alarm, Duration period ) with( this ) {
    63         this.alarm = alarm;
    64         this.period = period;
    65         this.callback = callback;
    66         set = false;
    67         type = Callback;
     64        kernel_alarm = true;
    6865}
    6966
     
    7471}
    7572
    76 void insert( alarm_list_t * this, alarm_node_t * n ) {
    77         alarm_node_t * it = & (*this)`first;
    78         while( it && (n->alarm > it->alarm) ) {
    79                 it = & (*it)`next;
    80         }
    81         if ( it ) {
    82                 insert_before( *it, *n );
    83         } else {
    84                 insert_last(*this, *n);
     73#if !defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__))
     74bool validate( alarm_list_t * this ) {
     75        alarm_node_t ** it = &this->head;
     76        while( (*it) ) {
     77                it = &(*it)->next;
    8578        }
    8679
    87         verify( validate( *this ) );
     80        return it == this->tail;
     81}
     82#endif
     83
     84static inline void insert_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t p ) {
     85        verify( !n->next );
     86        if( p == this->tail ) {
     87                this->tail = &n->next;
     88        }
     89        else {
     90                n->next = *p;
     91        }
     92        *p = n;
     93
     94        verify( validate( this ) );
     95}
     96
     97void insert( alarm_list_t * this, alarm_node_t * n ) {
     98        alarm_node_t ** it = &this->head;
     99        while( (*it) && (n->alarm > (*it)->alarm) ) {
     100                it = &(*it)->next;
     101        }
     102
     103        insert_at( this, n, it );
     104
     105        verify( validate( this ) );
    88106}
    89107
    90108alarm_node_t * pop( alarm_list_t * this ) {
    91         verify( validate( *this ) );
    92         alarm_node_t * head = & (*this)`first;
     109        alarm_node_t * head = this->head;
    93110        if( head ) {
    94                 remove(*head);
     111                this->head = head->next;
     112                if( !head->next ) {
     113                        this->tail = &this->head;
     114                }
     115                head->next = 0p;
    95116        }
    96         verify( validate( *this ) );
     117        verify( validate( this ) );
    97118        return head;
    98119}
    99120
     121static inline void remove_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t it ) {
     122        verify( it );
     123        verify( (*it) == n );
     124
     125        (*it) = n->next;
     126        if( !n-> next ) {
     127                this->tail = it;
     128        }
     129        n->next = 0p;
     130
     131        verify( validate( this ) );
     132}
     133
     134static inline void remove( alarm_list_t * this, alarm_node_t * n ) {
     135        alarm_node_t ** it = &this->head;
     136        while( (*it) && (*it) != n ) {
     137                it = &(*it)->next;
     138        }
     139
     140        verify( validate( this ) );
     141
     142        if( *it ) { remove_at( this, n, it ); }
     143
     144        verify( validate( this ) );
     145}
     146
    100147void register_self( alarm_node_t * this ) {
    101         alarm_list_t & alarms = event_kernel->alarms;
     148        alarm_list_t * alarms = &event_kernel->alarms;
    102149
    103150        disable_interrupts();
     
    105152        {
    106153                verify( validate( alarms ) );
    107                 bool first = ! & alarms`first;
     154                bool first = !alarms->head;
    108155
    109                 insert( &alarms, this );
     156                insert( alarms, this );
    110157                if( first ) {
    111                         __kernel_set_timer( alarms`first.alarm - __kernel_get_time() );
     158                        __kernel_set_timer( alarms->head->alarm - __kernel_get_time() );
    112159                }
    113160        }
     
    121168        lock( event_kernel->lock __cfaabi_dbg_ctx2 );
    122169        {
    123                 verify( validate( event_kernel->alarms ) );
    124                 remove( *this );
     170                verify( validate( &event_kernel->alarms ) );
     171                remove( &event_kernel->alarms, this );
    125172        }
    126173        unlock( event_kernel->lock );
     
    129176}
    130177
    131 //=============================================================================================
    132 // Utilities
    133 //=============================================================================================
    134 
    135 void sleep( Duration duration ) {
    136         alarm_node_t node = { active_thread(), __kernel_get_time() + duration, 0`s };
    137 
    138         register_self( &node );
    139         park();
    140 
    141         /* paranoid */ verify( !node.set );
    142         /* paranoid */ verify( & node`next == 0p );
    143         /* paranoid */ verify( & node`prev == 0p );
    144 }
    145 
    146178// Local Variables: //
    147179// mode: c //
  • libcfa/src/concurrency/alarm.hfa

    reef8dfb rbdfc032  
    2323#include "time.hfa"
    2424
    25 #include "containers/list.hfa"
    26 
    27 struct $thread;
     25struct thread_desc;
    2826struct processor;
    2927
     
    3937//=============================================================================================
    4038
    41 enum alarm_type{ Kernel = 0, User = 1, Callback = 2 };
    42 
    43 struct alarm_node_t;
    44 
    45 typedef void (*Alarm_Callback)(alarm_node_t & );
    46 
    4739struct alarm_node_t {
    4840        Time alarm;                             // time when alarm goes off
    4941        Duration period;                        // if > 0 => period of alarm
    50 
    51         DLISTED_MGD_IMPL_IN(alarm_node_t)
     42        alarm_node_t * next;            // intrusive link list field
    5243
    5344        union {
    54                 $thread * thrd;                                 // thrd who created event
    55                 processor * proc;                               // proc who created event
    56                 Alarm_Callback callback;                // callback to handle event
     45                thread_desc * thrd;     // thrd who created event
     46                processor * proc;               // proc who created event
    5747        };
    5848
    5949        bool set                :1;             // whether or not the alarm has be registered
    60         enum alarm_type type;           // true if this is not a user defined alarm
     50        bool kernel_alarm       :1;             // true if this is not a user defined alarm
    6151};
    62 DLISTED_MGD_IMPL_OUT(alarm_node_t)
    6352
    64 void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period );
     53typedef alarm_node_t ** __alarm_it_t;
     54
     55void ?{}( alarm_node_t & this, thread_desc * thrd, Time alarm, Duration period );
    6556void ?{}( alarm_node_t & this, processor   * proc, Time alarm, Duration period );
    66 void ?{}( alarm_node_t & this, Alarm_Callback callback, Time alarm, Duration period );
    6757void ^?{}( alarm_node_t & this );
    6858
    69 typedef dlist(alarm_node_t, alarm_node_t) alarm_list_t;
     59struct alarm_list_t {
     60        alarm_node_t * head;
     61        __alarm_it_t tail;
     62};
     63
     64static inline void ?{}( alarm_list_t & this ) with( this ) {
     65        head = 0;
     66        tail = &head;
     67}
    7068
    7169void insert( alarm_list_t * this, alarm_node_t * n );
  • libcfa/src/concurrency/coroutine.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec 15 12:06:04 2020
    13 // Update Count     : 23
     12// Last Modified On : Thu Dec  5 14:37:29 2019
     13// Update Count     : 15
    1414//
    1515
     
    1818#include "coroutine.hfa"
    1919
     20extern "C" {
    2021#include <stddef.h>
    2122#include <malloc.h>
     
    2324#include <string.h>
    2425#include <unistd.h>
    25 #include <sys/mman.h>                                                                   // mprotect
     26// use this define to make unwind.h play nice, definetely a hack
     27#define HIDE_EXPORTS
    2628#include <unwind.h>
     29#undef HIDE_EXPORTS
     30#include <sys/mman.h>
     31}
    2732
    2833#include "kernel_private.hfa"
    29 #include "exception.hfa"
    30 #include "math.hfa"
    31 
    32 #define CFA_COROUTINE_USE_MMAP 0
    3334
    3435#define __CFA_INVOKE_PRIVATE__
     
    3637
    3738extern "C" {
    38         void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct $coroutine *) __attribute__ ((__noreturn__));
     39        void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
    3940        static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__));
    4041        static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) {
     
    4647
    4748//-----------------------------------------------------------------------------
    48 FORALL_DATA_INSTANCE(CoroutineCancelled, (dtype coroutine_t), (coroutine_t))
    49 
    50 forall(dtype T)
    51 void mark_exception(CoroutineCancelled(T) *) {}
    52 
    53 forall(dtype T)
    54 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {
    55         dst->virtual_table = src->virtual_table;
    56         dst->the_coroutine = src->the_coroutine;
    57         dst->the_exception = src->the_exception;
    58 }
    59 
    60 forall(dtype T)
    61 const char * msg(CoroutineCancelled(T) *) {
    62         return "CoroutineCancelled(...)";
    63 }
    64 
    65 // This code should not be inlined. It is the error path on resume.
    66 forall(dtype T | is_coroutine(T))
    67 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ) {
    68         verify( desc->cancellation );
    69         desc->state = Cancelled;
    70         exception_t * except = __cfaehm_cancellation_exception( desc->cancellation );
    71 
    72         // TODO: Remove explitate vtable set once trac#186 is fixed.
    73         CoroutineCancelled(T) except;
    74         except.virtual_table = &get_exception_vtable(&except);
    75         except.the_coroutine = &cor;
    76         except.the_exception = except;
    77         throwResume except;
    78 
    79         except->virtual_table->free( except );
    80         free( desc->cancellation );
    81         desc->cancellation = 0p;
    82 }
    83 
    84 //-----------------------------------------------------------------------------
    8549// Global state variables
    8650
    8751// minimum feasible stack size in bytes
    88 static const size_t MinStackSize = 1000;
     52#define MinStackSize 1000
    8953extern size_t __page_size;                              // architecture pagesize HACK, should go in proper runtime singleton
    90 extern int __map_prot;
    9154
    9255void __stack_prepare( __stack_info_t * this, size_t create_size );
    93 void __stack_clean  ( __stack_info_t * this );
    9456
    9557//-----------------------------------------------------------------------------
     
    11274        bool userStack = ((intptr_t)this.storage & 0x1) != 0;
    11375        if ( ! userStack && this.storage ) {
    114                 __stack_clean( &this );
    115         }
    116 }
    117 
    118 void ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize ) with( this ) {
     76                __attribute__((may_alias)) intptr_t * istorage = (intptr_t *)&this.storage;
     77                *istorage &= (intptr_t)-1;
     78
     79                void * storage = this.storage->limit;
     80                __cfaabi_dbg_debug_do(
     81                        storage = (char*)(storage) - __page_size;
     82                        if ( mprotect( storage, __page_size, PROT_READ | PROT_WRITE ) == -1 ) {
     83                                abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) );
     84                        }
     85                );
     86                __cfaabi_dbg_print_safe("Kernel : Deleting stack %p\n", storage);
     87                free( storage );
     88        }
     89}
     90
     91void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize ) with( this ) {
    11992        (this.context){0p, 0p};
    12093        (this.stack){storage, storageSize};
     
    12699}
    127100
    128 void ^?{}($coroutine& this) {
     101void ^?{}(coroutine_desc& this) {
    129102        if(this.state != Halted && this.state != Start && this.state != Primed) {
    130                 $coroutine * src = active_coroutine();
    131                 $coroutine * dst = &this;
     103                coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     104                coroutine_desc * dst = &this;
    132105
    133106                struct _Unwind_Exception storage;
     
    142115                }
    143116
    144                 $ctx_switch( src, dst );
     117                CoroutineCtxSwitch( src, dst );
    145118        }
    146119}
     
    150123forall(dtype T | is_coroutine(T))
    151124void prime(T& cor) {
    152         $coroutine* this = get_coroutine(cor);
     125        coroutine_desc* this = get_coroutine(cor);
    153126        assert(this->state == Start);
    154127
     
    161134        assert(__page_size != 0l);
    162135        size_t size = libCeiling( storageSize, 16 ) + stack_data_size;
    163         size = ceiling(size, __page_size);
    164136
    165137        // If we are running debug, we also need to allocate a guardpage to catch stack overflows.
    166138        void * storage;
    167         #if CFA_COROUTINE_USE_MMAP
    168                 storage = mmap(0p, size + __page_size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
    169                 if(storage == ((void*)-1)) {
    170                         abort( "coroutine stack creation : internal error, mmap failure, error(%d) %s.", errno, strerror( errno ) );
     139        __cfaabi_dbg_debug_do(
     140                storage = memalign( __page_size, size + __page_size );
     141        );
     142        __cfaabi_dbg_no_debug_do(
     143                storage = (void*)malloc(size);
     144        );
     145
     146        __cfaabi_dbg_print_safe("Kernel : Created stack %p of size %zu\n", storage, size);
     147        __cfaabi_dbg_debug_do(
     148                if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) {
     149                        abort( "__stack_alloc : internal error, mprotect failure, error(%d) %s.", (int)errno, strerror( (int)errno ) );
    171150                }
    172                 if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) {
    173                         abort( "coroutine stack creation : internal error, mprotect failure, error(%d) %s.", errno, strerror( errno ) );
    174                 } // if
    175151                storage = (void *)(((intptr_t)storage) + __page_size);
    176         #else
    177                 __cfaabi_dbg_debug_do(
    178                         storage = memalign( __page_size, size + __page_size );
    179                 );
    180                 __cfaabi_dbg_no_debug_do(
    181                         storage = (void*)malloc(size);
    182                 );
    183 
    184                 __cfaabi_dbg_debug_do(
    185                         if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) {
    186                                 abort( "__stack_alloc : internal error, mprotect failure, error(%d) %s.", (int)errno, strerror( (int)errno ) );
    187                         }
    188                         storage = (void *)(((intptr_t)storage) + __page_size);
    189                 );
    190         #endif
    191         __cfaabi_dbg_print_safe("Kernel : Created stack %p of size %zu\n", storage, size);
     152        );
    192153
    193154        verify( ((intptr_t)storage & (libAlign() - 1)) == 0ul );
    194155        return [storage, size];
    195 }
    196 
    197 void __stack_clean  ( __stack_info_t * this ) {
    198         size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t);
    199         void * storage = this->storage->limit;
    200 
    201         #if CFA_COROUTINE_USE_MMAP
    202                 storage = (void *)(((intptr_t)storage) - __page_size);
    203                 if(munmap(storage, size + __page_size) == -1) {
    204                         abort( "coroutine stack destruction : internal error, munmap failure, error(%d) %s.", errno, strerror( errno ) );
    205                 }
    206         #else
    207                 __cfaabi_dbg_debug_do(
    208                         storage = (char*)(storage) - __page_size;
    209                         if ( mprotect( storage, __page_size, __map_prot ) == -1 ) {
    210                                 abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) );
    211                         }
    212                 );
    213 
    214                 free( storage );
    215         #endif
    216         __cfaabi_dbg_print_safe("Kernel : Deleting stack %p\n", storage);
    217156}
    218157
     
    236175                size = libFloor(create_size - stack_data_size - diff, libAlign());
    237176        } // if
    238         assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %zd bytes for a stack.", size, MinStackSize );
    239 
    240         this->storage = (__stack_t *)((intptr_t)storage + size - sizeof(__stack_t));
     177        assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", size, MinStackSize );
     178
     179        this->storage = (__stack_t *)((intptr_t)storage + size);
    241180        this->storage->limit = storage;
    242         this->storage->base  = (void*)((intptr_t)storage + size - sizeof(__stack_t));
    243         this->storage->exception_context.top_resume = 0p;
    244         this->storage->exception_context.current_exception = 0p;
     181        this->storage->base  = (void*)((intptr_t)storage + size);
    245182        __attribute__((may_alias)) intptr_t * istorage = (intptr_t*)&this->storage;
    246183        *istorage |= userStack ? 0x1 : 0x0;
     
    250187// is not inline (We can't inline Cforall in C)
    251188extern "C" {
    252         void __cfactx_cor_leave( struct $coroutine * src ) {
    253                 $coroutine * starter = src->cancellation != 0 ? src->last : src->starter;
     189        void __leave_coroutine( struct coroutine_desc * src ) {
     190                coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter;
    254191
    255192                src->state = Halted;
     
    264201                        src->name, src, starter->name, starter );
    265202
    266                 $ctx_switch( src, starter );
    267         }
    268 
    269         struct $coroutine * __cfactx_cor_finish(void) {
    270                 struct $coroutine * cor = active_coroutine();
     203                CoroutineCtxSwitch( src, starter );
     204        }
     205
     206        struct coroutine_desc * __finish_coroutine(void) {
     207                struct coroutine_desc * cor = kernelTLS.this_thread->curr_cor;
    271208
    272209                if(cor->state == Primed) {
    273                         __cfactx_suspend();
     210                        suspend();
    274211                }
    275212
  • libcfa/src/concurrency/coroutine.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 12:29:26 2020
    13 // Update Count     : 11
     12// Last Modified On : Tue Dec  3 22:47:58 2019
     13// Update Count     : 10
    1414//
    1515
     
    1818#include <assert.h>
    1919#include "invoke.h"
    20 #include "../exception.hfa"
    21 
    22 //-----------------------------------------------------------------------------
    23 // Exception thrown from resume when a coroutine stack is cancelled.
    24 FORALL_DATA_EXCEPTION(CoroutineCancelled, (dtype coroutine_t), (coroutine_t)) (
    25         coroutine_t * the_coroutine;
    26         exception_t * the_exception;
    27 );
    28 
    29 forall(dtype T)
    30 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src);
    31 
    32 forall(dtype T)
    33 const char * msg(CoroutineCancelled(T) *);
    3420
    3521//-----------------------------------------------------------------------------
     
    3723// Anything that implements this trait can be resumed.
    3824// Anything that is resumed is a coroutine.
    39 trait is_coroutine(dtype T | IS_RESUMPTION_EXCEPTION(CoroutineCancelled, (T))) {
    40         void main(T & this);
    41         $coroutine * get_coroutine(T & this);
     25trait is_coroutine(dtype T) {
     26      void main(T & this);
     27      coroutine_desc * get_coroutine(T & this);
    4228};
    4329
    44 #define DECL_COROUTINE(X) static inline $coroutine* get_coroutine(X& this) { return &this.__cor; } void main(X& this)
     30#define DECL_COROUTINE(X) static inline coroutine_desc* get_coroutine(X& this) { return &this.__cor; } void main(X& this)
    4531
    4632//-----------------------------------------------------------------------------
     
    4935// void ^?{}( coStack_t & this );
    5036
    51 void  ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize );
    52 void ^?{}( $coroutine & this );
     37void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize );
     38void ^?{}( coroutine_desc & this );
    5339
    54 static inline void ?{}( $coroutine & this)                                       { this{ "Anonymous Coroutine", 0p, 0 }; }
    55 static inline void ?{}( $coroutine & this, size_t stackSize)                     { this{ "Anonymous Coroutine", 0p, stackSize }; }
    56 static inline void ?{}( $coroutine & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
    57 static inline void ?{}( $coroutine & this, const char name[])                    { this{ name, 0p, 0 }; }
    58 static inline void ?{}( $coroutine & this, const char name[], size_t stackSize ) { this{ name, 0p, stackSize }; }
     40static inline void ?{}( coroutine_desc & this)                                       { this{ "Anonymous Coroutine", 0p, 0 }; }
     41static inline void ?{}( coroutine_desc & this, size_t stackSize)                     { this{ "Anonymous Coroutine", 0p, stackSize }; }
     42static inline void ?{}( coroutine_desc & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
     43static inline void ?{}( coroutine_desc & this, const char * name)                    { this{ name, 0p, 0 }; }
     44static inline void ?{}( coroutine_desc & this, const char * name, size_t stackSize ) { this{ name, 0p, stackSize }; }
    5945
    6046//-----------------------------------------------------------------------------
    6147// Public coroutine API
     48static inline void suspend(void);
     49
     50forall(dtype T | is_coroutine(T))
     51static inline T & resume(T & cor);
     52
    6253forall(dtype T | is_coroutine(T))
    6354void prime(T & cor);
    6455
    65 static inline struct $coroutine * active_coroutine() { return active_thread()->curr_cor; }
     56static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; }
    6657
    6758//-----------------------------------------------------------------------------
     
    7061// Start coroutine routines
    7162extern "C" {
    72         void __cfactx_invoke_coroutine(void (*main)(void *), void * this);
     63        void CtxInvokeCoroutine(void (*main)(void *), void * this);
    7364
    7465        forall(dtype T)
    75         void __cfactx_start(void (*main)(T &), struct $coroutine * cor, T & this, void (*invoke)(void (*main)(void *), void *));
     66        void CtxStart(void (*main)(T &), struct coroutine_desc * cor, T & this, void (*invoke)(void (*main)(void *), void *));
    7667
    77         extern void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine *) __attribute__ ((__noreturn__));
     68        extern void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
    7869
    79         extern void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("__cfactx_switch");
     70        extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
    8071}
    8172
    8273// Private wrappers for context switch and stack creation
    8374// Wrapper for co
    84 static inline void $ctx_switch( $coroutine * src, $coroutine * dst ) __attribute__((nonnull (1, 2))) {
     75static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
    8576        // set state of current coroutine to inactive
    86         src->state = src->state == Halted ? Halted : Blocked;
     77        src->state = src->state == Halted ? Halted : Inactive;
    8778
    8879        // set new coroutine that task is executing
    89         active_thread()->curr_cor = dst;
     80        TL_GET( this_thread )->curr_cor = dst;
    9081
    9182        // context switch to specified coroutine
    9283        verify( dst->context.SP );
    93         __cfactx_switch( &src->context, &dst->context );
    94         // when __cfactx_switch returns we are back in the src coroutine
     84        CtxSwitch( &src->context, &dst->context );
     85        // when CtxSwitch returns we are back in the src coroutine
    9586
    9687        // set state of new coroutine to active
     
    9889
    9990        if( unlikely(src->cancellation != 0p) ) {
    100                 __cfactx_coroutine_unwind(src->cancellation, src);
     91                _CtxCoroutine_Unwind(src->cancellation, src);
    10192        }
    10293}
    10394
    104 extern void __stack_prepare( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
    105 extern void __stack_clean  ( __stack_info_t * this );
    106 
     95extern void __stack_prepare   ( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
    10796
    10897// Suspend implementation inlined for performance
    109 extern "C" {
    110         static inline void __cfactx_suspend(void) {
    111                 // optimization : read TLS once and reuse it
    112                 // Safety note: this is preemption safe since if
    113                 // preemption occurs after this line, the pointer
    114                 // will also migrate which means this value will
    115                 // stay in syn with the TLS
    116                 $coroutine * src = active_coroutine();
     98static inline void suspend(void) {
     99        // optimization : read TLS once and reuse it
     100        // Safety note: this is preemption safe since if
     101        // preemption occurs after this line, the pointer
     102        // will also migrate which means this value will
     103        // stay in syn with the TLS
     104        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    117105
    118                 assertf( src->last != 0,
    119                         "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
    120                         "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
    121                         src->name, src );
    122                 assertf( src->last->state != Halted,
    123                         "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
    124                         "Possible cause is terminated coroutine's main routine has already returned.",
    125                         src->name, src, src->last->name, src->last );
     106        assertf( src->last != 0,
     107                "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
     108                "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
     109                src->name, src );
     110        assertf( src->last->state != Halted,
     111                "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
     112                "Possible cause is terminated coroutine's main routine has already returned.",
     113                src->name, src, src->last->name, src->last );
    126114
    127                 $ctx_switch( src, src->last );
    128         }
     115        CoroutineCtxSwitch( src, src->last );
    129116}
    130 
    131 forall(dtype T | is_coroutine(T))
    132 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc );
    133117
    134118// Resume implementation inlined for performance
     
    140124        // will also migrate which means this value will
    141125        // stay in syn with the TLS
    142         $coroutine * src = active_coroutine();
    143         $coroutine * dst = get_coroutine(cor);
     126        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     127        coroutine_desc * dst = get_coroutine(cor);
    144128
    145129        if( unlikely(dst->context.SP == 0p) ) {
     130                TL_GET( this_thread )->curr_cor = dst;
    146131                __stack_prepare(&dst->stack, 65000);
    147                 __cfactx_start(main, dst, cor, __cfactx_invoke_coroutine);
     132                CtxStart(main, dst, cor, CtxInvokeCoroutine);
     133                TL_GET( this_thread )->curr_cor = src;
    148134        }
    149135
     
    161147
    162148        // always done for performance testing
    163         $ctx_switch( src, dst );
    164         if ( unlikely(dst->cancellation) ) {
    165                 __cfaehm_cancelled_coroutine( cor, dst );
    166         }
     149        CoroutineCtxSwitch( src, dst );
    167150
    168151        return cor;
    169152}
    170153
    171 static inline void resume( $coroutine * dst ) __attribute__((nonnull (1))) {
     154static inline void resume(coroutine_desc * dst) {
    172155        // optimization : read TLS once and reuse it
    173156        // Safety note: this is preemption safe since if
     
    175158        // will also migrate which means this value will
    176159        // stay in syn with the TLS
    177         $coroutine * src = active_coroutine();
     160        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    178161
    179162        // not resuming self ?
     
    189172
    190173        // always done for performance testing
    191         $ctx_switch( src, dst );
     174        CoroutineCtxSwitch( src, dst );
    192175}
    193176
  • libcfa/src/concurrency/invoke.c

    reef8dfb rbdfc032  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Oct 24 14:35:28 2020
    13 // Update Count     : 32
     12// Last Modified On : Fri Feb  9 16:37:42 2018
     13// Update Count     : 5
    1414//
    1515
     
    2929// Called from the kernel when starting a coroutine or task so must switch back to user mode.
    3030
    31 extern struct $coroutine * __cfactx_cor_finish(void);
    32 extern void __cfactx_cor_leave ( struct $coroutine * );
    33 extern void __cfactx_thrd_leave();
    34 
     31extern void __leave_coroutine ( struct coroutine_desc * );
     32extern struct coroutine_desc * __finish_coroutine(void);
     33extern void __leave_thread_monitor();
    3534extern void disable_interrupts() OPTIONAL_THREAD;
    3635extern void enable_interrupts( __cfaabi_dbg_ctx_param );
    3736
    38 void __cfactx_invoke_coroutine(
     37void CtxInvokeCoroutine(
    3938        void (*main)(void *),
    4039        void *this
    4140) {
    4241        // Finish setting up the coroutine by setting its state
    43         struct $coroutine * cor = __cfactx_cor_finish();
     42        struct coroutine_desc * cor = __finish_coroutine();
    4443
    4544        // Call the main of the coroutine
     
    4746
    4847        //Final suspend, should never return
    49         __cfactx_cor_leave( cor );
     48        __leave_coroutine( cor );
    5049        __cabi_abort( "Resumed dead coroutine" );
    5150}
    5251
    53 static _Unwind_Reason_Code __cfactx_coroutine_unwindstop(
     52static _Unwind_Reason_Code _CtxCoroutine_UnwindStop(
    5453        __attribute((__unused__)) int version,
    5554        _Unwind_Action actions,
     
    6261                // We finished unwinding the coroutine,
    6362                // leave it
    64                 __cfactx_cor_leave( param );
     63                __leave_coroutine( param );
    6564                __cabi_abort( "Resumed dead coroutine" );
    6665        }
     
    7069}
    7170
    72 void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine * cor) __attribute__ ((__noreturn__));
    73 void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine * cor) {
    74         _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, __cfactx_coroutine_unwindstop, cor );
     71void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) __attribute__ ((__noreturn__));
     72void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) {
     73        _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, cor );
    7574        printf("UNWIND ERROR %d after force unwind\n", ret);
    7675        abort();
    7776}
    7877
    79 void __cfactx_invoke_thread(
     78void CtxInvokeThread(
    8079        void (*main)(void *),
    8180        void *this
     
    9493        // The order of these 4 operations is very important
    9594        //Final suspend, should never return
    96         __cfactx_thrd_leave();
     95        __leave_thread_monitor();
    9796        __cabi_abort( "Resumed dead thread" );
    9897}
    9998
    100 void __cfactx_start(
     99void CtxStart(
    101100        void (*main)(void *),
    102         struct $coroutine * cor,
     101        struct coroutine_desc * cor,
    103102        void *this,
    104103        void (*invoke)(void *)
     
    109108
    110109        struct FakeStack {
    111             void *fixedRegisters[3];                                            // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant)
    112             void *rturn;                                                                        // where to go on return from uSwitch
    113             void *dummyReturn;                                                          // fake return compiler would have pushed on call to uInvoke
    114             void *argument[3];                                                          // for 16-byte ABI, 16-byte alignment starts here
    115             void *padding;                                                                      // padding to force 16-byte alignment, as "base" is 16-byte aligned
     110            void *fixedRegisters[3];              // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant)
     111            void *rturn;                          // where to go on return from uSwitch
     112            void *dummyReturn;                    // fake return compiler would have pushed on call to uInvoke
     113            void *argument[3];                    // for 16-byte ABI, 16-byte alignment starts here
     114            void *padding;                        // padding to force 16-byte alignment, as "base" is 16-byte aligned
    116115        };
    117116
     
    122121
    123122        fs->dummyReturn = NULL;
    124         fs->argument[0] = main;                                                         // argument to invoke
    125         fs->argument[1] = this;                                                         // argument to invoke
     123        fs->argument[0] = main;     // argument to invoke
     124        fs->argument[1] = this;     // argument to invoke
    126125        fs->rturn = invoke;
    127126
     
    129128
    130129        struct FakeStack {
    131                 void *fixedRegisters[5];                                                // fixed registers rbx, r12, r13, r14, r15
    132                 void *rturn;                                                                    // where to go on return from uSwitch
    133                 void *dummyReturn;                                                              // NULL return address to provide proper alignment
     130                void *fixedRegisters[5];            // fixed registers rbx, r12, r13, r14, r15
     131                void *rturn;                        // where to go on return from uSwitch
     132                void *dummyReturn;                  // NULL return address to provide proper alignment
    134133        };
    135134
    136135        cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );
    137         cor->context.FP = NULL;                                                         // terminate stack with NULL fp
     136        cor->context.FP = NULL;         // terminate stack with NULL fp
    138137
    139138        struct FakeStack *fs = (struct FakeStack *)cor->context.SP;
    140139
    141140        fs->dummyReturn = NULL;
    142         fs->rturn = __cfactx_invoke_stub;
    143         fs->fixedRegisters[0] = main;                                           // argument to invoke
    144         fs->fixedRegisters[1] = this;                                           // argument to invoke
     141        fs->rturn = CtxInvokeStub;
     142        fs->fixedRegisters[0] = main;
     143        fs->fixedRegisters[1] = this;
    145144        fs->fixedRegisters[2] = invoke;
    146145
    147 #elif defined( __ARM_ARCH_32 )
    148 #error ARM needs to be upgrade to use two parameters like X86/X64 (A.K.A. : I broke this and do not know how to fix it)
    149         // More details about the error:
    150         // To avoid the thunk problem, I changed the invoke routine to pass the main explicitly
    151         // instead of relying on an assertion. This effectively hoists any required thunk one level
    152         // which was enough to get to global scope in most cases.
    153         // This means that __cfactx_invoke_... now takes two parameters and the FakeStack needs
    154         // to be adjusted as a consequence of that.
    155         // I don't know how to do that for ARM, hence the #error
    156 
     146#elif defined( __ARM_ARCH )
     147#error ARM needs to be upgrade to use to parameters like X86/X64 (A.K.A. : I broke this and do not know how to fix it)
    157148        struct FakeStack {
    158                 float fpRegs[16];                                                               // floating point registers
    159                 void * intRegs[9];                                                              // integer/pointer registers
    160                 void * arg[2];                                                                  // placeholder for this pointer
     149                float fpRegs[16];                       // floating point registers
     150                void *intRegs[9];                       // integer/pointer registers
     151                void *arg[2];                           // placeholder for this pointer
    161152        };
    162153
     
    166157        struct FakeStack *fs = (struct FakeStack *)cor->context.SP;
    167158
    168         fs->intRegs[8] = __cfactx_invoke_stub;
     159        fs->intRegs[8] = CtxInvokeStub;
    169160        fs->arg[0] = this;
    170161        fs->arg[1] = invoke;
    171162
    172 #elif defined( __ARM_ARCH )
    173         struct FakeStack {
    174                 void * intRegs[12];                                                             // x19-x30 integer registers
    175                 double fpRegs[8];                                                               // v8-v15 floating point
    176         };
    177 
    178         cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );
    179         cor->context.FP = NULL;
    180 
    181         struct FakeStack *fs = (struct FakeStack *)cor->context.SP;
    182 
    183         fs->intRegs[0] = main;                                                          // argument to invoke x19 => x0
    184         fs->intRegs[1] = this;                                                          // argument to invoke x20 => x1
    185         fs->intRegs[2] = invoke;
    186         fs->intRegs[11] = __cfactx_invoke_stub;                         // link register x30 => ret moves to pc
    187163#else
    188164        #error uknown hardware architecture
  • libcfa/src/concurrency/invoke.h

    reef8dfb rbdfc032  
    1717#include "bits/defs.hfa"
    1818#include "bits/locks.hfa"
    19 #include "kernel/fwd.hfa"
    2019
    2120#ifdef __cforall
     
    2726#define _INVOKE_H_
    2827
    29         struct __cfaehm_try_resume_node;
    30         struct __cfaehm_base_exception_t;
    31         struct exception_context_t {
    32                 struct __cfaehm_try_resume_node * top_resume;
    33                 struct __cfaehm_base_exception_t * current_exception;
    34         };
     28#ifdef __ARM_ARCH
     29        // function prototypes are only really used by these macros on ARM
     30        void disable_global_interrupts();
     31        void enable_global_interrupts();
     32
     33        #define TL_GET( member ) ( { __typeof__( kernelTLS.member ) target; \
     34                disable_global_interrupts(); \
     35                target = kernelTLS.member; \
     36                enable_global_interrupts(); \
     37                target; } )
     38        #define TL_SET( member, value ) disable_global_interrupts(); \
     39                kernelTLS.member = value; \
     40                enable_global_interrupts();
     41#else
     42        #define TL_GET( member ) kernelTLS.member
     43        #define TL_SET( member, value ) kernelTLS.member = value;
     44#endif
     45
     46        #ifdef __cforall
     47        extern "Cforall" {
     48                extern __attribute__((aligned(128))) thread_local struct KernelThreadData {
     49                        struct thread_desc    * volatile this_thread;
     50                        struct processor      * volatile this_processor;
     51
     52                        struct {
     53                                volatile unsigned short disable_count;
     54                                volatile bool enabled;
     55                                volatile bool in_progress;
     56                        } preemption_state;
     57
     58                        uint32_t rand_seed;
     59                } kernelTLS __attribute__ ((tls_model ( "initial-exec" )));
     60        }
     61        #endif
    3562
    3663        struct __stack_context_t {
     
    5885                // base of stack
    5986                void * base;
    60 
    61                 // Information for exception handling.
    62                 struct exception_context_t exception_context;
    6387        };
    6488
     
    6892        };
    6993
    70         enum __Coroutine_State { Halted, Start, Primed, Blocked, Ready, Active, Cancelled, Halting };
    71 
    72         struct $coroutine {
    73                 // context that is switch during a __cfactx_switch
     94        enum coroutine_state { Halted, Start, Inactive, Active, Primed };
     95
     96        struct coroutine_desc {
     97                // context that is switch during a CtxSwitch
    7498                struct __stack_context_t context;
    7599
     
    81105
    82106                // current execution status for coroutine
    83                 enum __Coroutine_State state;
     107                enum coroutine_state state;
    84108
    85109                // first coroutine to resume this one
    86                 struct $coroutine * starter;
     110                struct coroutine_desc * starter;
    87111
    88112                // last coroutine to resume this one
    89                 struct $coroutine * last;
     113                struct coroutine_desc * last;
    90114
    91115                // If non-null stack must be unwound with this exception
     
    93117
    94118        };
    95         // Wrapper for gdb
    96         struct cfathread_coroutine_t { struct $coroutine debug; };
    97 
    98         static inline struct __stack_t * __get_stack( struct $coroutine * cor ) {
    99                 return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2));
    100         }
    101119
    102120        // struct which calls the monitor is accepting
     
    109127        };
    110128
    111         struct $monitor {
     129        struct monitor_desc {
    112130                // spinlock to protect internal data
    113131                struct __spinlock_t lock;
    114132
    115133                // current owner of the monitor
    116                 struct $thread * owner;
     134                struct thread_desc * owner;
    117135
    118136                // queue of threads that are blocked waiting for the monitor
    119                 __queue_t(struct $thread) entry_queue;
     137                __queue_t(struct thread_desc) entry_queue;
    120138
    121139                // stack of conditions to run next once we exit the monitor
     
    131149                struct __condition_node_t * dtor_node;
    132150        };
    133         // Wrapper for gdb
    134         struct cfathread_monitor_t { struct $monitor debug; };
    135151
    136152        struct __monitor_group_t {
    137153                // currently held monitors
    138                 __cfa_anonymous_object( __small_array_t($monitor*) );
     154                __cfa_anonymous_object( __small_array_t(monitor_desc*) );
    139155
    140156                // last function that acquired monitors
     
    142158        };
    143159
    144         // Link lists fields
    145         // instrusive link field for threads
    146         struct __thread_desc_link {
    147                 struct $thread * next;
    148                 struct $thread * prev;
    149                 volatile unsigned long long ts;
    150                 int preferred;
    151         };
    152 
    153         struct $thread {
     160        struct thread_desc {
    154161                // Core threading fields
    155                 // context that is switch during a __cfactx_switch
     162                // context that is switch during a CtxSwitch
    156163                struct __stack_context_t context;
    157164
    158165                // current execution status for coroutine
    159                 // Possible values are:
    160                 //    - TICKET_BLOCKED (-1) thread is blocked
    161                 //    - TICKET_RUNNING ( 0) thread is running
    162                 //    - TICKET_UNBLOCK ( 1) thread should ignore next block
    163                 volatile int ticket;
    164                 enum __Coroutine_State state:8;
    165                 enum __Preemption_Reason preempted:8;
     166                enum coroutine_state state;
    166167
    167168                //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it
     169
     170                // coroutine body used to store context
     171                struct coroutine_desc  self_cor;
     172
     173                // current active context
     174                struct coroutine_desc * curr_cor;
     175
     176                // monitor body used for mutual exclusion
     177                struct monitor_desc    self_mon;
     178
     179                // pointer to monitor with sufficient lifetime for current monitors
     180                struct monitor_desc *  self_mon_p;
    168181
    169182                // pointer to the cluster on which the thread is running
    170183                struct cluster * curr_cluster;
    171184
     185                // monitors currently held by this thread
     186                struct __monitor_group_t monitors;
     187
    172188                // Link lists fields
    173189                // instrusive link field for threads
    174                 struct __thread_desc_link link;
    175 
    176                 // coroutine body used to store context
    177                 struct $coroutine  self_cor;
    178 
    179                 // current active context
    180                 struct $coroutine * curr_cor;
    181 
    182                 // monitor body used for mutual exclusion
    183                 struct $monitor    self_mon;
    184 
    185                 // pointer to monitor with sufficient lifetime for current monitors
    186                 struct $monitor *  self_mon_p;
    187 
    188                 // monitors currently held by this thread
    189                 struct __monitor_group_t monitors;
    190 
    191                 // used to put threads on user data structures
     190                struct thread_desc * next;
     191
    192192                struct {
    193                         struct $thread * next;
    194                         struct $thread * back;
    195                 } seqable;
    196 
    197                 struct {
    198                         struct $thread * next;
    199                         struct $thread * prev;
     193                        struct thread_desc * next;
     194                        struct thread_desc * prev;
    200195                } node;
    201 
    202                 #if defined( __CFA_WITH_VERIFY__ )
    203                         void * canary;
    204                 #endif
    205         };
    206         // Wrapper for gdb
    207         struct cfathread_thread_t { struct $thread debug; };
    208 
    209         #ifdef __CFA_DEBUG__
    210                 void __cfaabi_dbg_record_thrd($thread & this, bool park, const char prev_name[]);
    211         #else
    212                 #define __cfaabi_dbg_record_thrd(x, y, z)
    213         #endif
     196        };
    214197
    215198        #ifdef __cforall
    216199        extern "Cforall" {
    217 
    218                 static inline $thread *& get_next( $thread & this ) __attribute__((const)) {
    219                         return this.link.next;
    220                 }
    221 
    222                 static inline [$thread *&, $thread *& ] __get( $thread & this ) __attribute__((const)) {
     200                static inline thread_desc *& get_next( thread_desc & this ) {
     201                        return this.next;
     202                }
     203
     204                static inline [thread_desc *&, thread_desc *& ] __get( thread_desc & this ) {
    223205                        return this.node.[next, prev];
    224                 }
    225 
    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;
    236206                }
    237207
     
    242212                }
    243213
    244                 static inline void ?{}(__monitor_group_t & this, struct $monitor ** data, __lock_size_t size, fptr_t func) {
     214                static inline void ?{}(__monitor_group_t & this, struct monitor_desc ** data, __lock_size_t size, fptr_t func) {
    245215                        (this.data){data};
    246216                        (this.size){size};
     
    248218                }
    249219
    250                 static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) __attribute__((const)) {
     220                static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) {
    251221                        if( (lhs.data != 0) != (rhs.data != 0) ) return false;
    252222                        if( lhs.size != rhs.size ) return false;
     
    282252
    283253        // assembler routines that performs the context switch
    284         extern void __cfactx_invoke_stub( void );
    285         extern void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("__cfactx_switch");
     254        extern void CtxInvokeStub( void );
     255        extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
    286256        // void CtxStore ( void * this ) asm ("CtxStore");
    287257        // void CtxRet   ( void * dst  ) asm ("CtxRet");
  • libcfa/src/concurrency/kernel.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Aug 31 07:08:20 2020
    13 // Update Count     : 71
     12// Last Modified On : Thu Jan 30 22:55:50 2020
     13// Update Count     : 56
    1414//
    1515
    1616#define __cforall_thread__
    17 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
    1817
    1918//C Includes
     19#include <stddef.h>
    2020#include <errno.h>
     21#include <string.h>
     22extern "C" {
    2123#include <stdio.h>
     24#include <fenv.h>
     25#include <sys/resource.h>
    2226#include <signal.h>
    2327#include <unistd.h>
     28#include <limits.h>                                                                             // PTHREAD_STACK_MIN
     29#include <sys/mman.h>                                                                   // mprotect
     30}
    2431
    2532//CFA Includes
     33#include "time.hfa"
    2634#include "kernel_private.hfa"
    2735#include "preemption.hfa"
     36#include "startup.hfa"
    2837
    2938//Private includes
     
    3140#include "invoke.h"
    3241
    33 
    3442//-----------------------------------------------------------------------------
    3543// Some assembly required
    3644#if defined( __i386 )
     45        #define CtxGet( ctx )        \
     46                __asm__ volatile (     \
     47                        "movl %%esp,%0\n"\
     48                        "movl %%ebp,%1\n"\
     49                        : "=rm" (ctx.SP),\
     50                                "=rm" (ctx.FP) \
     51                )
     52
    3753        // mxcr : SSE Status and Control bits (control bits are preserved across function calls)
    3854        // fcw  : X87 FPU control word (preserved across function calls)
     
    5672
    5773#elif defined( __x86_64 )
     74        #define CtxGet( ctx )        \
     75                __asm__ volatile (     \
     76                        "movq %%rsp,%0\n"\
     77                        "movq %%rbp,%1\n"\
     78                        : "=rm" (ctx.SP),\
     79                                "=rm" (ctx.FP) \
     80                )
     81
    5882        #define __x87_store         \
    5983                uint32_t __mxcr;      \
     
    7498                )
    7599
    76 #elif defined( __arm__ )
    77         #define __x87_store
    78         #define __x87_load
    79 
    80 #elif defined( __aarch64__ )
    81         #define __x87_store              \
    82                 uint32_t __fpcntl[2];    \
    83                 __asm__ volatile (    \
    84                         "mrs x9, FPCR\n" \
    85                         "mrs x10, FPSR\n"  \
    86                         "stp x9, x10, %0\n"  \
    87                         : "=m" (__fpcntl) : : "x9", "x10" \
    88                 )
    89 
    90         #define __x87_load         \
    91                 __asm__ volatile (    \
    92                         "ldp x9, x10, %0\n"  \
    93                         "msr FPSR, x10\n"  \
    94                         "msr FPCR, x9\n" \
    95                 : "=m" (__fpcntl) : : "x9", "x10" \
    96                 )
    97 
     100
     101#elif defined( __ARM_ARCH )
     102#define CtxGet( ctx ) __asm__ ( \
     103                "mov %0,%%sp\n"   \
     104                "mov %1,%%r11\n"   \
     105        : "=rm" (ctx.SP), "=rm" (ctx.FP) )
    98106#else
    99         #error unsupported hardware architecture
     107        #error unknown hardware architecture
    100108#endif
    101109
    102 extern $thread * mainThread;
    103 extern processor * mainProcessor;
    104 
    105 //-----------------------------------------------------------------------------
    106 // Kernel Scheduling logic
    107 static $thread * __next_thread(cluster * this);
    108 static $thread * __next_thread_slow(cluster * this);
    109 static void __run_thread(processor * this, $thread * dst);
    110 static void __wake_one(cluster * cltr);
    111 
    112 static void push  (__cluster_idles & idles, processor & proc);
    113 static void remove(__cluster_idles & idles, processor & proc);
    114 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles );
    115 
     110//-----------------------------------------------------------------------------
     111//Start and stop routine for the kernel, declared first to make sure they run first
     112static void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
     113static void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
     114
     115//-----------------------------------------------------------------------------
     116// Kernel storage
     117KERNEL_STORAGE(cluster,         mainCluster);
     118KERNEL_STORAGE(processor,       mainProcessor);
     119KERNEL_STORAGE(thread_desc,     mainThread);
     120KERNEL_STORAGE(__stack_t,       mainThreadCtx);
     121
     122cluster     * mainCluster;
     123processor   * mainProcessor;
     124thread_desc * mainThread;
     125
     126extern "C" {
     127        struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters;
     128}
     129
     130size_t __page_size = 0;
     131
     132//-----------------------------------------------------------------------------
     133// Global state
     134thread_local struct KernelThreadData kernelTLS __attribute__ ((tls_model ( "initial-exec" ))) = {
     135        NULL,                                                                                           // cannot use 0p
     136        NULL,
     137        { 1, false, false },
     138        6u //this should be seeded better but due to a bug calling rdtsc doesn't work
     139};
     140
     141//-----------------------------------------------------------------------------
     142// Struct to steal stack
     143struct current_stack_info_t {
     144        __stack_t * storage;                                                            // pointer to stack object
     145        void * base;                                                                            // base of stack
     146        void * limit;                                                                           // stack grows towards stack limit
     147        void * context;                                                                         // address of cfa_context_t
     148};
     149
     150void ?{}( current_stack_info_t & this ) {
     151        __stack_context_t ctx;
     152        CtxGet( ctx );
     153        this.base = ctx.FP;
     154
     155        rlimit r;
     156        getrlimit( RLIMIT_STACK, &r);
     157        size_t size = r.rlim_cur;
     158
     159        this.limit = (void *)(((intptr_t)this.base) - size);
     160        this.context = &storage_mainThreadCtx;
     161}
     162
     163//-----------------------------------------------------------------------------
     164// Main thread construction
     165
     166void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) {
     167        stack.storage = info->storage;
     168        with(*stack.storage) {
     169                limit     = info->limit;
     170                base      = info->base;
     171        }
     172        __attribute__((may_alias)) intptr_t * istorage = (intptr_t*) &stack.storage;
     173        *istorage |= 0x1;
     174        name = "Main Thread";
     175        state = Start;
     176        starter = 0p;
     177        last = 0p;
     178        cancellation = 0p;
     179}
     180
     181void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) {
     182        state = Start;
     183        self_cor{ info };
     184        curr_cor = &self_cor;
     185        curr_cluster = mainCluster;
     186        self_mon.owner = &this;
     187        self_mon.recursion = 1;
     188        self_mon_p = &self_mon;
     189        next = 0p;
     190
     191        node.next = 0p;
     192        node.prev = 0p;
     193        doregister(curr_cluster, this);
     194
     195        monitors{ &self_mon_p, 1, (fptr_t)0 };
     196}
     197
     198//-----------------------------------------------------------------------------
     199// Processor coroutine
     200void ?{}(processorCtx_t & this) {
     201
     202}
     203
     204// Construct the processor context of non-main processors
     205static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) {
     206        (this.__cor){ info };
     207        this.proc = proc;
     208}
     209
     210static void start(processor * this);
     211void ?{}(processor & this, const char * name, cluster & cltr) with( this ) {
     212        this.name = name;
     213        this.cltr = &cltr;
     214        terminated{ 0 };
     215        do_terminate = false;
     216        preemption_alarm = 0p;
     217        pending_preemption = false;
     218        runner.proc = &this;
     219
     220        idleLock{};
     221
     222        start( &this );
     223}
     224
     225void ^?{}(processor & this) with( this ){
     226        if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) {
     227                __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this);
     228
     229                __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED);
     230                wake( &this );
     231
     232                P( terminated );
     233                verify( kernelTLS.this_processor != &this);
     234        }
     235
     236        pthread_join( kernel_thread, 0p );
     237        free( this.stack );
     238}
     239
     240void ?{}(cluster & this, const char * name, Duration preemption_rate) with( this ) {
     241        this.name = name;
     242        this.preemption_rate = preemption_rate;
     243        ready_queue{};
     244        ready_queue_lock{};
     245
     246        procs{ __get };
     247        idles{ __get };
     248        threads{ __get };
     249
     250        doregister(this);
     251}
     252
     253void ^?{}(cluster & this) {
     254        unregister(this);
     255}
    116256
    117257//=============================================================================================
    118258// Kernel Scheduling logic
    119259//=============================================================================================
     260static void runThread(processor * this, thread_desc * dst);
     261static void finishRunning(processor * this);
     262static void halt(processor * this);
     263
    120264//Main of the processor contexts
    121265void main(processorCtx_t & runner) {
    122266        // Because of a bug, we couldn't initialized the seed on construction
    123267        // Do it here
    124         __cfaabi_tls.rand_seed ^= rdtscl();
    125         __cfaabi_tls.ready_rng.fwd_seed = 25214903917_l64u * (rdtscl() ^ (uintptr_t)&runner);
    126         __tls_rand_advance_bck();
     268        kernelTLS.rand_seed ^= rdtscl();
    127269
    128270        processor * this = runner.proc;
    129271        verify(this);
    130272
    131         __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this);
    132         #if !defined(__CFA_NO_STATISTICS__)
    133                 if( this->print_halts ) {
    134                         __cfaabi_bits_print_safe( STDOUT_FILENO, "Processor : %d - %s (%p)\n", this->id, this->name, (void*)this);
    135                 }
    136         #endif
     273        __cfaabi_dbg_print_safe("Kernel : core %p starting\n", this);
     274
     275        doregister(this->cltr, this);
    137276
    138277        {
     
    140279                preemption_scope scope = { this };
    141280
    142                 __cfadbg_print_safe(runtime_core, "Kernel : core %p started\n", this);
    143 
    144                 $thread * readyThread = 0p;
    145                 MAIN_LOOP:
    146                 for() {
    147                         // Try to get the next thread
    148                         readyThread = __next_thread( this->cltr );
    149 
    150                         if( !readyThread ) {
    151                                 readyThread = __next_thread_slow( this->cltr );
     281                __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
     282
     283                thread_desc * readyThread = 0p;
     284                for( unsigned int spin_count = 0; ! __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST); spin_count++ ) {
     285                        readyThread = nextThread( this->cltr );
     286
     287                        if(readyThread) {
     288                                verify( ! kernelTLS.preemption_state.enabled );
     289
     290                                runThread(this, readyThread);
     291
     292                                verify( ! kernelTLS.preemption_state.enabled );
     293
     294                                //Some actions need to be taken from the kernel
     295                                finishRunning(this);
     296
     297                                spin_count = 0;
     298                        } else {
     299                                // spin(this, &spin_count);
     300                                halt(this);
    152301                        }
    153 
    154                         HALT:
    155                         if( !readyThread ) {
    156                                 // Don't block if we are done
    157                                 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    158 
    159                                 #if !defined(__CFA_NO_STATISTICS__)
    160                                         __tls_stats()->ready.sleep.halts++;
    161                                 #endif
    162 
    163                                 // Push self to idle stack
    164                                 push(this->cltr->idles, * this);
    165 
    166                                 // Confirm the ready-queue is empty
    167                                 readyThread = __next_thread_slow( this->cltr );
    168                                 if( readyThread ) {
    169                                         // A thread was found, cancel the halt
    170                                         remove(this->cltr->idles, * this);
    171 
    172                                         #if !defined(__CFA_NO_STATISTICS__)
    173                                                 __tls_stats()->ready.sleep.cancels++;
    174                                         #endif
    175 
    176                                         // continue the mai loop
    177                                         break HALT;
    178                                 }
    179 
    180                                 #if !defined(__CFA_NO_STATISTICS__)
    181                                         if(this->print_halts) {
    182                                                 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl());
    183                                         }
    184                                 #endif
    185 
    186                                 wait( this->idle );
    187 
    188                                 #if !defined(__CFA_NO_STATISTICS__)
    189                                         if(this->print_halts) {
    190                                                 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl());
    191                                         }
    192                                 #endif
    193 
    194                                 // We were woken up, remove self from idle
    195                                 remove(this->cltr->idles, * this);
    196 
    197                                 // DON'T just proceed, start looking again
    198                                 continue MAIN_LOOP;
    199                         }
    200 
    201                         /* paranoid */ verify( readyThread );
    202 
    203                         // We found a thread run it
    204                         __run_thread(this, readyThread);
    205 
    206                         // Are we done?
    207                         if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    208302                }
    209303
    210                 __cfadbg_print_safe(runtime_core, "Kernel : core %p stopping\n", this);
    211         }
     304                __cfaabi_dbg_print_safe("Kernel : core %p stopping\n", this);
     305        }
     306
     307        unregister(this->cltr, this);
    212308
    213309        V( this->terminated );
    214310
    215         if(this == mainProcessor) {
    216                 // HACK : the coroutine context switch expects this_thread to be set
    217                 // and it make sense for it to be set in all other cases except here
    218                 // fake it
    219                 __cfaabi_tls.this_thread = mainThread;
    220         }
    221 
    222         __cfadbg_print_safe(runtime_core, "Kernel : core %p terminated\n", this);
     311        __cfaabi_dbg_print_safe("Kernel : core %p terminated\n", this);
    223312}
    224313
     
    229318// runThread runs a thread by context switching
    230319// from the processor coroutine to the target thread
    231 static void __run_thread(processor * this, $thread * thrd_dst) {
    232         /* paranoid */ verify( ! __preemption_enabled() );
    233         /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted);
    234         /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next );
    235         __builtin_prefetch( thrd_dst->context.SP );
    236 
    237         $coroutine * proc_cor = get_coroutine(this->runner);
    238 
    239         // set state of processor coroutine to inactive
    240         verify(proc_cor->state == Active);
    241         proc_cor->state = Blocked;
    242 
    243         // Actually run the thread
    244         RUNNING:  while(true) {
    245                 thrd_dst->preempted = __NO_PREEMPTION;
    246                 thrd_dst->state = Active;
    247 
    248                 // Update global state
    249                 kernelTLS().this_thread = thrd_dst;
    250 
    251                 /* paranoid */ verify( ! __preemption_enabled() );
    252                 /* paranoid */ verify( kernelTLS().this_thread == thrd_dst );
    253                 /* paranoid */ verify( thrd_dst->curr_cluster == this->cltr );
    254                 /* paranoid */ verify( thrd_dst->context.SP );
    255                 /* paranoid */ verify( thrd_dst->state != Halted );
    256                 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); // add escape condition if we are setting up the processor
    257                 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); // add escape condition if we are setting up the processor
    258                 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary );
    259 
    260 
    261 
    262                 // set context switch to the thread that the processor is executing
    263                 __cfactx_switch( &proc_cor->context, &thrd_dst->context );
    264                 // when __cfactx_switch returns we are back in the processor coroutine
    265 
    266                 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary );
    267                 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit), "ERROR : Destination $thread %p has been corrupted.\n StackPointer too large.\n", thrd_dst );
    268                 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ), "ERROR : Destination $thread %p has been corrupted.\n StackPointer too small.\n", thrd_dst );
    269                 /* paranoid */ verify( thrd_dst->context.SP );
    270                 /* paranoid */ verify( thrd_dst->curr_cluster == this->cltr );
    271                 /* paranoid */ verify( kernelTLS().this_thread == thrd_dst );
    272                 /* paranoid */ verify( ! __preemption_enabled() );
    273 
    274                 // Reset global state
    275                 kernelTLS().this_thread = 0p;
    276 
    277                 // We just finished running a thread, there are a few things that could have happened.
    278                 // 1 - Regular case : the thread has blocked and now one has scheduled it yet.
    279                 // 2 - Racy case    : the thread has blocked but someone has already tried to schedule it.
    280                 // 4 - Preempted
    281                 // In case 1, we may have won a race so we can't write to the state again.
    282                 // In case 2, we lost the race so we now own the thread.
    283 
    284                 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) {
    285                         // The thread was preempted, reschedule it and reset the flag
    286                         __schedule_thread( thrd_dst );
    287                         break RUNNING;
     320static void runThread(processor * this, thread_desc * thrd_dst) {
     321        coroutine_desc * proc_cor = get_coroutine(this->runner);
     322
     323        // Reset the terminating actions here
     324        this->finish.action_code = No_Action;
     325
     326        // Update global state
     327        kernelTLS.this_thread = thrd_dst;
     328
     329        // set state of processor coroutine to inactive and the thread to active
     330        proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
     331        thrd_dst->state = Active;
     332
     333        // set context switch to the thread that the processor is executing
     334        verify( thrd_dst->context.SP );
     335        CtxSwitch( &proc_cor->context, &thrd_dst->context );
     336        // when CtxSwitch returns we are back in the processor coroutine
     337
     338        // set state of processor coroutine to active and the thread to inactive
     339        thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive;
     340        proc_cor->state = Active;
     341}
     342
     343// KERNEL_ONLY
     344static void returnToKernel() {
     345        coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner);
     346        thread_desc * thrd_src = kernelTLS.this_thread;
     347
     348        // set state of current coroutine to inactive
     349        thrd_src->state = thrd_src->state == Halted ? Halted : Inactive;
     350        proc_cor->state = Active;
     351        int local_errno = *__volatile_errno();
     352        #if defined( __i386 ) || defined( __x86_64 )
     353                __x87_store;
     354        #endif
     355
     356        // set new coroutine that the processor is executing
     357        // and context switch to it
     358        verify( proc_cor->context.SP );
     359        CtxSwitch( &thrd_src->context, &proc_cor->context );
     360
     361        // set state of new coroutine to active
     362        proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
     363        thrd_src->state = Active;
     364
     365        #if defined( __i386 ) || defined( __x86_64 )
     366                __x87_load;
     367        #endif
     368        *__volatile_errno() = local_errno;
     369}
     370
     371// KERNEL_ONLY
     372// Once a thread has finished running, some of
     373// its final actions must be executed from the kernel
     374static void finishRunning(processor * this) with( this->finish ) {
     375        verify( ! kernelTLS.preemption_state.enabled );
     376        choose( action_code ) {
     377        case No_Action:
     378                break;
     379        case Release:
     380                unlock( *lock );
     381        case Schedule:
     382                ScheduleThread( thrd );
     383        case Release_Schedule:
     384                unlock( *lock );
     385                ScheduleThread( thrd );
     386        case Release_Multi:
     387                for(int i = 0; i < lock_count; i++) {
     388                        unlock( *locks[i] );
    288389                }
    289 
    290                 if(unlikely(thrd_dst->state == Halting)) {
    291                         // The thread has halted, it should never be scheduled/run again
    292                         // finish the thread
    293                         __thread_finish( thrd_dst );
    294                         break RUNNING;
     390        case Release_Multi_Schedule:
     391                for(int i = 0; i < lock_count; i++) {
     392                        unlock( *locks[i] );
    295393                }
    296 
    297                 /* paranoid */ verify( thrd_dst->state == Active );
    298                 thrd_dst->state = Blocked;
    299 
    300                 // set state of processor coroutine to active and the thread to inactive
    301                 int old_ticket = __atomic_fetch_sub(&thrd_dst->ticket, 1, __ATOMIC_SEQ_CST);
    302                 switch(old_ticket) {
    303                         case TICKET_RUNNING:
    304                                 // This is case 1, the regular case, nothing more is needed
    305                                 break RUNNING;
    306                         case TICKET_UNBLOCK:
    307                                 // This is case 2, the racy case, someone tried to run this thread before it finished blocking
    308                                 // In this case, just run it again.
    309                                 continue RUNNING;
    310                         default:
    311                                 // This makes no sense, something is wrong abort
    312                                 abort();
     394                for(int i = 0; i < thrd_count; i++) {
     395                        ScheduleThread( thrds[i] );
    313396                }
    314         }
    315 
    316         // Just before returning to the processor, set the processor coroutine to active
    317         proc_cor->state = Active;
    318 
    319         /* paranoid */ verify( ! __preemption_enabled() );
     397        case Callback:
     398                callback();
     399        default:
     400                abort("KERNEL ERROR: Unexpected action to run after thread");
     401        }
    320402}
    321403
    322404// KERNEL_ONLY
    323 void returnToKernel() {
    324         /* paranoid */ verify( ! __preemption_enabled() );
    325         $coroutine * proc_cor = get_coroutine(kernelTLS().this_processor->runner);
    326         $thread * thrd_src = kernelTLS().this_thread;
    327 
    328         #if !defined(__CFA_NO_STATISTICS__)
    329                 struct processor * last_proc = kernelTLS().this_processor;
    330         #endif
    331 
    332         // Run the thread on this processor
    333         {
    334                 int local_errno = *__volatile_errno();
    335                 #if defined( __i386 ) || defined( __x86_64 )
    336                         __x87_store;
    337                 #endif
    338                 /* paranoid */ verify( proc_cor->context.SP );
    339                 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_src->canary );
    340                 __cfactx_switch( &thrd_src->context, &proc_cor->context );
    341                 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_src->canary );
    342                 #if defined( __i386 ) || defined( __x86_64 )
    343                         __x87_load;
    344                 #endif
    345                 *__volatile_errno() = local_errno;
    346         }
    347 
    348         #if !defined(__CFA_NO_STATISTICS__)
    349                 if(last_proc != kernelTLS().this_processor) {
    350                         __tls_stats()->ready.threads.migration++;
     405// Context invoker for processors
     406// This is the entry point for processors (kernel threads)
     407// It effectively constructs a coroutine by stealing the pthread stack
     408static void * CtxInvokeProcessor(void * arg) {
     409        processor * proc = (processor *) arg;
     410        kernelTLS.this_processor = proc;
     411        kernelTLS.this_thread    = 0p;
     412        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
     413        // SKULLDUGGERY: We want to create a context for the processor coroutine
     414        // which is needed for the 2-step context switch. However, there is no reason
     415        // to waste the perfectly valid stack create by pthread.
     416        current_stack_info_t info;
     417        __stack_t ctx;
     418        info.storage = &ctx;
     419        (proc->runner){ proc, &info };
     420
     421        __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);
     422
     423        //Set global state
     424        kernelTLS.this_thread = 0p;
     425
     426        //We now have a proper context from which to schedule threads
     427        __cfaabi_dbg_print_safe("Kernel : core %p created (%p, %p)\n", proc, &proc->runner, &ctx);
     428
     429        // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
     430        // resume it to start it like it normally would, it will just context switch
     431        // back to here. Instead directly call the main since we already are on the
     432        // appropriate stack.
     433        get_coroutine(proc->runner)->state = Active;
     434        main( proc->runner );
     435        get_coroutine(proc->runner)->state = Halted;
     436
     437        // Main routine of the core returned, the core is now fully terminated
     438        __cfaabi_dbg_print_safe("Kernel : core %p main ended (%p)\n", proc, &proc->runner);
     439
     440        return 0p;
     441}
     442
     443static void Abort( int ret, const char * func ) {
     444        if ( ret ) {                                                                            // pthread routines return errno values
     445                abort( "%s : internal error, error(%d) %s.", func, ret, strerror( ret ) );
     446        } // if
     447} // Abort
     448
     449void * create_pthread( pthread_t * pthread, void * (*start)(void *), void * arg ) {
     450        pthread_attr_t attr;
     451
     452        Abort( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
     453
     454        size_t stacksize;
     455        // default stack size, normally defined by shell limit
     456        Abort( pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" );
     457        assert( stacksize >= PTHREAD_STACK_MIN );
     458
     459        void * stack;
     460        __cfaabi_dbg_debug_do(
     461                stack = memalign( __page_size, stacksize + __page_size );
     462                // pthread has no mechanism to create the guard page in user supplied stack.
     463                if ( mprotect( stack, __page_size, PROT_NONE ) == -1 ) {
     464                        abort( "mprotect : internal error, mprotect failure, error(%d) %s.", errno, strerror( errno ) );
     465                } // if
     466        );
     467        __cfaabi_dbg_no_debug_do(
     468                stack = malloc( stacksize );
     469        );
     470
     471        Abort( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" );
     472
     473        Abort( pthread_create( pthread, &attr, start, arg ), "pthread_create" );
     474        return stack;
     475}
     476
     477static void start(processor * this) {
     478        __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", this);
     479
     480        this->stack = create_pthread( &this->kernel_thread, CtxInvokeProcessor, (void *)this );
     481
     482        __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
     483}
     484
     485// KERNEL_ONLY
     486void kernel_first_resume( processor * this ) {
     487        thread_desc * src = mainThread;
     488        coroutine_desc * dst = get_coroutine(this->runner);
     489
     490        verify( ! kernelTLS.preemption_state.enabled );
     491
     492        kernelTLS.this_thread->curr_cor = dst;
     493        __stack_prepare( &dst->stack, 65000 );
     494        CtxStart(main, dst, this->runner, CtxInvokeCoroutine);
     495
     496        verify( ! kernelTLS.preemption_state.enabled );
     497
     498        dst->last = &src->self_cor;
     499        dst->starter = dst->starter ? dst->starter : &src->self_cor;
     500
     501        // set state of current coroutine to inactive
     502        src->state = src->state == Halted ? Halted : Inactive;
     503
     504        // context switch to specified coroutine
     505        verify( dst->context.SP );
     506        CtxSwitch( &src->context, &dst->context );
     507        // when CtxSwitch returns we are back in the src coroutine
     508
     509        mainThread->curr_cor = &mainThread->self_cor;
     510
     511        // set state of new coroutine to active
     512        src->state = Active;
     513
     514        verify( ! kernelTLS.preemption_state.enabled );
     515}
     516
     517// KERNEL_ONLY
     518void kernel_last_resume( processor * this ) {
     519        coroutine_desc * src = &mainThread->self_cor;
     520        coroutine_desc * dst = get_coroutine(this->runner);
     521
     522        verify( ! kernelTLS.preemption_state.enabled );
     523        verify( dst->starter == src );
     524        verify( dst->context.SP );
     525
     526        // context switch to the processor
     527        CtxSwitch( &src->context, &dst->context );
     528}
     529
     530//-----------------------------------------------------------------------------
     531// Scheduler routines
     532
     533// KERNEL ONLY
     534void ScheduleThread( thread_desc * thrd ) {
     535        verify( thrd );
     536        verify( thrd->state != Halted );
     537
     538        verify( ! kernelTLS.preemption_state.enabled );
     539
     540        verifyf( thrd->next == 0p, "Expected null got %p", thrd->next );
     541
     542        with( *thrd->curr_cluster ) {
     543                lock  ( ready_queue_lock __cfaabi_dbg_ctx2 );
     544                bool was_empty = !(ready_queue != 0);
     545                append( ready_queue, thrd );
     546                unlock( ready_queue_lock );
     547
     548                if(was_empty) {
     549                        lock      (proc_list_lock __cfaabi_dbg_ctx2);
     550                        if(idles) {
     551                                wake_fast(idles.head);
     552                        }
     553                        unlock    (proc_list_lock);
    351554                }
    352         #endif
    353 
    354         /* paranoid */ verify( ! __preemption_enabled() );
    355         /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) < ((uintptr_t)__get_stack(thrd_src->curr_cor)->base ), "ERROR : Returning $thread %p has been corrupted.\n StackPointer too small.\n", thrd_src );
    356         /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) > ((uintptr_t)__get_stack(thrd_src->curr_cor)->limit), "ERROR : Returning $thread %p has been corrupted.\n StackPointer too large.\n", thrd_src );
    357 }
    358 
    359 //-----------------------------------------------------------------------------
    360 // Scheduler routines
     555                else if( struct processor * idle = idles.head ) {
     556                        wake_fast(idle);
     557                }
     558
     559        }
     560
     561        verify( ! kernelTLS.preemption_state.enabled );
     562}
     563
    361564// KERNEL ONLY
    362 void __schedule_thread( $thread * thrd ) {
    363         /* paranoid */ verify( ! __preemption_enabled() );
    364         /* paranoid */ verify( kernelTLS().this_proc_id );
    365         /* paranoid */ verify( thrd );
    366         /* paranoid */ verify( thrd->state != Halted );
    367         /* paranoid */ verify( thrd->curr_cluster );
    368         /* paranoid */ #if defined( __CFA_WITH_VERIFY__ )
    369         /* paranoid */  if( thrd->state == Blocked || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION,
    370                                         "Error inactive thread marked as preempted, state %d, preemption %d\n", thrd->state, thrd->preempted );
    371         /* paranoid */  if( thrd->preempted != __NO_PREEMPTION ) assertf(thrd->state == Active,
    372                                         "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted );
    373         /* paranoid */ #endif
    374         /* paranoid */ verifyf( thrd->link.next == 0p, "Expected null got %p", thrd->link.next );
    375         /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary );
    376 
    377 
    378         if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready;
    379 
    380         ready_schedule_lock();
    381                 // Dereference the thread now because once we push it, there is not guaranteed it's still valid.
    382                 struct cluster * cl = thrd->curr_cluster;
    383 
    384                 // push the thread to the cluster ready-queue
    385                 push( cl, thrd );
    386 
    387                 // variable thrd is no longer safe to use
    388 
    389                 // wake the cluster using the save variable.
    390                 __wake_one( cl );
    391         ready_schedule_unlock();
    392 
    393         /* paranoid */ verify( ! __preemption_enabled() );
     565thread_desc * nextThread(cluster * this) with( *this ) {
     566        verify( ! kernelTLS.preemption_state.enabled );
     567        lock( ready_queue_lock __cfaabi_dbg_ctx2 );
     568        thread_desc * head = pop_head( ready_queue );
     569        unlock( ready_queue_lock );
     570        verify( ! kernelTLS.preemption_state.enabled );
     571        return head;
     572}
     573
     574void BlockInternal() {
     575        disable_interrupts();
     576        verify( ! kernelTLS.preemption_state.enabled );
     577        returnToKernel();
     578        verify( ! kernelTLS.preemption_state.enabled );
     579        enable_interrupts( __cfaabi_dbg_ctx );
     580}
     581
     582void BlockInternal( __spinlock_t * lock ) {
     583        disable_interrupts();
     584        with( *kernelTLS.this_processor ) {
     585                finish.action_code = Release;
     586                finish.lock        = lock;
     587        }
     588
     589        verify( ! kernelTLS.preemption_state.enabled );
     590        returnToKernel();
     591        verify( ! kernelTLS.preemption_state.enabled );
     592
     593        enable_interrupts( __cfaabi_dbg_ctx );
     594}
     595
     596void BlockInternal( thread_desc * thrd ) {
     597        disable_interrupts();
     598        with( * kernelTLS.this_processor ) {
     599                finish.action_code = Schedule;
     600                finish.thrd        = thrd;
     601        }
     602
     603        verify( ! kernelTLS.preemption_state.enabled );
     604        returnToKernel();
     605        verify( ! kernelTLS.preemption_state.enabled );
     606
     607        enable_interrupts( __cfaabi_dbg_ctx );
     608}
     609
     610void BlockInternal( __spinlock_t * lock, thread_desc * thrd ) {
     611        assert(thrd);
     612        disable_interrupts();
     613        with( * kernelTLS.this_processor ) {
     614                finish.action_code = Release_Schedule;
     615                finish.lock        = lock;
     616                finish.thrd        = thrd;
     617        }
     618
     619        verify( ! kernelTLS.preemption_state.enabled );
     620        returnToKernel();
     621        verify( ! kernelTLS.preemption_state.enabled );
     622
     623        enable_interrupts( __cfaabi_dbg_ctx );
     624}
     625
     626void BlockInternal(__spinlock_t * locks [], unsigned short count) {
     627        disable_interrupts();
     628        with( * kernelTLS.this_processor ) {
     629                finish.action_code = Release_Multi;
     630                finish.locks       = locks;
     631                finish.lock_count  = count;
     632        }
     633
     634        verify( ! kernelTLS.preemption_state.enabled );
     635        returnToKernel();
     636        verify( ! kernelTLS.preemption_state.enabled );
     637
     638        enable_interrupts( __cfaabi_dbg_ctx );
     639}
     640
     641void BlockInternal(__spinlock_t * locks [], unsigned short lock_count, thread_desc * thrds [], unsigned short thrd_count) {
     642        disable_interrupts();
     643        with( *kernelTLS.this_processor ) {
     644                finish.action_code = Release_Multi_Schedule;
     645                finish.locks       = locks;
     646                finish.lock_count  = lock_count;
     647                finish.thrds       = thrds;
     648                finish.thrd_count  = thrd_count;
     649        }
     650
     651        verify( ! kernelTLS.preemption_state.enabled );
     652        returnToKernel();
     653        verify( ! kernelTLS.preemption_state.enabled );
     654
     655        enable_interrupts( __cfaabi_dbg_ctx );
     656}
     657
     658void BlockInternal(__finish_callback_fptr_t callback) {
     659        disable_interrupts();
     660        with( *kernelTLS.this_processor ) {
     661                finish.action_code = Callback;
     662                finish.callback    = callback;
     663        }
     664
     665        verify( ! kernelTLS.preemption_state.enabled );
     666        returnToKernel();
     667        verify( ! kernelTLS.preemption_state.enabled );
     668
     669        enable_interrupts( __cfaabi_dbg_ctx );
    394670}
    395671
    396672// KERNEL ONLY
    397 static inline $thread * __next_thread(cluster * this) with( *this ) {
    398         /* paranoid */ verify( ! __preemption_enabled() );
    399         /* paranoid */ verify( kernelTLS().this_proc_id );
    400 
    401         ready_schedule_lock();
    402                 $thread * thrd = pop( this );
    403         ready_schedule_unlock();
    404 
    405         /* paranoid */ verify( kernelTLS().this_proc_id );
    406         /* paranoid */ verify( ! __preemption_enabled() );
    407         return thrd;
    408 }
    409 
    410 // KERNEL ONLY
    411 static inline $thread * __next_thread_slow(cluster * this) with( *this ) {
    412         /* paranoid */ verify( ! __preemption_enabled() );
    413         /* paranoid */ verify( kernelTLS().this_proc_id );
    414 
    415         ready_schedule_lock();
    416                 $thread * thrd = pop_slow( this );
    417         ready_schedule_unlock();
    418 
    419         /* paranoid */ verify( kernelTLS().this_proc_id );
    420         /* paranoid */ verify( ! __preemption_enabled() );
    421         return thrd;
    422 }
    423 
    424 void unpark( $thread * thrd ) {
    425         if( !thrd ) return;
    426 
    427         int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST);
    428         switch(old_ticket) {
    429                 case TICKET_RUNNING:
    430                         // Wake won the race, the thread will reschedule/rerun itself
    431                         break;
    432                 case TICKET_BLOCKED:
    433                         /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION );
    434                         /* paranoid */ verify( thrd->state == Blocked );
    435 
    436                         {
    437                                 /* paranoid */ verify( publicTLS_get(this_proc_id) );
    438                                 bool full = publicTLS_get(this_proc_id)->full_proc;
    439                                 if(full) disable_interrupts();
    440 
    441                                 /* paranoid */ verify( ! __preemption_enabled() );
    442 
    443                                 // Wake lost the race,
    444                                 __schedule_thread( thrd );
    445 
    446                                 /* paranoid */ verify( ! __preemption_enabled() );
    447 
    448                                 if(full) enable_interrupts( __cfaabi_dbg_ctx );
    449                                 /* paranoid */ verify( publicTLS_get(this_proc_id) );
    450                         }
    451 
    452                         break;
    453                 default:
    454                         // This makes no sense, something is wrong abort
    455                         abort("Thread %p (%s) has mismatch park/unpark\n", thrd, thrd->self_cor.name);
    456         }
    457 }
    458 
    459 void park( void ) {
    460         /* paranoid */ verify( __preemption_enabled() );
     673void LeaveThread(__spinlock_t * lock, thread_desc * thrd) {
     674        verify( ! kernelTLS.preemption_state.enabled );
     675        with( * kernelTLS.this_processor ) {
     676                finish.action_code = thrd ? Release_Schedule : Release;
     677                finish.lock        = lock;
     678                finish.thrd        = thrd;
     679        }
     680
     681        returnToKernel();
     682}
     683
     684//=============================================================================================
     685// Kernel Setup logic
     686//=============================================================================================
     687//-----------------------------------------------------------------------------
     688// Kernel boot procedures
     689static void kernel_startup(void) {
     690        verify( ! kernelTLS.preemption_state.enabled );
     691        __cfaabi_dbg_print_safe("Kernel : Starting\n");
     692
     693        __page_size = sysconf( _SC_PAGESIZE );
     694
     695        __cfa_dbg_global_clusters.list{ __get };
     696        __cfa_dbg_global_clusters.lock{};
     697
     698        // Initialize the main cluster
     699        mainCluster = (cluster *)&storage_mainCluster;
     700        (*mainCluster){"Main Cluster"};
     701
     702        __cfaabi_dbg_print_safe("Kernel : Main cluster ready\n");
     703
     704        // Start by initializing the main thread
     705        // SKULLDUGGERY: the mainThread steals the process main thread
     706        // which will then be scheduled by the mainProcessor normally
     707        mainThread = (thread_desc *)&storage_mainThread;
     708        current_stack_info_t info;
     709        info.storage = (__stack_t*)&storage_mainThreadCtx;
     710        (*mainThread){ &info };
     711
     712        __cfaabi_dbg_print_safe("Kernel : Main thread ready\n");
     713
     714
     715
     716        // Construct the processor context of the main processor
     717        void ?{}(processorCtx_t & this, processor * proc) {
     718                (this.__cor){ "Processor" };
     719                this.__cor.starter = 0p;
     720                this.proc = proc;
     721        }
     722
     723        void ?{}(processor & this) with( this ) {
     724                name = "Main Processor";
     725                cltr = mainCluster;
     726                terminated{ 0 };
     727                do_terminate = false;
     728                preemption_alarm = 0p;
     729                pending_preemption = false;
     730                kernel_thread = pthread_self();
     731
     732                runner{ &this };
     733                __cfaabi_dbg_print_safe("Kernel : constructed main processor context %p\n", &runner);
     734        }
     735
     736        // Initialize the main processor and the main processor ctx
     737        // (the coroutine that contains the processing control flow)
     738        mainProcessor = (processor *)&storage_mainProcessor;
     739        (*mainProcessor){};
     740
     741        //initialize the global state variables
     742        kernelTLS.this_processor = mainProcessor;
     743        kernelTLS.this_thread    = mainThread;
     744
     745        // Enable preemption
     746        kernel_start_preemption();
     747
     748        // Add the main thread to the ready queue
     749        // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
     750        ScheduleThread(mainThread);
     751
     752        // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
     753        // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
     754        // mainThread is on the ready queue when this call is made.
     755        kernel_first_resume( kernelTLS.this_processor );
     756
     757
     758
     759        // THE SYSTEM IS NOW COMPLETELY RUNNING
     760        __cfaabi_dbg_print_safe("Kernel : Started\n--------------------------------------------------\n\n");
     761
     762        verify( ! kernelTLS.preemption_state.enabled );
     763        enable_interrupts( __cfaabi_dbg_ctx );
     764        verify( TL_GET( preemption_state.enabled ) );
     765}
     766
     767static void kernel_shutdown(void) {
     768        __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n");
     769
     770        verify( TL_GET( preemption_state.enabled ) );
    461771        disable_interrupts();
    462         /* paranoid */ verify( ! __preemption_enabled() );
    463         /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION );
    464 
    465         returnToKernel();
    466 
    467         /* paranoid */ verify( ! __preemption_enabled() );
    468         enable_interrupts( __cfaabi_dbg_ctx );
    469         /* paranoid */ verify( __preemption_enabled() );
    470 
    471 }
    472 
    473 extern "C" {
    474         // Leave the thread monitor
    475         // last routine called by a thread.
    476         // Should never return
    477         void __cfactx_thrd_leave() {
    478                 $thread * thrd = active_thread();
    479                 $monitor * this = &thrd->self_mon;
    480 
    481                 // Lock the monitor now
    482                 lock( this->lock __cfaabi_dbg_ctx2 );
    483 
    484                 disable_interrupts();
    485 
    486                 /* paranoid */ verify( ! __preemption_enabled() );
    487                 /* paranoid */ verify( thrd->state == Active );
    488                 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary );
    489                 /* paranoid */ verify( kernelTLS().this_thread == thrd );
    490                 /* paranoid */ verify( thrd->context.SP );
    491                 /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) > ((uintptr_t)__get_stack(thrd->curr_cor)->limit), "ERROR : $thread %p has been corrupted.\n StackPointer too large.\n", thrd );
    492                 /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) < ((uintptr_t)__get_stack(thrd->curr_cor)->base ), "ERROR : $thread %p has been corrupted.\n StackPointer too small.\n", thrd );
    493 
    494                 thrd->state = Halting;
    495                 if( TICKET_RUNNING != thrd->ticket ) { abort( "Thread terminated with pending unpark" ); }
    496                 if( thrd != this->owner ) { abort( "Thread internal monitor has incorrect owner" ); }
    497                 if( this->recursion != 1) { abort( "Thread internal monitor has unbalanced recursion" ); }
    498 
    499                 // Leave the thread
    500                 returnToKernel();
    501 
    502                 // Control flow should never reach here!
    503                 abort();
    504         }
    505 }
    506 
    507 // KERNEL ONLY
    508 bool force_yield( __Preemption_Reason reason ) {
    509         /* paranoid */ verify( __preemption_enabled() );
    510         disable_interrupts();
    511         /* paranoid */ verify( ! __preemption_enabled() );
    512 
    513         $thread * thrd = kernelTLS().this_thread;
    514         /* paranoid */ verify(thrd->state == Active);
    515 
    516         // SKULLDUGGERY: It is possible that we are preempting this thread just before
    517         // it was going to park itself. If that is the case and it is already using the
    518         // intrusive fields then we can't use them to preempt the thread
    519         // If that is the case, abandon the preemption.
    520         bool preempted = false;
    521         if(thrd->link.next == 0p) {
    522                 preempted = true;
    523                 thrd->preempted = reason;
    524                 returnToKernel();
    525         }
    526 
    527         /* paranoid */ verify( ! __preemption_enabled() );
    528         enable_interrupts_noPoll();
    529         /* paranoid */ verify( __preemption_enabled() );
    530 
    531         return preempted;
     772        verify( ! kernelTLS.preemption_state.enabled );
     773
     774        // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.
     775        // When its coroutine terminates, it return control to the mainThread
     776        // which is currently here
     777        __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE);
     778        kernel_last_resume( kernelTLS.this_processor );
     779        mainThread->self_cor.state = Halted;
     780
     781        // THE SYSTEM IS NOW COMPLETELY STOPPED
     782
     783        // Disable preemption
     784        kernel_stop_preemption();
     785
     786        // Destroy the main processor and its context in reverse order of construction
     787        // These were manually constructed so we need manually destroy them
     788        ^(mainProcessor->runner){};
     789        ^(mainProcessor){};
     790
     791        // Final step, destroy the main thread since it is no longer needed
     792        // Since we provided a stack to this taxk it will not destroy anything
     793        ^(mainThread){};
     794
     795        ^(__cfa_dbg_global_clusters.list){};
     796        ^(__cfa_dbg_global_clusters.lock){};
     797
     798        __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n");
    532799}
    533800
    534801//=============================================================================================
    535 // Kernel Idle Sleep
     802// Kernel Quiescing
    536803//=============================================================================================
    537 // Wake a thread from the front if there are any
    538 static void __wake_one(cluster * this) {
    539         /* paranoid */ verify( ! __preemption_enabled() );
    540         /* paranoid */ verify( ready_schedule_islocked() );
    541 
    542         // Check if there is a sleeping processor
    543         processor * p;
    544         unsigned idle;
    545         unsigned total;
    546         [idle, total, p] = query(this->idles);
    547 
    548         // If no one is sleeping, we are done
    549         if( idle == 0 ) return;
    550 
    551         // We found a processor, wake it up
    552         post( p->idle );
    553 
    554         #if !defined(__CFA_NO_STATISTICS__)
    555                 __tls_stats()->ready.sleep.wakes++;
    556         #endif
    557 
    558         /* paranoid */ verify( ready_schedule_islocked() );
    559         /* paranoid */ verify( ! __preemption_enabled() );
    560 
    561         return;
    562 }
    563 
    564 // Unconditionnaly wake a thread
    565 void __wake_proc(processor * this) {
    566         __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this);
    567 
    568         disable_interrupts();
    569                 /* paranoid */ verify( ! __preemption_enabled() );
    570                 post( this->idle );
    571         enable_interrupts( __cfaabi_dbg_ctx );
    572 }
    573 
    574 static void push  (__cluster_idles & this, processor & proc) {
    575         /* paranoid */ verify( ! __preemption_enabled() );
    576         lock( this );
    577                 this.idle++;
    578                 /* paranoid */ verify( this.idle <= this.total );
    579 
    580                 insert_first(this.list, proc);
    581         unlock( this );
    582         /* paranoid */ verify( ! __preemption_enabled() );
    583 }
    584 
    585 static void remove(__cluster_idles & this, processor & proc) {
    586         /* paranoid */ verify( ! __preemption_enabled() );
    587         lock( this );
    588                 this.idle--;
    589                 /* paranoid */ verify( this.idle >= 0 );
    590 
    591                 remove(proc);
    592         unlock( this );
    593         /* paranoid */ verify( ! __preemption_enabled() );
    594 }
    595 
    596 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) {
    597         for() {
    598                 uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);
    599                 if( 1 == (l % 2) ) { Pause(); continue; }
    600                 unsigned idle    = this.idle;
    601                 unsigned total   = this.total;
    602                 processor * proc = &this.list`first;
    603                 // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it
    604                 asm volatile("": : :"memory");
    605                 if(l != __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST)) { Pause(); continue; }
    606                 return [idle, total, proc];
     804static void halt(processor * this) with( *this ) {
     805        // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
     806
     807        with( *cltr ) {
     808                lock      (proc_list_lock __cfaabi_dbg_ctx2);
     809                remove    (procs, *this);
     810                push_front(idles, *this);
     811                unlock    (proc_list_lock);
     812        }
     813
     814        __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this);
     815
     816        wait( idleLock );
     817
     818        __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this);
     819
     820        with( *cltr ) {
     821                lock      (proc_list_lock __cfaabi_dbg_ctx2);
     822                remove    (idles, *this);
     823                push_front(procs, *this);
     824                unlock    (proc_list_lock);
    607825        }
    608826}
     
    618836        // the globalAbort flag is true.
    619837        lock( kernel_abort_lock __cfaabi_dbg_ctx2 );
    620 
    621         // disable interrupts, it no longer makes sense to try to interrupt this processor
    622         disable_interrupts();
    623838
    624839        // first task to abort ?
     
    638853        }
    639854
    640         return __cfaabi_tls.this_thread;
     855        return kernelTLS.this_thread;
    641856}
    642857
    643858void kernel_abort_msg( void * kernel_data, char * abort_text, int abort_text_size ) {
    644         $thread * thrd = ( $thread * ) kernel_data;
     859        thread_desc * thrd = kernel_data;
    645860
    646861        if(thrd) {
     
    663878
    664879int kernel_abort_lastframe( void ) __attribute__ ((__nothrow__)) {
    665         return get_coroutine(kernelTLS().this_thread) == get_coroutine(mainThread) ? 4 : 2;
     880        return get_coroutine(kernelTLS.this_thread) == get_coroutine(mainThread) ? 4 : 2;
    666881}
    667882
     
    690905void ^?{}(semaphore & this) {}
    691906
    692 bool P(semaphore & this) with( this ){
     907void P(semaphore & this) with( this ){
    693908        lock( lock __cfaabi_dbg_ctx2 );
    694909        count -= 1;
    695910        if ( count < 0 ) {
    696911                // queue current task
    697                 append( waiting, active_thread() );
     912                append( waiting, kernelTLS.this_thread );
    698913
    699914                // atomically release spin lock and block
    700                 unlock( lock );
    701                 park();
    702                 return true;
     915                BlockInternal( &lock );
    703916        }
    704917        else {
    705918            unlock( lock );
    706             return false;
    707         }
    708 }
    709 
    710 bool V(semaphore & this) with( this ) {
    711         $thread * thrd = 0p;
     919        }
     920}
     921
     922void V(semaphore & this) with( this ) {
     923        thread_desc * thrd = 0p;
    712924        lock( lock __cfaabi_dbg_ctx2 );
    713925        count += 1;
     
    720932
    721933        // make new owner
    722         unpark( thrd );
    723 
    724         return thrd != 0p;
    725 }
    726 
    727 bool V(semaphore & this, unsigned diff) with( this ) {
    728         $thread * thrd = 0p;
    729         lock( lock __cfaabi_dbg_ctx2 );
    730         int release = max(-count, (int)diff);
    731         count += diff;
    732         for(release) {
    733                 unpark( pop_head( waiting ) );
    734         }
    735 
    736         unlock( lock );
    737 
    738         return thrd != 0p;
     934        WakeThread( thrd );
     935}
     936
     937//-----------------------------------------------------------------------------
     938// Global Queues
     939void doregister( cluster     & cltr ) {
     940        lock      ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2);
     941        push_front( __cfa_dbg_global_clusters.list, cltr );
     942        unlock    ( __cfa_dbg_global_clusters.lock );
     943}
     944
     945void unregister( cluster     & cltr ) {
     946        lock  ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2);
     947        remove( __cfa_dbg_global_clusters.list, cltr );
     948        unlock( __cfa_dbg_global_clusters.lock );
     949}
     950
     951void doregister( cluster * cltr, thread_desc & thrd ) {
     952        lock      (cltr->thread_list_lock __cfaabi_dbg_ctx2);
     953        cltr->nthreads += 1;
     954        push_front(cltr->threads, thrd);
     955        unlock    (cltr->thread_list_lock);
     956}
     957
     958void unregister( cluster * cltr, thread_desc & thrd ) {
     959        lock  (cltr->thread_list_lock __cfaabi_dbg_ctx2);
     960        remove(cltr->threads, thrd );
     961        cltr->nthreads -= 1;
     962        unlock(cltr->thread_list_lock);
     963}
     964
     965void doregister( cluster * cltr, processor * proc ) {
     966        lock      (cltr->proc_list_lock __cfaabi_dbg_ctx2);
     967        cltr->nprocessors += 1;
     968        push_front(cltr->procs, *proc);
     969        unlock    (cltr->proc_list_lock);
     970}
     971
     972void unregister( cluster * cltr, processor * proc ) {
     973        lock  (cltr->proc_list_lock __cfaabi_dbg_ctx2);
     974        remove(cltr->procs, *proc );
     975        cltr->nprocessors -= 1;
     976        unlock(cltr->proc_list_lock);
    739977}
    740978
     
    743981__cfaabi_dbg_debug_do(
    744982        extern "C" {
    745                 void __cfaabi_dbg_record_lock(__spinlock_t & this, const char prev_name[]) {
     983                void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) {
    746984                        this.prev_name = prev_name;
    747                         this.prev_thrd = kernelTLS().this_thread;
     985                        this.prev_thrd = kernelTLS.this_thread;
    748986                }
    749987        }
     
    752990//-----------------------------------------------------------------------------
    753991// Debug
    754 bool threading_enabled(void) __attribute__((const)) {
     992bool threading_enabled(void) {
    755993        return true;
    756994}
    757 
    758 //-----------------------------------------------------------------------------
    759 // Statistics
    760 #if !defined(__CFA_NO_STATISTICS__)
    761         void print_halts( processor & this ) {
    762                 this.print_halts = true;
    763         }
    764 
    765         void print_stats_now( cluster & this, int flags ) {
    766                 __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this );
    767         }
    768 
    769         extern int __print_alarm_stats;
    770         void print_alarm_stats() {
    771                 __print_alarm_stats = -1;
    772         }
    773 #endif
    774995// Local Variables: //
    775996// mode: c //
  • libcfa/src/concurrency/kernel.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 12:29:26 2020
    13 // Update Count     : 22
     12// Last Modified On : Wed Dec  4 07:54:51 2019
     13// Update Count     : 18
    1414//
    1515
    1616#pragma once
     17
     18#include <stdbool.h>
    1719
    1820#include "invoke.h"
     
    2022#include "coroutine.hfa"
    2123
    22 #include "containers/list.hfa"
    23 
    2424extern "C" {
    25         #include <bits/pthreadtypes.h>
    26         #include <linux/types.h>
     25#include <pthread.h>
     26#include <semaphore.h>
    2727}
    2828
     
    3232        __spinlock_t lock;
    3333        int count;
    34         __queue_t($thread) waiting;
     34        __queue_t(thread_desc) waiting;
    3535};
    3636
    3737void  ?{}(semaphore & this, int count = 1);
    3838void ^?{}(semaphore & this);
    39 bool   P (semaphore & this);
    40 bool   V (semaphore & this);
    41 bool   V (semaphore & this, unsigned count);
     39void   P (semaphore & this);
     40void   V (semaphore & this);
    4241
    4342
     
    4645extern struct cluster * mainCluster;
    4746
    48 // Processor id, required for scheduling threads
    49 struct __processor_id_t {
    50         unsigned id:24;
    51         bool full_proc:1;
    52 
    53         #if !defined(__CFA_NO_STATISTICS__)
    54                 struct __stats_t * stats;
    55         #endif
    56 };
    57 
     47enum FinishOpCode { No_Action, Release, Schedule, Release_Schedule, Release_Multi, Release_Multi_Schedule, Callback };
     48
     49typedef void (*__finish_callback_fptr_t)(void);
     50
     51//TODO use union, many of these fields are mutually exclusive (i.e. MULTI vs NOMULTI)
     52struct FinishAction {
     53        FinishOpCode action_code;
     54        /*
     55        // Union of possible actions
     56        union {
     57                // Option 1 : locks and threads
     58                struct {
     59                        // 1 thread or N thread
     60                        union {
     61                                thread_desc * thrd;
     62                                struct {
     63                                        thread_desc ** thrds;
     64                                        unsigned short thrd_count;
     65                                };
     66                        };
     67                        // 1 lock or N lock
     68                        union {
     69                                __spinlock_t * lock;
     70                                struct {
     71                                        __spinlock_t ** locks;
     72                                        unsigned short lock_count;
     73                                };
     74                        };
     75                };
     76                // Option 2 : action pointer
     77                __finish_callback_fptr_t callback;
     78        };
     79        /*/
     80        thread_desc * thrd;
     81        thread_desc ** thrds;
     82        unsigned short thrd_count;
     83        __spinlock_t * lock;
     84        __spinlock_t ** locks;
     85        unsigned short lock_count;
     86        __finish_callback_fptr_t callback;
     87        //*/
     88};
     89static inline void ?{}(FinishAction & this) {
     90        this.action_code = No_Action;
     91        this.thrd = 0p;
     92        this.lock = 0p;
     93}
     94static inline void ^?{}(FinishAction &) {}
     95
     96// Processor
    5897coroutine processorCtx_t {
    5998        struct processor * proc;
     
    61100
    62101// Wrapper around kernel threads
    63 struct __attribute__((aligned(128))) processor {
     102struct processor {
    64103        // Main state
    65         inline __processor_id_t;
     104        // Coroutine ctx who does keeps the state of the processor
     105        struct processorCtx_t runner;
    66106
    67107        // Cluster from which to get threads
    68108        struct cluster * cltr;
    69109
    70         // Set to true to notify the processor should terminate
    71         volatile bool do_terminate;
    72 
    73         // Coroutine ctx who does keeps the state of the processor
    74         struct processorCtx_t runner;
    75 
    76110        // Name of the processor
    77111        const char * name;
     
    79113        // Handle to pthreads
    80114        pthread_t kernel_thread;
     115
     116        // RunThread data
     117        // Action to do after a thread is ran
     118        struct FinishAction finish;
    81119
    82120        // Preemption data
     
    87125        bool pending_preemption;
    88126
    89         // Idle lock (kernel semaphore)
    90         __bin_sem_t idle;
    91 
    92         // Termination synchronisation (user semaphore)
     127        // Idle lock
     128        __bin_sem_t idleLock;
     129
     130        // Termination
     131        // Set to true to notify the processor should terminate
     132        volatile bool do_terminate;
     133
     134        // Termination synchronisation
    93135        semaphore terminated;
    94136
     
    97139
    98140        // Link lists fields
    99         DLISTED_MGD_IMPL_IN(processor)
    100 
    101         #if !defined(__CFA_NO_STATISTICS__)
    102                 int print_stats;
    103                 bool print_halts;
    104         #endif
     141        struct __dbg_node_proc {
     142                struct processor * next;
     143                struct processor * prev;
     144        } node;
    105145
    106146#ifdef __CFA_DEBUG__
     
    110150};
    111151
    112 void  ?{}(processor & this, const char name[], struct cluster & cltr);
     152void  ?{}(processor & this, const char * name, struct cluster & cltr);
    113153void ^?{}(processor & this);
    114154
    115155static inline void  ?{}(processor & this)                    { this{ "Anonymous Processor", *mainCluster}; }
    116156static inline void  ?{}(processor & this, struct cluster & cltr)    { this{ "Anonymous Processor", cltr}; }
    117 static inline void  ?{}(processor & this, const char name[]) { this{name, *mainCluster }; }
    118 
    119 DLISTED_MGD_IMPL_OUT(processor)
    120 
    121 //-----------------------------------------------------------------------------
    122 // I/O
    123 struct __io_data;
    124 
    125 // IO poller user-thread
    126 // Not using the "thread" keyword because we want to control
    127 // more carefully when to start/stop it
    128 struct $io_ctx_thread {
    129         struct __io_data * ring;
    130         single_sem sem;
    131         volatile bool done;
    132         $thread self;
    133 };
    134 
    135 
    136 struct io_context {
    137         $io_ctx_thread thrd;
    138 };
    139 
    140 struct io_context_params {
    141         int num_entries;
    142         int num_ready;
    143         int submit_aff;
    144         bool eager_submits:1;
    145         bool poller_submits:1;
    146         bool poll_submit:1;
    147         bool poll_complete:1;
    148 };
    149 
    150 void  ?{}(io_context_params & this);
    151 
    152 void  ?{}(io_context & this, struct cluster & cl);
    153 void  ?{}(io_context & this, struct cluster & cl, const io_context_params & params);
    154 void ^?{}(io_context & this);
    155 
    156 struct io_cancellation {
    157         __u64 target;
    158 };
    159 
    160 static inline void  ?{}(io_cancellation & this) { this.target = -1u; }
    161 static inline void ^?{}(io_cancellation &) {}
    162 bool cancel(io_cancellation & this);
    163 
    164 //-----------------------------------------------------------------------------
    165 // Cluster Tools
    166 
    167 // Intrusives lanes which are used by the relaxed ready queue
    168 struct __attribute__((aligned(128))) __intrusive_lane_t;
    169 void  ?{}(__intrusive_lane_t & this);
    170 void ^?{}(__intrusive_lane_t & this);
    171 
    172 // Counter used for wether or not the lanes are all empty
    173 struct __attribute__((aligned(128))) __snzi_node_t;
    174 struct __snzi_t {
    175         unsigned mask;
    176         int root;
    177         __snzi_node_t * nodes;
    178 };
    179 
    180 void  ?{}( __snzi_t & this, unsigned depth );
    181 void ^?{}( __snzi_t & this );
    182 
    183 //TODO adjust cache size to ARCHITECTURE
    184 // Structure holding the relaxed ready queue
    185 struct __ready_queue_t {
    186         // Data tracking how many/which lanes are used
    187         // Aligned to 128 for cache locality
    188         __snzi_t snzi;
    189 
    190         // Data tracking the actual lanes
    191         // On a seperate cacheline from the used struct since
    192         // used can change on each push/pop but this data
    193         // only changes on shrink/grow
    194         struct {
    195                 // Arary of lanes
    196                 __intrusive_lane_t * volatile data;
    197 
    198                 // Number of lanes (empty or not)
    199                 volatile size_t count;
    200         } lanes;
    201 };
    202 
    203 void  ?{}(__ready_queue_t & this);
    204 void ^?{}(__ready_queue_t & this);
    205 
    206 // Idle Sleep
    207 struct __cluster_idles {
    208         // Spin lock protecting the queue
    209         volatile uint64_t lock;
    210 
    211         // Total number of processors
    212         unsigned total;
    213 
    214         // Total number of idle processors
    215         unsigned idle;
    216 
    217         // List of idle processors
    218         dlist(processor, processor) list;
    219 };
     157static inline void  ?{}(processor & this, const char * name) { this{name, *mainCluster }; }
     158
     159static inline [processor *&, processor *& ] __get( processor & this ) {
     160        return this.node.[next, prev];
     161}
    220162
    221163//-----------------------------------------------------------------------------
    222164// Cluster
    223 struct __attribute__((aligned(128))) cluster {
     165struct cluster {
     166        // Ready queue locks
     167        __spinlock_t ready_queue_lock;
     168
    224169        // Ready queue for threads
    225         __ready_queue_t ready_queue;
     170        __queue_t(thread_desc) ready_queue;
    226171
    227172        // Name of the cluster
     
    231176        Duration preemption_rate;
    232177
    233         // List of idle processors
    234         __cluster_idles idles;
     178        // List of processors
     179        __spinlock_t proc_list_lock;
     180        __dllist_t(struct processor) procs;
     181        __dllist_t(struct processor) idles;
     182        unsigned int nprocessors;
    235183
    236184        // List of threads
    237185        __spinlock_t thread_list_lock;
    238         __dllist_t(struct $thread) threads;
     186        __dllist_t(struct thread_desc) threads;
    239187        unsigned int nthreads;
    240188
     
    244192                cluster * prev;
    245193        } node;
    246 
    247         struct {
    248                 io_context * ctxs;
    249                 unsigned cnt;
    250         } io;
    251 
    252         #if !defined(__CFA_NO_STATISTICS__)
    253                 struct __stats_t * stats;
    254                 int print_stats;
    255         #endif
    256194};
    257195extern Duration default_preemption();
    258196
    259 void ?{} (cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params);
     197void ?{} (cluster & this, const char * name, Duration preemption_rate);
    260198void ^?{}(cluster & this);
    261199
    262 static inline void ?{} (cluster & this)                                            { io_context_params default_params;    this{"Anonymous Cluster", default_preemption(), 1, default_params}; }
    263 static inline void ?{} (cluster & this, Duration preemption_rate)                  { io_context_params default_params;    this{"Anonymous Cluster", preemption_rate, 1, default_params}; }
    264 static inline void ?{} (cluster & this, const char name[])                         { io_context_params default_params;    this{name, default_preemption(), 1, default_params}; }
    265 static inline void ?{} (cluster & this, unsigned num_io)                           { io_context_params default_params;    this{"Anonymous Cluster", default_preemption(), num_io, default_params}; }
    266 static inline void ?{} (cluster & this, Duration preemption_rate, unsigned num_io) { io_context_params default_params;    this{"Anonymous Cluster", preemption_rate, num_io, default_params}; }
    267 static inline void ?{} (cluster & this, const char name[], unsigned num_io)        { io_context_params default_params;    this{name, default_preemption(), num_io, default_params}; }
    268 static inline void ?{} (cluster & this, const io_context_params & io_params)                                            { this{"Anonymous Cluster", default_preemption(), 1, io_params}; }
    269 static inline void ?{} (cluster & this, Duration preemption_rate, const io_context_params & io_params)                  { this{"Anonymous Cluster", preemption_rate, 1, io_params}; }
    270 static inline void ?{} (cluster & this, const char name[], const io_context_params & io_params)                         { this{name, default_preemption(), 1, io_params}; }
    271 static inline void ?{} (cluster & this, unsigned num_io, const io_context_params & io_params)                           { this{"Anonymous Cluster", default_preemption(), num_io, io_params}; }
    272 static inline void ?{} (cluster & this, Duration preemption_rate, unsigned num_io, const io_context_params & io_params) { this{"Anonymous Cluster", preemption_rate, num_io, io_params}; }
    273 static inline void ?{} (cluster & this, const char name[], unsigned num_io, const io_context_params & io_params)        { this{name, default_preemption(), num_io, io_params}; }
    274 
    275 static inline [cluster *&, cluster *& ] __get( cluster & this ) __attribute__((const)) { return this.node.[next, prev]; }
    276 
    277 static inline struct processor * active_processor() { return publicTLS_get( this_processor ); } // UNSAFE
    278 static inline struct cluster   * active_cluster  () { return publicTLS_get( this_processor )->cltr; }
    279 
    280 #if !defined(__CFA_NO_STATISTICS__)
    281         void print_stats_now( cluster & this, int flags );
    282 
    283         static inline void print_stats_at_exit( cluster & this, int flags ) {
    284                 this.print_stats |= flags;
    285         }
    286 
    287         static inline void print_stats_at_exit( processor & this, int flags ) {
    288                 this.print_stats |= flags;
    289         }
    290 
    291         void print_halts( processor & this );
    292 #endif
     200static inline void ?{} (cluster & this)                           { this{"Anonymous Cluster", default_preemption()}; }
     201static inline void ?{} (cluster & this, Duration preemption_rate) { this{"Anonymous Cluster", preemption_rate}; }
     202static inline void ?{} (cluster & this, const char * name)        { this{name, default_preemption()}; }
     203
     204static inline [cluster *&, cluster *& ] __get( cluster & this ) {
     205        return this.node.[next, prev];
     206}
     207
     208static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE
     209static inline struct cluster   * active_cluster  () { return TL_GET( this_processor )->cltr; }
    293210
    294211// Local Variables: //
  • libcfa/src/concurrency/kernel_private.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Mon Feb 13 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Aug 12 08:21:33 2020
    13 // Update Count     : 9
     12// Last Modified On : Sat Nov 30 19:25:02 2019
     13// Update Count     : 8
    1414//
    1515
     
    2020
    2121#include "alarm.hfa"
    22 #include "stats.hfa"
     22
    2323
    2424//-----------------------------------------------------------------------------
    2525// Scheduler
    26 
    27 struct __attribute__((aligned(128))) __scheduler_lock_id_t;
    2826
    2927extern "C" {
     
    3331}
    3432
    35 void __schedule_thread( $thread * )
    36 #if defined(NDEBUG) || (!defined(__CFA_DEBUG__) && !defined(__CFA_VERIFY__))
    37         __attribute__((nonnull (1)))
    38 #endif
    39 ;
     33void ScheduleThread( thread_desc * );
     34static inline void WakeThread( thread_desc * thrd ) {
     35        if( !thrd ) return;
    4036
    41 extern bool __preemption_enabled();
     37        verify(thrd->state == Inactive);
    4238
    43 //release/wake-up the following resources
    44 void __thread_finish( $thread * thrd );
     39        disable_interrupts();
     40        ScheduleThread( thrd );
     41        enable_interrupts( __cfaabi_dbg_ctx );
     42}
     43thread_desc * nextThread(cluster * this);
     44
     45//Block current thread and release/wake-up the following resources
     46void BlockInternal(void);
     47void BlockInternal(__spinlock_t * lock);
     48void BlockInternal(thread_desc * thrd);
     49void BlockInternal(__spinlock_t * lock, thread_desc * thrd);
     50void BlockInternal(__spinlock_t * locks [], unsigned short count);
     51void BlockInternal(__spinlock_t * locks [], unsigned short count, thread_desc * thrds [], unsigned short thrd_count);
     52void BlockInternal(__finish_callback_fptr_t callback);
     53void LeaveThread(__spinlock_t * lock, thread_desc * thrd);
    4554
    4655//-----------------------------------------------------------------------------
     
    4857void main(processorCtx_t *);
    4958
    50 void * __create_pthread( pthread_t *, void * (*)(void *), void * );
    51 void __destroy_pthread( pthread_t pthread, void * stack, void ** retval );
     59void * create_pthread( pthread_t *, void * (*)(void *), void * );
    5260
     61static inline void wake_fast(processor * this) {
     62        __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this);
     63        post( this->idleLock );
     64}
    5365
     66static inline void wake(processor * this) {
     67        disable_interrupts();
     68        wake_fast(this);
     69        enable_interrupts( __cfaabi_dbg_ctx );
     70}
    5471
    55 extern cluster * mainCluster;
     72struct event_kernel_t {
     73        alarm_list_t alarms;
     74        __spinlock_t lock;
     75};
     76
     77extern event_kernel_t * event_kernel;
     78
     79struct __cfa_kernel_preemption_state_t {
     80        bool enabled;
     81        bool in_progress;
     82        unsigned short disable_count;
     83};
     84
     85extern volatile thread_local __cfa_kernel_preemption_state_t preemption_state __attribute__ ((tls_model ( "initial-exec" )));
    5686
    5787//-----------------------------------------------------------------------------
    5888// Threads
    5989extern "C" {
    60       void __cfactx_invoke_thread(void (*main)(void *), void * this);
     90      void CtxInvokeThread(void (*main)(void *), void * this);
    6191}
    6292
     93extern void ThreadCtxSwitch(coroutine_desc * src, coroutine_desc * dst);
     94
    6395__cfaabi_dbg_debug_do(
    64         extern void __cfaabi_dbg_thread_register  ( $thread * thrd );
    65         extern void __cfaabi_dbg_thread_unregister( $thread * thrd );
     96        extern void __cfaabi_dbg_thread_register  ( thread_desc * thrd );
     97        extern void __cfaabi_dbg_thread_unregister( thread_desc * thrd );
    6698)
    67 
    68 #define TICKET_BLOCKED (-1) // thread is blocked
    69 #define TICKET_RUNNING ( 0) // thread is running
    70 #define TICKET_UNBLOCK ( 1) // thread should ignore next block
    7199
    72100//-----------------------------------------------------------------------------
    73101// Utils
    74 void doregister( struct cluster * cltr, struct $thread & thrd );
    75 void unregister( struct cluster * cltr, struct $thread & thrd );
     102#define KERNEL_STORAGE(T,X) static char storage_##X[sizeof(T)]
    76103
    77 //-----------------------------------------------------------------------------
    78 // I/O
    79 void ^?{}(io_context & this, bool );
    80 
    81 //=======================================================================
    82 // Cluster lock API
    83 //=======================================================================
    84 // Cells use by the reader writer lock
    85 // while not generic it only relies on a opaque pointer
    86 struct __attribute__((aligned(128))) __scheduler_lock_id_t {
    87         // Spin lock used as the underlying lock
    88         volatile bool lock;
    89 
    90         // Handle pointing to the proc owning this cell
    91         // Used for allocating cells and debugging
    92         __processor_id_t * volatile handle;
    93 
    94         #ifdef __CFA_WITH_VERIFY__
    95                 // Debug, check if this is owned for reading
    96                 bool owned;
    97         #endif
    98 };
    99 
    100 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
    101 
    102 // Lock-Free registering/unregistering of threads
    103 // Register a processor to a given cluster and get its unique id in return
    104 unsigned doregister( struct __processor_id_t * proc );
    105 
    106 // Unregister a processor from a given cluster using its id, getting back the original pointer
    107 void     unregister( struct __processor_id_t * proc );
    108 
    109 //-----------------------------------------------------------------------
    110 // Cluster idle lock/unlock
    111 static inline void lock(__cluster_idles & this) {
    112         for() {
    113                 uint64_t l = this.lock;
    114                 if(
    115                         (0 == (l % 2))
    116                         && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
    117                 ) return;
    118                 Pause();
    119         }
     104static inline uint32_t tls_rand() {
     105        kernelTLS.rand_seed ^= kernelTLS.rand_seed << 6;
     106        kernelTLS.rand_seed ^= kernelTLS.rand_seed >> 21;
     107        kernelTLS.rand_seed ^= kernelTLS.rand_seed << 7;
     108        return kernelTLS.rand_seed;
    120109}
    121110
    122 static inline void unlock(__cluster_idles & this) {
    123         /* paranoid */ verify( 1 == (this.lock % 2) );
    124         __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
    125 }
    126111
    127 //=======================================================================
    128 // Reader-writer lock implementation
    129 // Concurrent with doregister/unregister,
    130 //    i.e., threads can be added at any point during or between the entry/exit
     112void doregister( struct cluster & cltr );
     113void unregister( struct cluster & cltr );
    131114
    132 //-----------------------------------------------------------------------
    133 // simple spinlock underlying the RWLock
    134 // Blocking acquire
    135 static inline void __atomic_acquire(volatile bool * ll) {
    136         while( __builtin_expect(__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST), false) ) {
    137                 while(__atomic_load_n(ll, (int)__ATOMIC_RELAXED))
    138                         Pause();
    139         }
    140         /* paranoid */ verify(*ll);
    141 }
     115void doregister( struct cluster * cltr, struct thread_desc & thrd );
     116void unregister( struct cluster * cltr, struct thread_desc & thrd );
    142117
    143 // Non-Blocking acquire
    144 static inline bool __atomic_try_acquire(volatile bool * ll) {
    145         return !__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST);
    146 }
    147 
    148 // Release
    149 static inline void __atomic_unlock(volatile bool * ll) {
    150         /* paranoid */ verify(*ll);
    151         __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE);
    152 }
    153 
    154 //-----------------------------------------------------------------------
    155 // Reader-Writer lock protecting the ready-queues
    156 // while this lock is mostly generic some aspects
    157 // have been hard-coded to for the ready-queue for
    158 // simplicity and performance
    159 struct __scheduler_RWLock_t {
    160         // total cachelines allocated
    161         unsigned int max;
    162 
    163         // cachelines currently in use
    164         volatile unsigned int alloc;
    165 
    166         // cachelines ready to itereate over
    167         // (!= to alloc when thread is in second half of doregister)
    168         volatile unsigned int ready;
    169 
    170         // writer lock
    171         volatile bool lock;
    172 
    173         // data pointer
    174         __scheduler_lock_id_t * data;
    175 };
    176 
    177 void  ?{}(__scheduler_RWLock_t & this);
    178 void ^?{}(__scheduler_RWLock_t & this);
    179 
    180 extern __scheduler_RWLock_t * __scheduler_lock;
    181 
    182 //-----------------------------------------------------------------------
    183 // Reader side : acquire when using the ready queue to schedule but not
    184 //  creating/destroying queues
    185 static inline void ready_schedule_lock(void) with(*__scheduler_lock) {
    186         /* paranoid */ verify( ! __preemption_enabled() );
    187         /* paranoid */ verify( kernelTLS().this_proc_id );
    188 
    189         unsigned iproc = kernelTLS().this_proc_id->id;
    190         /*paranoid*/ verify(data[iproc].handle == kernelTLS().this_proc_id);
    191         /*paranoid*/ verify(iproc < ready);
    192 
    193         // Step 1 : make sure no writer are in the middle of the critical section
    194         while(__atomic_load_n(&lock, (int)__ATOMIC_RELAXED))
    195                 Pause();
    196 
    197         // Fence needed because we don't want to start trying to acquire the lock
    198         // before we read a false.
    199         // Not needed on x86
    200         // std::atomic_thread_fence(std::memory_order_seq_cst);
    201 
    202         // Step 2 : acquire our local lock
    203         __atomic_acquire( &data[iproc].lock );
    204         /*paranoid*/ verify(data[iproc].lock);
    205 
    206         #ifdef __CFA_WITH_VERIFY__
    207                 // Debug, check if this is owned for reading
    208                 data[iproc].owned = true;
    209         #endif
    210 }
    211 
    212 static inline void ready_schedule_unlock(void) with(*__scheduler_lock) {
    213         /* paranoid */ verify( ! __preemption_enabled() );
    214         /* paranoid */ verify( kernelTLS().this_proc_id );
    215 
    216         unsigned iproc = kernelTLS().this_proc_id->id;
    217         /*paranoid*/ verify(data[iproc].handle == kernelTLS().this_proc_id);
    218         /*paranoid*/ verify(iproc < ready);
    219         /*paranoid*/ verify(data[iproc].lock);
    220         /*paranoid*/ verify(data[iproc].owned);
    221         #ifdef __CFA_WITH_VERIFY__
    222                 // Debug, check if this is owned for reading
    223                 data[iproc].owned = false;
    224         #endif
    225         __atomic_unlock(&data[iproc].lock);
    226 }
    227 
    228 #ifdef __CFA_WITH_VERIFY__
    229         static inline bool ready_schedule_islocked(void) {
    230                 /* paranoid */ verify( ! __preemption_enabled() );
    231                 /*paranoid*/ verify( kernelTLS().this_proc_id );
    232                 __processor_id_t * proc = kernelTLS().this_proc_id;
    233                 return __scheduler_lock->data[proc->id].owned;
    234         }
    235 
    236         static inline bool ready_mutate_islocked() {
    237                 return __scheduler_lock->lock;
    238         }
    239 #endif
    240 
    241 //-----------------------------------------------------------------------
    242 // Writer side : acquire when changing the ready queue, e.g. adding more
    243 //  queues or removing them.
    244 uint_fast32_t ready_mutate_lock( void );
    245 
    246 void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ );
    247 
    248 //=======================================================================
    249 // Ready-Queue API
    250 //-----------------------------------------------------------------------
    251 // pop thread from the ready queue of a cluster
    252 // returns 0p if empty
    253 __attribute__((hot)) bool query(struct cluster * cltr);
    254 
    255 //-----------------------------------------------------------------------
    256 // push thread onto a ready queue for a cluster
    257 // returns true if the list was previously empty, false otherwise
    258 __attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd);
    259 
    260 //-----------------------------------------------------------------------
    261 // pop thread from the ready queue of a cluster
    262 // returns 0p if empty
    263 // May return 0p spuriously
    264 __attribute__((hot)) struct $thread * pop(struct cluster * cltr);
    265 
    266 //-----------------------------------------------------------------------
    267 // pop thread from the ready queue of a cluster
    268 // returns 0p if empty
    269 // guaranteed to find any threads added before this call
    270 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr);
    271 
    272 //-----------------------------------------------------------------------
    273 // remove thread from the ready queue of a cluster
    274 // returns bool if it wasn't found
    275 bool remove_head(struct cluster * cltr, struct $thread * thrd);
    276 
    277 //-----------------------------------------------------------------------
    278 // Increase the width of the ready queue (number of lanes) by 4
    279 void ready_queue_grow  (struct cluster * cltr, int target);
    280 
    281 //-----------------------------------------------------------------------
    282 // Decrease the width of the ready queue (number of lanes) by 4
    283 void ready_queue_shrink(struct cluster * cltr, int target);
    284 
     118void doregister( struct cluster * cltr, struct processor * proc );
     119void unregister( struct cluster * cltr, struct processor * proc );
    285120
    286121// Local Variables: //
  • libcfa/src/concurrency/monitor.cfa

    reef8dfb rbdfc032  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // $monitor.c --
     7// monitor_desc.c --
    88//
    99// Author           : Thierry Delisle
     
    2727//-----------------------------------------------------------------------------
    2828// Forward declarations
    29 static inline void __set_owner ( $monitor * this, $thread * owner );
    30 static inline void __set_owner ( $monitor * storage [], __lock_size_t count, $thread * owner );
    31 static inline void set_mask  ( $monitor * storage [], __lock_size_t count, const __waitfor_mask_t & mask );
    32 static inline void reset_mask( $monitor * this );
    33 
    34 static inline $thread * next_thread( $monitor * this );
    35 static inline bool is_accepted( $monitor * this, const __monitor_group_t & monitors );
     29static inline void set_owner ( monitor_desc * this, thread_desc * owner );
     30static inline void set_owner ( monitor_desc * storage [], __lock_size_t count, thread_desc * owner );
     31static inline void set_mask  ( monitor_desc * storage [], __lock_size_t count, const __waitfor_mask_t & mask );
     32static inline void reset_mask( monitor_desc * this );
     33
     34static inline thread_desc * next_thread( monitor_desc * this );
     35static inline bool is_accepted( monitor_desc * this, const __monitor_group_t & monitors );
    3636
    3737static inline void lock_all  ( __spinlock_t * locks [], __lock_size_t count );
    38 static inline void lock_all  ( $monitor * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count );
     38static inline void lock_all  ( monitor_desc * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count );
    3939static inline void unlock_all( __spinlock_t * locks [], __lock_size_t count );
    40 static inline void unlock_all( $monitor * locks [], __lock_size_t count );
    41 
    42 static inline void save   ( $monitor * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*out*/ recursions [], __waitfor_mask_t /*out*/ masks [] );
    43 static inline void restore( $monitor * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*in */ recursions [], __waitfor_mask_t /*in */ masks [] );
    44 
    45 static inline void init     ( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
    46 static inline void init_push( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
    47 
    48 static inline $thread *        check_condition   ( __condition_criterion_t * );
     40static inline void unlock_all( monitor_desc * locks [], __lock_size_t count );
     41
     42static inline void save   ( monitor_desc * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*out*/ recursions [], __waitfor_mask_t /*out*/ masks [] );
     43static inline void restore( monitor_desc * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*in */ recursions [], __waitfor_mask_t /*in */ masks [] );
     44
     45static inline void init     ( __lock_size_t count, monitor_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
     46static inline void init_push( __lock_size_t count, monitor_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
     47
     48static inline thread_desc *        check_condition   ( __condition_criterion_t * );
    4949static inline void                 brand_condition   ( condition & );
    50 static inline [$thread *, int] search_entry_queue( const __waitfor_mask_t &, $monitor * monitors [], __lock_size_t count );
     50static inline [thread_desc *, int] search_entry_queue( const __waitfor_mask_t &, monitor_desc * monitors [], __lock_size_t count );
    5151
    5252forall(dtype T | sized( T ))
    5353static inline __lock_size_t insert_unique( T * array [], __lock_size_t & size, T * val );
    5454static inline __lock_size_t count_max    ( const __waitfor_mask_t & mask );
    55 static inline __lock_size_t aggregate    ( $monitor * storage [], const __waitfor_mask_t & mask );
     55static inline __lock_size_t aggregate    ( monitor_desc * storage [], const __waitfor_mask_t & mask );
    5656
    5757//-----------------------------------------------------------------------------
     
    6868
    6969#define monitor_ctx( mons, cnt )                                /* Define that create the necessary struct for internal/external scheduling operations */ \
    70         $monitor ** monitors = mons;                          /* Save the targeted monitors                                                          */ \
     70        monitor_desc ** monitors = mons;                          /* Save the targeted monitors                                                          */ \
    7171        __lock_size_t count = cnt;                                /* Save the count to a local variable                                                  */ \
    7272        unsigned int recursions[ count ];                         /* Save the current recursion levels to restore them later                             */ \
     
    8080//-----------------------------------------------------------------------------
    8181// Enter/Leave routines
    82 // Enter single monitor
    83 static void __enter( $monitor * this, const __monitor_group_t & group ) {
    84         $thread * thrd = active_thread();
    85 
    86         // Lock the monitor spinlock
    87         lock( this->lock __cfaabi_dbg_ctx2 );
    88 
    89         __cfaabi_dbg_print_safe( "Kernel : %10p Entering mon %p (%p)\n", thrd, this, this->owner);
    90 
    91         if( unlikely(0 != (0x1 & (uintptr_t)this->owner)) ) {
    92                 abort( "Attempt by thread \"%.256s\" (%p) to access joined monitor %p.", thrd->self_cor.name, thrd, this );
    93         }
    94         else if( !this->owner ) {
    95                 // No one has the monitor, just take it
    96                 __set_owner( this, thrd );
    97 
    98                 __cfaabi_dbg_print_safe( "Kernel :  mon is free \n" );
    99         }
    100         else if( this->owner == thrd) {
    101                 // We already have the monitor, just note how many times we took it
    102                 this->recursion += 1;
    103 
    104                 __cfaabi_dbg_print_safe( "Kernel :  mon already owned \n" );
    105         }
    106         else if( is_accepted( this, group) ) {
    107                 // Some one was waiting for us, enter
    108                 __set_owner( this, thrd );
    109 
    110                 // Reset mask
    111                 reset_mask( this );
    112 
    113                 __cfaabi_dbg_print_safe( "Kernel :  mon accepts \n" );
    114         }
    115         else {
    116                 __cfaabi_dbg_print_safe( "Kernel :  blocking \n" );
    117 
    118                 // Some one else has the monitor, wait in line for it
    119                 /* paranoid */ verify( thrd->link.next == 0p );
    120                 append( this->entry_queue, thrd );
    121                 /* paranoid */ verify( thrd->link.next == 1p );
    122 
    123                 unlock( this->lock );
    124                 park();
     82
     83
     84extern "C" {
     85        // Enter single monitor
     86        static void __enter_monitor_desc( monitor_desc * this, const __monitor_group_t & group ) {
     87                // Lock the monitor spinlock
     88                lock( this->lock __cfaabi_dbg_ctx2 );
     89                // Interrupts disable inside critical section
     90                thread_desc * thrd = kernelTLS.this_thread;
     91
     92                __cfaabi_dbg_print_safe( "Kernel : %10p Entering mon %p (%p)\n", thrd, this, this->owner);
     93
     94                if( !this->owner ) {
     95                        // No one has the monitor, just take it
     96                        set_owner( this, thrd );
     97
     98                        __cfaabi_dbg_print_safe( "Kernel :  mon is free \n" );
     99                }
     100                else if( this->owner == thrd) {
     101                        // We already have the monitor, just note how many times we took it
     102                        this->recursion += 1;
     103
     104                        __cfaabi_dbg_print_safe( "Kernel :  mon already owned \n" );
     105                }
     106                else if( is_accepted( this, group) ) {
     107                        // Some one was waiting for us, enter
     108                        set_owner( this, thrd );
     109
     110                        // Reset mask
     111                        reset_mask( this );
     112
     113                        __cfaabi_dbg_print_safe( "Kernel :  mon accepts \n" );
     114                }
     115                else {
     116                        __cfaabi_dbg_print_safe( "Kernel :  blocking \n" );
     117
     118                        // Some one else has the monitor, wait in line for it
     119                        append( this->entry_queue, thrd );
     120
     121                        BlockInternal( &this->lock );
     122
     123                        __cfaabi_dbg_print_safe( "Kernel : %10p Entered  mon %p\n", thrd, this);
     124
     125                        // BlockInternal will unlock spinlock, no need to unlock ourselves
     126                        return;
     127                }
    125128
    126129                __cfaabi_dbg_print_safe( "Kernel : %10p Entered  mon %p\n", thrd, this);
    127130
    128                 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    129                 return;
    130         }
    131 
    132         __cfaabi_dbg_print_safe( "Kernel : %10p Entered  mon %p\n", thrd, this);
    133 
    134         /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    135         /* paranoid */ verify( this->lock.lock );
    136 
    137         // Release the lock and leave
    138         unlock( this->lock );
    139         return;
    140 }
    141 
    142 static void __dtor_enter( $monitor * this, fptr_t func, bool join ) {
    143         $thread * thrd = active_thread();
    144         #if defined( __CFA_WITH_VERIFY__ )
    145                 bool is_thrd = this == &thrd->self_mon;
    146         #endif
    147 
    148         // Lock the monitor spinlock
    149         lock( this->lock __cfaabi_dbg_ctx2 );
    150 
    151         __cfaabi_dbg_print_safe( "Kernel : %10p Entering dtor for mon %p (%p)\n", thrd, this, this->owner);
    152 
    153 
    154         if( !this->owner ) {
    155                 __cfaabi_dbg_print_safe( "Kernel : Destroying free mon %p\n", this);
    156 
    157                 // No one has the monitor, just take it
    158                 __set_owner( this, thrd );
    159 
    160                 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    161                 /* paranoid */ verify( !is_thrd || thrd->state == Halted || thrd->state == Cancelled );
    162 
     131                // Release the lock and leave
    163132                unlock( this->lock );
    164133                return;
    165134        }
    166         else if( this->owner == thrd && !join) {
    167                 // We already have the monitor... but where about to destroy it so the nesting will fail
    168                 // Abort!
    169                 abort( "Attempt to destroy monitor %p by thread \"%.256s\" (%p) in nested mutex.", this, thrd->self_cor.name, thrd );
    170         }
    171         // SKULLDUGGERY: join will act as a dtor so it would normally trigger to above check
    172         // because join will not release the monitor after it executed.
    173         // to avoid that it sets the owner to the special value thrd | 1p before exiting
    174         else if( this->owner == ($thread*)(1 | (uintptr_t)thrd) ) {
    175                 // restore the owner and just return
    176                 __cfaabi_dbg_print_safe( "Kernel : Destroying free mon %p\n", this);
    177 
    178                 // No one has the monitor, just take it
    179                 __set_owner( this, thrd );
    180 
    181                 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    182                 /* paranoid */ verify( !is_thrd || thrd->state == Halted || thrd->state == Cancelled );
    183 
     135
     136        static void __enter_monitor_dtor( monitor_desc * this, fptr_t func ) {
     137                // Lock the monitor spinlock
     138                lock( this->lock __cfaabi_dbg_ctx2 );
     139                // Interrupts disable inside critical section
     140                thread_desc * thrd = kernelTLS.this_thread;
     141
     142                __cfaabi_dbg_print_safe( "Kernel : %10p Entering dtor for mon %p (%p)\n", thrd, this, this->owner);
     143
     144
     145                if( !this->owner ) {
     146                        __cfaabi_dbg_print_safe( "Kernel : Destroying free mon %p\n", this);
     147
     148                        // No one has the monitor, just take it
     149                        set_owner( this, thrd );
     150
     151                        unlock( this->lock );
     152                        return;
     153                }
     154                else if( this->owner == thrd) {
     155                        // We already have the monitor... but where about to destroy it so the nesting will fail
     156                        // Abort!
     157                        abort( "Attempt to destroy monitor %p by thread \"%.256s\" (%p) in nested mutex.", this, thrd->self_cor.name, thrd );
     158                }
     159
     160                __lock_size_t count = 1;
     161                monitor_desc ** monitors = &this;
     162                __monitor_group_t group = { &this, 1, func };
     163                if( is_accepted( this, group) ) {
     164                        __cfaabi_dbg_print_safe( "Kernel :  mon accepts dtor, block and signal it \n" );
     165
     166                        // Wake the thread that is waiting for this
     167                        __condition_criterion_t * urgent = pop( this->signal_stack );
     168                        verify( urgent );
     169
     170                        // Reset mask
     171                        reset_mask( this );
     172
     173                        // Create the node specific to this wait operation
     174                        wait_ctx_primed( thrd, 0 )
     175
     176                        // Some one else has the monitor, wait for him to finish and then run
     177                        BlockInternal( &this->lock, urgent->owner->waiting_thread );
     178
     179                        // Some one was waiting for us, enter
     180                        set_owner( this, thrd );
     181                }
     182                else {
     183                        __cfaabi_dbg_print_safe( "Kernel :  blocking \n" );
     184
     185                        wait_ctx( thrd, 0 )
     186                        this->dtor_node = &waiter;
     187
     188                        // Some one else has the monitor, wait in line for it
     189                        append( this->entry_queue, thrd );
     190                        BlockInternal( &this->lock );
     191
     192                        // BlockInternal will unlock spinlock, no need to unlock ourselves
     193                        return;
     194                }
     195
     196                __cfaabi_dbg_print_safe( "Kernel : Destroying %p\n", this);
     197
     198        }
     199
     200        // Leave single monitor
     201        void __leave_monitor_desc( monitor_desc * this ) {
     202                // Lock the monitor spinlock
     203                lock( this->lock __cfaabi_dbg_ctx2 );
     204
     205                __cfaabi_dbg_print_safe( "Kernel : %10p Leaving mon %p (%p)\n", kernelTLS.this_thread, this, this->owner);
     206
     207                verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
     208
     209                // Leaving a recursion level, decrement the counter
     210                this->recursion -= 1;
     211
     212                // If we haven't left the last level of recursion
     213                // it means we don't need to do anything
     214                if( this->recursion != 0) {
     215                        __cfaabi_dbg_print_safe( "Kernel :  recursion still %d\n", this->recursion);
     216                        unlock( this->lock );
     217                        return;
     218                }
     219
     220                // Get the next thread, will be null on low contention monitor
     221                thread_desc * new_owner = next_thread( this );
     222
     223                // We can now let other threads in safely
    184224                unlock( this->lock );
    185                 return;
    186         }
    187 
    188         // The monitor is busy, if this is a thread and the thread owns itself, it better be active
    189         /* paranoid */ verify( !is_thrd || this->owner != thrd || (thrd->state != Halted && thrd->state != Cancelled) );
    190 
    191         __lock_size_t count = 1;
    192         $monitor ** monitors = &this;
    193         __monitor_group_t group = { &this, 1, func };
    194         if( is_accepted( this, group) ) {
    195                 __cfaabi_dbg_print_safe( "Kernel :  mon accepts dtor, block and signal it \n" );
    196 
    197                 // Wake the thread that is waiting for this
    198                 __condition_criterion_t * urgent = pop( this->signal_stack );
    199                 /* paranoid */ verify( urgent );
    200 
    201                 // Reset mask
    202                 reset_mask( this );
    203 
    204                 // Create the node specific to this wait operation
    205                 wait_ctx_primed( thrd, 0 )
    206 
    207                 // Some one else has the monitor, wait for him to finish and then run
    208                 unlock( this->lock );
    209 
    210                 // Release the next thread
    211                 /* paranoid */ verifyf( urgent->owner->waiting_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    212                 unpark( urgent->owner->waiting_thread );
    213 
    214                 // Park current thread waiting
    215                 park();
    216 
    217                 // Some one was waiting for us, enter
    218                 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    219 
    220                 __cfaabi_dbg_print_safe( "Kernel : Destroying %p\n", this);
    221                 return;
    222         }
    223         else {
    224                 __cfaabi_dbg_print_safe( "Kernel :  blocking \n" );
    225 
    226                 wait_ctx( thrd, 0 )
    227                 this->dtor_node = &waiter;
    228 
    229                 // Some one else has the monitor, wait in line for it
    230                 /* paranoid */ verify( thrd->link.next == 0p );
    231                 append( this->entry_queue, thrd );
    232                 /* paranoid */ verify( thrd->link.next == 1p );
    233                 unlock( this->lock );
    234 
    235                 // Park current thread waiting
    236                 park();
    237 
    238                 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    239                 return;
    240         }
    241 }
    242 
    243 // Leave single monitor
    244 void __leave( $monitor * this ) {
    245         // Lock the monitor spinlock
    246         lock( this->lock __cfaabi_dbg_ctx2 );
    247 
    248         __cfaabi_dbg_print_safe( "Kernel : %10p Leaving mon %p (%p)\n", active_thread(), this, this->owner);
    249 
    250         /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    251 
    252         // Leaving a recursion level, decrement the counter
    253         this->recursion -= 1;
    254 
    255         // If we haven't left the last level of recursion
    256         // it means we don't need to do anything
    257         if( this->recursion != 0) {
    258                 __cfaabi_dbg_print_safe( "Kernel :  recursion still %d\n", this->recursion);
    259                 unlock( this->lock );
    260                 return;
    261         }
    262 
    263         // Get the next thread, will be null on low contention monitor
    264         $thread * new_owner = next_thread( this );
    265 
    266         // Check the new owner is consistent with who we wake-up
    267         // new_owner might be null even if someone owns the monitor when the owner is still waiting for another monitor
    268         /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this );
    269 
    270         // We can now let other threads in safely
    271         unlock( this->lock );
    272 
    273         //We need to wake-up the thread
    274         /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this );
    275         unpark( new_owner );
    276 }
    277 
    278 // Leave single monitor for the last time
    279 void __dtor_leave( $monitor * this, bool join ) {
    280         __cfaabi_dbg_debug_do(
    281                 if( active_thread() != this->owner ) {
    282                         abort( "Destroyed monitor %p has inconsistent owner, expected %p got %p.\n", this, active_thread(), this->owner);
    283                 }
    284                 if( this->recursion != 1  && !join ) {
    285                         abort( "Destroyed monitor %p has %d outstanding nested calls.\n", this, this->recursion - 1);
    286                 }
    287         )
    288 
    289         this->owner = ($thread*)(1 | (uintptr_t)this->owner);
    290 }
    291 
    292 void __thread_finish( $thread * thrd ) {
    293         $monitor * this = &thrd->self_mon;
    294 
    295         // Lock the monitor now
    296         /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary );
    297         /* paranoid */ verify( this->lock.lock );
    298         /* paranoid */ verify( thrd->context.SP );
    299         /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) > ((uintptr_t)__get_stack(thrd->curr_cor)->limit), "ERROR : $thread %p has been corrupted.\n StackPointer too large.\n", thrd );
    300         /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) < ((uintptr_t)__get_stack(thrd->curr_cor)->base ), "ERROR : $thread %p has been corrupted.\n StackPointer too small.\n", thrd );
    301         /* paranoid */ verify( ! __preemption_enabled() );
    302 
    303         /* paranoid */ verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this );
    304         /* paranoid */ verify( thrd->state == Halting );
    305         /* paranoid */ verify( this->recursion == 1 );
    306 
    307         // Leaving a recursion level, decrement the counter
    308         this->recursion -= 1;
    309         this->owner = 0p;
    310 
    311         // Fetch the next thread, can be null
    312         $thread * new_owner = next_thread( this );
    313 
    314         // Mark the state as fully halted
    315         thrd->state = Halted;
    316 
    317         // Release the monitor lock
    318         unlock( this->lock );
    319 
    320         // Unpark the next owner if needed
    321         /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this );
    322         /* paranoid */ verify( ! __preemption_enabled() );
    323         /* paranoid */ verify( thrd->state == Halted );
    324         unpark( new_owner );
     225
     226                //We need to wake-up the thread
     227                WakeThread( new_owner );
     228        }
     229
     230        // Leave single monitor for the last time
     231        void __leave_dtor_monitor_desc( monitor_desc * this ) {
     232                __cfaabi_dbg_debug_do(
     233                        if( TL_GET( this_thread ) != this->owner ) {
     234                                abort( "Destroyed monitor %p has inconsistent owner, expected %p got %p.\n", this, TL_GET( this_thread ), this->owner);
     235                        }
     236                        if( this->recursion != 1 ) {
     237                                abort( "Destroyed monitor %p has %d outstanding nested calls.\n", this, this->recursion - 1);
     238                        }
     239                )
     240        }
     241
     242        // Leave the thread monitor
     243        // last routine called by a thread.
     244        // Should never return
     245        void __leave_thread_monitor() {
     246                thread_desc * thrd = TL_GET( this_thread );
     247                monitor_desc * this = &thrd->self_mon;
     248
     249                // Lock the monitor now
     250                lock( this->lock __cfaabi_dbg_ctx2 );
     251
     252                disable_interrupts();
     253
     254                thrd->self_cor.state = Halted;
     255
     256                verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this );
     257
     258                // Leaving a recursion level, decrement the counter
     259                this->recursion -= 1;
     260
     261                // If we haven't left the last level of recursion
     262                // it must mean there is an error
     263                if( this->recursion != 0) { abort( "Thread internal monitor has unbalanced recursion" ); }
     264
     265                // Fetch the next thread, can be null
     266                thread_desc * new_owner = next_thread( this );
     267
     268                // Leave the thread, this will unlock the spinlock
     269                // Use leave thread instead of BlockInternal which is
     270                // specialized for this case and supports null new_owner
     271                LeaveThread( &this->lock, new_owner );
     272
     273                // Control flow should never reach here!
     274        }
    325275}
    326276
     
    329279static inline void enter( __monitor_group_t monitors ) {
    330280        for( __lock_size_t i = 0; i < monitors.size; i++) {
    331                 __enter( monitors[i], monitors );
     281                __enter_monitor_desc( monitors[i], monitors );
    332282        }
    333283}
     
    335285// Leave multiple monitor
    336286// relies on the monitor array being sorted
    337 static inline void leave($monitor * monitors [], __lock_size_t count) {
     287static inline void leave(monitor_desc * monitors [], __lock_size_t count) {
    338288        for( __lock_size_t i = count - 1; i >= 0; i--) {
    339                 __leave( monitors[i] );
     289                __leave_monitor_desc( monitors[i] );
    340290        }
    341291}
     
    343293// Ctor for monitor guard
    344294// Sorts monitors before entering
    345 void ?{}( monitor_guard_t & this, $monitor * m [], __lock_size_t count, fptr_t func ) {
    346         $thread * thrd = active_thread();
     295void ?{}( monitor_guard_t & this, monitor_desc * m [], __lock_size_t count, fptr_t func ) {
     296        thread_desc * thrd = TL_GET( this_thread );
    347297
    348298        // Store current array
     
    379329
    380330        // Restore thread context
    381         active_thread()->monitors = this.prev;
     331        TL_GET( this_thread )->monitors = this.prev;
    382332}
    383333
    384334// Ctor for monitor guard
    385335// Sorts monitors before entering
    386 void ?{}( monitor_dtor_guard_t & this, $monitor * m [], fptr_t func, bool join ) {
     336void ?{}( monitor_dtor_guard_t & this, monitor_desc * m [], fptr_t func ) {
    387337        // optimization
    388         $thread * thrd = active_thread();
     338        thread_desc * thrd = TL_GET( this_thread );
    389339
    390340        // Store current array
     
    394344        this.prev = thrd->monitors;
    395345
    396         // Save whether we are in a join or not
    397         this.join = join;
    398 
    399346        // Update thread context (needed for conditions)
    400347        (thrd->monitors){m, 1, func};
    401348
    402         __dtor_enter( this.m, func, join );
     349        __enter_monitor_dtor( this.m, func );
    403350}
    404351
     
    406353void ^?{}( monitor_dtor_guard_t & this ) {
    407354        // Leave the monitors in order
    408         __dtor_leave( this.m, this.join );
     355        __leave_dtor_monitor_desc( this.m );
    409356
    410357        // Restore thread context
    411         active_thread()->monitors = this.prev;
     358        TL_GET( this_thread )->monitors = this.prev;
    412359}
    413360
    414361//-----------------------------------------------------------------------------
    415362// Internal scheduling types
    416 void ?{}(__condition_node_t & this, $thread * waiting_thread, __lock_size_t count, uintptr_t user_info ) {
     363void ?{}(__condition_node_t & this, thread_desc * waiting_thread, __lock_size_t count, uintptr_t user_info ) {
    417364        this.waiting_thread = waiting_thread;
    418365        this.count = count;
     
    428375}
    429376
    430 void ?{}(__condition_criterion_t & this, $monitor * target, __condition_node_t & owner ) {
     377void ?{}(__condition_criterion_t & this, monitor_desc * target, __condition_node_t & owner ) {
    431378        this.ready  = false;
    432379        this.target = target;
     
    449396
    450397        // Create the node specific to this wait operation
    451         wait_ctx( active_thread(), user_info );
     398        wait_ctx( TL_GET( this_thread ), user_info );
    452399
    453400        // Append the current wait operation to the ones already queued on the condition
    454401        // We don't need locks for that since conditions must always be waited on inside monitor mutual exclusion
    455         /* paranoid */ verify( waiter.next == 0p );
    456402        append( this.blocked, &waiter );
    457         /* paranoid */ verify( waiter.next == 1p );
    458403
    459404        // Lock all monitors (aggregates the locks as well)
     
    462407        // Find the next thread(s) to run
    463408        __lock_size_t thread_count = 0;
    464         $thread * threads[ count ];
     409        thread_desc * threads[ count ];
    465410        __builtin_memset( threads, 0, sizeof( threads ) );
    466411
     
    470415        // Remove any duplicate threads
    471416        for( __lock_size_t i = 0; i < count; i++) {
    472                 $thread * new_owner = next_thread( monitors[i] );
     417                thread_desc * new_owner = next_thread( monitors[i] );
    473418                insert_unique( threads, thread_count, new_owner );
    474419        }
    475420
    476         // Unlock the locks, we don't need them anymore
    477         for(int i = 0; i < count; i++) {
    478                 unlock( *locks[i] );
    479         }
    480 
    481         // Wake the threads
    482         for(int i = 0; i < thread_count; i++) {
    483                 unpark( threads[i] );
    484         }
    485 
    486421        // Everything is ready to go to sleep
    487         park();
     422        BlockInternal( locks, count, threads, thread_count );
    488423
    489424        // We are back, restore the owners and recursions
     
    500435        //Some more checking in debug
    501436        __cfaabi_dbg_debug_do(
    502                 $thread * this_thrd = active_thread();
     437                thread_desc * this_thrd = TL_GET( this_thread );
    503438                if ( this.monitor_count != this_thrd->monitors.size ) {
    504439                        abort( "Signal on condition %p made with different number of monitor(s), expected %zi got %zi", &this, this.monitor_count, this_thrd->monitors.size );
     
    548483
    549484        // Create the node specific to this wait operation
    550         wait_ctx_primed( active_thread(), 0 )
     485        wait_ctx_primed( kernelTLS.this_thread, 0 )
    551486
    552487        //save contexts
     
    554489
    555490        //Find the thread to run
    556         $thread * signallee = pop_head( this.blocked )->waiting_thread;
    557         __set_owner( monitors, count, signallee );
     491        thread_desc * signallee = pop_head( this.blocked )->waiting_thread;
     492        set_owner( monitors, count, signallee );
    558493
    559494        __cfaabi_dbg_print_buffer_decl( "Kernel : signal_block condition %p (s: %p)\n", &this, signallee );
    560495
    561         // unlock all the monitors
    562         unlock_all( locks, count );
    563 
    564         // unpark the thread we signalled
    565         unpark( signallee );
    566 
    567496        //Everything is ready to go to sleep
    568         park();
     497        BlockInternal( locks, count, &signallee, 1 );
    569498
    570499
     
    607536        // Create one!
    608537        __lock_size_t max = count_max( mask );
    609         $monitor * mon_storage[max];
     538        monitor_desc * mon_storage[max];
    610539        __builtin_memset( mon_storage, 0, sizeof( mon_storage ) );
    611540        __lock_size_t actual_count = aggregate( mon_storage, mask );
     
    625554        {
    626555                // Check if the entry queue
    627                 $thread * next; int index;
     556                thread_desc * next; int index;
    628557                [next, index] = search_entry_queue( mask, monitors, count );
    629558
     
    635564                                verifyf( accepted.size == 1,  "ERROR: Accepted dtor has more than 1 mutex parameter." );
    636565
    637                                 $monitor * mon2dtor = accepted[0];
     566                                monitor_desc * mon2dtor = accepted[0];
    638567                                verifyf( mon2dtor->dtor_node, "ERROR: Accepted monitor has no dtor_node." );
    639568
     
    647576
    648577                                // Create the node specific to this wait operation
    649                                 wait_ctx_primed( active_thread(), 0 );
     578                                wait_ctx_primed( kernelTLS.this_thread, 0 );
    650579
    651580                                // Save monitor states
     
    661590
    662591                                // Set the owners to be the next thread
    663                                 __set_owner( monitors, count, next );
    664 
    665                                 // unlock all the monitors
    666                                 unlock_all( locks, count );
    667 
    668                                 // unpark the thread we signalled
    669                                 unpark( next );
    670 
    671                                 //Everything is ready to go to sleep
    672                                 park();
     592                                set_owner( monitors, count, next );
     593
     594                                // Everything is ready to go to sleep
     595                                BlockInternal( locks, count, &next, 1 );
    673596
    674597                                // We are back, restore the owners and recursions
     
    699622
    700623        // Create the node specific to this wait operation
    701         wait_ctx_primed( active_thread(), 0 );
     624        wait_ctx_primed( kernelTLS.this_thread, 0 );
    702625
    703626        monitor_save;
     
    705628
    706629        for( __lock_size_t i = 0; i < count; i++) {
    707                 verify( monitors[i]->owner == active_thread() );
    708         }
    709 
    710         // unlock all the monitors
    711         unlock_all( locks, count );
     630                verify( monitors[i]->owner == kernelTLS.this_thread );
     631        }
    712632
    713633        //Everything is ready to go to sleep
    714         park();
     634        BlockInternal( locks, count );
    715635
    716636
     
    729649// Utilities
    730650
    731 static inline void __set_owner( $monitor * this, $thread * owner ) {
    732         /* paranoid */ verify( this->lock.lock );
     651static inline void set_owner( monitor_desc * this, thread_desc * owner ) {
     652        // __cfaabi_dbg_print_safe( "Kernal :   Setting owner of %p to %p ( was %p)\n", this, owner, this->owner );
    733653
    734654        //Pass the monitor appropriately
     
    739659}
    740660
    741 static inline void __set_owner( $monitor * monitors [], __lock_size_t count, $thread * owner ) {
    742         /* paranoid */ verify ( monitors[0]->lock.lock );
    743         /* paranoid */ verifyf( monitors[0]->owner == active_thread(), "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), monitors[0]->owner, monitors[0]->recursion, monitors[0] );
    744         monitors[0]->owner        = owner;
    745         monitors[0]->recursion    = 1;
     661static inline void set_owner( monitor_desc * monitors [], __lock_size_t count, thread_desc * owner ) {
     662        monitors[0]->owner     = owner;
     663        monitors[0]->recursion = 1;
    746664        for( __lock_size_t i = 1; i < count; i++ ) {
    747                 /* paranoid */ verify ( monitors[i]->lock.lock );
    748                 /* paranoid */ verifyf( monitors[i]->owner == active_thread(), "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), monitors[i]->owner, monitors[i]->recursion, monitors[i] );
    749                 monitors[i]->owner        = owner;
    750                 monitors[i]->recursion    = 0;
    751         }
    752 }
    753 
    754 static inline void set_mask( $monitor * storage [], __lock_size_t count, const __waitfor_mask_t & mask ) {
     665                monitors[i]->owner     = owner;
     666                monitors[i]->recursion = 0;
     667        }
     668}
     669
     670static inline void set_mask( monitor_desc * storage [], __lock_size_t count, const __waitfor_mask_t & mask ) {
    755671        for( __lock_size_t i = 0; i < count; i++) {
    756672                storage[i]->mask = mask;
     
    758674}
    759675
    760 static inline void reset_mask( $monitor * this ) {
     676static inline void reset_mask( monitor_desc * this ) {
    761677        this->mask.accepted = 0p;
    762678        this->mask.data = 0p;
     
    764680}
    765681
    766 static inline $thread * next_thread( $monitor * this ) {
     682static inline thread_desc * next_thread( monitor_desc * this ) {
    767683        //Check the signaller stack
    768684        __cfaabi_dbg_print_safe( "Kernel :  mon %p AS-stack top %p\n", this, this->signal_stack.top);
     
    772688                //regardless of if we are ready to baton pass,
    773689                //we need to set the monitor as in use
    774                 /* paranoid */ verifyf( !this->owner || active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    775                 __set_owner( this,  urgent->owner->waiting_thread );
     690                set_owner( this,  urgent->owner->waiting_thread );
    776691
    777692                return check_condition( urgent );
     
    780695        // No signaller thread
    781696        // Get the next thread in the entry_queue
    782         $thread * new_owner = pop_head( this->entry_queue );
    783         /* paranoid */ verifyf( !this->owner || active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this );
    784         /* paranoid */ verify( !new_owner || new_owner->link.next == 0p );
    785         __set_owner( this, new_owner );
     697        thread_desc * new_owner = pop_head( this->entry_queue );
     698        set_owner( this, new_owner );
    786699
    787700        return new_owner;
    788701}
    789702
    790 static inline bool is_accepted( $monitor * this, const __monitor_group_t & group ) {
     703static inline bool is_accepted( monitor_desc * this, const __monitor_group_t & group ) {
    791704        __acceptable_t * it = this->mask.data; // Optim
    792705        __lock_size_t count = this->mask.size;
     
    810723}
    811724
    812 static inline void init( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
     725static inline void init( __lock_size_t count, monitor_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
    813726        for( __lock_size_t i = 0; i < count; i++) {
    814727                (criteria[i]){ monitors[i], waiter };
     
    818731}
    819732
    820 static inline void init_push( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
     733static inline void init_push( __lock_size_t count, monitor_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
    821734        for( __lock_size_t i = 0; i < count; i++) {
    822735                (criteria[i]){ monitors[i], waiter };
     
    834747}
    835748
    836 static inline void lock_all( $monitor * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count ) {
     749static inline void lock_all( monitor_desc * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count ) {
    837750        for( __lock_size_t i = 0; i < count; i++ ) {
    838751                __spinlock_t * l = &source[i]->lock;
     
    848761}
    849762
    850 static inline void unlock_all( $monitor * locks [], __lock_size_t count ) {
     763static inline void unlock_all( monitor_desc * locks [], __lock_size_t count ) {
    851764        for( __lock_size_t i = 0; i < count; i++ ) {
    852765                unlock( locks[i]->lock );
     
    855768
    856769static inline void save(
    857         $monitor * ctx [],
     770        monitor_desc * ctx [],
    858771        __lock_size_t count,
    859772        __attribute((unused)) __spinlock_t * locks [],
     
    868781
    869782static inline void restore(
    870         $monitor * ctx [],
     783        monitor_desc * ctx [],
    871784        __lock_size_t count,
    872785        __spinlock_t * locks [],
     
    886799// 2 - Checks if all the monitors are ready to run
    887800//     if so return the thread to run
    888 static inline $thread * check_condition( __condition_criterion_t * target ) {
     801static inline thread_desc * check_condition( __condition_criterion_t * target ) {
    889802        __condition_node_t * node = target->owner;
    890803        unsigned short count = node->count;
     
    904817        }
    905818
    906         __cfaabi_dbg_print_safe( "Kernel :  Runing %i (%p)\n", ready2run, ready2run ? (thread*)node->waiting_thread : (thread*)0p );
     819        __cfaabi_dbg_print_safe( "Kernel :  Runing %i (%p)\n", ready2run, ready2run ? node->waiting_thread : 0p );
    907820        return ready2run ? node->waiting_thread : 0p;
    908821}
    909822
    910823static inline void brand_condition( condition & this ) {
    911         $thread * thrd = active_thread();
     824        thread_desc * thrd = TL_GET( this_thread );
    912825        if( !this.monitors ) {
    913826                // __cfaabi_dbg_print_safe( "Branding\n" );
     
    915828                this.monitor_count = thrd->monitors.size;
    916829
    917                 this.monitors = ($monitor **)malloc( this.monitor_count * sizeof( *this.monitors ) );
     830                this.monitors = (monitor_desc **)malloc( this.monitor_count * sizeof( *this.monitors ) );
    918831                for( int i = 0; i < this.monitor_count; i++ ) {
    919832                        this.monitors[i] = thrd->monitors[i];
     
    922835}
    923836
    924 static inline [$thread *, int] search_entry_queue( const __waitfor_mask_t & mask, $monitor * monitors [], __lock_size_t count ) {
    925 
    926         __queue_t($thread) & entry_queue = monitors[0]->entry_queue;
     837static inline [thread_desc *, int] search_entry_queue( const __waitfor_mask_t & mask, monitor_desc * monitors [], __lock_size_t count ) {
     838
     839        __queue_t(thread_desc) & entry_queue = monitors[0]->entry_queue;
    927840
    928841        // For each thread in the entry-queue
    929         for(    $thread ** thrd_it = &entry_queue.head;
    930                 (*thrd_it) != 1p;
    931                 thrd_it = &(*thrd_it)->link.next
     842        for(    thread_desc ** thrd_it = &entry_queue.head;
     843                *thrd_it;
     844                thrd_it = &(*thrd_it)->next
    932845        ) {
    933846                // For each acceptable check if it matches
     
    971884}
    972885
    973 static inline __lock_size_t aggregate( $monitor * storage [], const __waitfor_mask_t & mask ) {
     886static inline __lock_size_t aggregate( monitor_desc * storage [], const __waitfor_mask_t & mask ) {
    974887        __lock_size_t size = 0;
    975888        for( __lock_size_t i = 0; i < mask.size; i++ ) {
  • libcfa/src/concurrency/monitor.hfa

    reef8dfb rbdfc032  
    2323
    2424trait is_monitor(dtype T) {
    25         $monitor * get_monitor( T & );
     25        monitor_desc * get_monitor( T & );
    2626        void ^?{}( T & mutex );
    2727};
    2828
    29 static inline void ?{}($monitor & this) with( this ) {
     29static inline void ?{}(monitor_desc & this) with( this ) {
    3030        lock{};
    3131        entry_queue{};
     
    3939}
    4040
    41 static inline void ^?{}($monitor & ) {}
     41static inline void ^?{}(monitor_desc & ) {}
    4242
    4343struct monitor_guard_t {
    44         $monitor **     m;
     44        monitor_desc **         m;
    4545        __lock_size_t           count;
    4646        __monitor_group_t prev;
    4747};
    4848
    49 void ?{}( monitor_guard_t & this, $monitor ** m, __lock_size_t count, void (*func)() );
     49void ?{}( monitor_guard_t & this, monitor_desc ** m, __lock_size_t count, void (*func)() );
    5050void ^?{}( monitor_guard_t & this );
    5151
    5252struct monitor_dtor_guard_t {
    53         $monitor *    m;
     53        monitor_desc *    m;
    5454        __monitor_group_t prev;
    55         bool join;
    5655};
    5756
    58 void ?{}( monitor_dtor_guard_t & this, $monitor ** m, void (*func)(), bool join );
     57void ?{}( monitor_dtor_guard_t & this, monitor_desc ** m, void (*func)() );
    5958void ^?{}( monitor_dtor_guard_t & this );
    6059
     
    7372
    7473        // The monitor this criterion concerns
    75         $monitor * target;
     74        monitor_desc * target;
    7675
    7776        // The parent node to which this criterion belongs
     
    8887struct __condition_node_t {
    8988        // Thread that needs to be woken when all criteria are met
    90         $thread * waiting_thread;
     89        thread_desc * waiting_thread;
    9190
    9291        // Array of criteria (Criterions are contiguous in memory)
     
    107106}
    108107
    109 void ?{}(__condition_node_t & this, $thread * waiting_thread, __lock_size_t count, uintptr_t user_info );
     108void ?{}(__condition_node_t & this, thread_desc * waiting_thread, __lock_size_t count, uintptr_t user_info );
    110109void ?{}(__condition_criterion_t & this );
    111 void ?{}(__condition_criterion_t & this, $monitor * target, __condition_node_t * owner );
     110void ?{}(__condition_criterion_t & this, monitor_desc * target, __condition_node_t * owner );
    112111
    113112struct condition {
     
    116115
    117116        // Array of monitor pointers (Monitors are NOT contiguous in memory)
    118         $monitor ** monitors;
     117        monitor_desc ** monitors;
    119118
    120119        // Number of monitors in the array
     
    132131
    133132              void wait        ( condition & this, uintptr_t user_info = 0 );
    134 static inline bool is_empty    ( condition & this ) { return this.blocked.head == 1p; }
    135133              bool signal      ( condition & this );
    136134              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; }
     135static inline bool is_empty    ( condition & this ) { return !this.blocked.head; }
    138136         uintptr_t front       ( condition & this );
    139137
  • libcfa/src/concurrency/mutex.cfa

    reef8dfb rbdfc032  
    3030        this.lock{};
    3131        this.blocked_threads{};
    32         this.is_locked = false;
    3332}
    3433
     
    4039        lock( lock __cfaabi_dbg_ctx2 );
    4140        if( is_locked ) {
    42                 append( blocked_threads, active_thread() );
    43                 unlock( lock );
    44                 park();
     41                append( blocked_threads, kernelTLS.this_thread );
     42                BlockInternal( &lock );
    4543        }
    4644        else {
     
    6462        lock( this.lock __cfaabi_dbg_ctx2 );
    6563        this.is_locked = (this.blocked_threads != 0);
    66         unpark(
     64        WakeThread(
    6765                pop_head( this.blocked_threads )
    6866        );
     
    8684        lock( lock __cfaabi_dbg_ctx2 );
    8785        if( owner == 0p ) {
    88                 owner = active_thread();
     86                owner = kernelTLS.this_thread;
    8987                recursion_count = 1;
    9088                unlock( lock );
    9189        }
    92         else if( owner == active_thread() ) {
     90        else if( owner == kernelTLS.this_thread ) {
    9391                recursion_count++;
    9492                unlock( lock );
    9593        }
    9694        else {
    97                 append( blocked_threads, active_thread() );
    98                 unlock( lock );
    99                 park();
     95                append( blocked_threads, kernelTLS.this_thread );
     96                BlockInternal( &lock );
    10097        }
    10198}
     
    105102        lock( lock __cfaabi_dbg_ctx2 );
    106103        if( owner == 0p ) {
    107                 owner = active_thread();
     104                owner = kernelTLS.this_thread;
    108105                recursion_count = 1;
    109106                ret = true;
    110107        }
    111         else if( owner == active_thread() ) {
     108        else if( owner == kernelTLS.this_thread ) {
    112109                recursion_count++;
    113110                ret = true;
     
    121118        recursion_count--;
    122119        if( recursion_count == 0 ) {
    123                 $thread * thrd = pop_head( blocked_threads );
     120                thread_desc * thrd = pop_head( blocked_threads );
    124121                owner = thrd;
    125122                recursion_count = (thrd ? 1 : 0);
    126                 unpark( thrd );
     123                WakeThread( thrd );
    127124        }
    128125        unlock( lock );
     
    141138void notify_one(condition_variable & this) with(this) {
    142139        lock( lock __cfaabi_dbg_ctx2 );
    143         unpark(
     140        WakeThread(
    144141                pop_head( this.blocked_threads )
    145142        );
     
    150147        lock( lock __cfaabi_dbg_ctx2 );
    151148        while(this.blocked_threads) {
    152                 unpark(
     149                WakeThread(
    153150                        pop_head( this.blocked_threads )
    154151                );
     
    159156void wait(condition_variable & this) {
    160157        lock( this.lock __cfaabi_dbg_ctx2 );
    161         append( this.blocked_threads, active_thread() );
    162         unlock( this.lock );
    163         park();
     158        append( this.blocked_threads, kernelTLS.this_thread );
     159        BlockInternal( &this.lock );
    164160}
    165161
     
    167163void wait(condition_variable & this, L & l) {
    168164        lock( this.lock __cfaabi_dbg_ctx2 );
    169         append( this.blocked_threads, active_thread() );
    170         unlock(l);
    171         unlock(this.lock);
    172         park();
     165        append( this.blocked_threads, kernelTLS.this_thread );
     166        void __unlock(void) {
     167                unlock(l);
     168                unlock(this.lock);
     169        }
     170        BlockInternal( __unlock );
    173171        lock(l);
    174172}
  • libcfa/src/concurrency/mutex.hfa

    reef8dfb rbdfc032  
    3636
    3737        // List of blocked threads
    38         __queue_t(struct $thread) blocked_threads;
     38        __queue_t(struct thread_desc) blocked_threads;
    3939
    4040        // Locked flag
     
    5555
    5656        // List of blocked threads
    57         __queue_t(struct $thread) blocked_threads;
     57        __queue_t(struct thread_desc) blocked_threads;
    5858
    5959        // Current thread owning the lock
    60         struct $thread * owner;
     60        struct thread_desc * owner;
    6161
    6262        // Number of recursion level
     
    8383
    8484        // List of blocked threads
    85         __queue_t(struct $thread) blocked_threads;
     85        __queue_t(struct thread_desc) blocked_threads;
    8686};
    8787
  • libcfa/src/concurrency/preemption.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Mon Jun 5 14:20:42 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Nov  6 07:42:13 2020
    13 // Update Count     : 54
     12// Last Modified On : Thu Dec  5 16:34:05 2019
     13// Update Count     : 43
    1414//
    1515
     
    1919#include <assert.h>
    2020
     21extern "C" {
    2122#include <errno.h>
    2223#include <stdio.h>
     
    2425#include <unistd.h>
    2526#include <limits.h>                                                                             // PTHREAD_STACK_MIN
     27}
    2628
    2729#include "bits/signal.hfa"
    28 #include "kernel_private.hfa"
    2930
    3031#if !defined(__CFA_DEFAULT_PREEMPTION__)
     
    3839// FwdDeclarations : timeout handlers
    3940static void preempt( processor   * this );
    40 static void timeout( $thread * this );
     41static void timeout( thread_desc * this );
    4142
    4243// FwdDeclarations : Signal handlers
    4344static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ );
    44 static void sigHandler_alarm    ( __CFA_SIGPARMS__ );
    4545static void sigHandler_segv     ( __CFA_SIGPARMS__ );
    4646static void sigHandler_ill      ( __CFA_SIGPARMS__ );
     
    5656#elif defined( __x86_64 )
    5757#define CFA_REG_IP gregs[REG_RIP]
    58 #elif defined( __arm__ )
     58#elif defined( __ARM_ARCH )
    5959#define CFA_REG_IP arm_pc
    60 #elif defined( __aarch64__ )
    61 #define CFA_REG_IP pc
    6260#else
    63 #error unsupported hardware architecture
     61#error unknown hardware architecture
    6462#endif
    6563
     
    8583// Get next expired node
    8684static inline alarm_node_t * get_expired( alarm_list_t * alarms, Time currtime ) {
    87         if( ! & (*alarms)`first ) return 0p;                                            // If no alarms return null
    88         if( (*alarms)`first.alarm >= currtime ) return 0p;      // If alarms head not expired return null
     85        if( !alarms->head ) return 0p;                                          // If no alarms return null
     86        if( alarms->head->alarm >= currtime ) return 0p;        // If alarms head not expired return null
    8987        return pop(alarms);                                                                     // Otherwise just pop head
    9088}
    9189
    9290// Tick one frame of the Discrete Event Simulation for alarms
    93 static void tick_preemption(void) {
     91static void tick_preemption() {
    9492        alarm_node_t * node = 0p;                                                       // Used in the while loop but cannot be declared in the while condition
    9593        alarm_list_t * alarms = &event_kernel->alarms;          // Local copy for ease of reading
     
    9997        while( node = get_expired( alarms, currtime ) ) {
    10098                // __cfaabi_dbg_print_buffer_decl( " KERNEL: preemption tick.\n" );
     99
     100                // Check if this is a kernel
     101                if( node->kernel_alarm ) {
     102                        preempt( node->proc );
     103                }
     104                else {
     105                        timeout( node->thrd );
     106                }
     107
     108                // Check if this is a periodic alarm
    101109                Duration period = node->period;
    102                 if( period == 0) {
    103                         node->set = false;                  // Node is one-shot, just mark it as not pending
    104                 }
    105 
    106                 // Check if this is a kernel
    107                 if( node->type == Kernel ) {
    108                         preempt( node->proc );
    109                 }
    110                 else if( node->type == User ) {
    111                         timeout( node->thrd );
    112                 }
    113                 else {
    114                         node->callback(*node);
    115                 }
    116 
    117                 // Check if this is a periodic alarm
    118110                if( period > 0 ) {
    119111                        // __cfaabi_dbg_print_buffer_local( " KERNEL: alarm period is %lu.\n", period.tv );
     
    121113                        insert( alarms, node );             // Reinsert the node for the next time it triggers
    122114                }
     115                else {
     116                        node->set = false;                  // Node is one-shot, just mark it as not pending
     117                }
    123118        }
    124119
    125120        // If there are still alarms pending, reset the timer
    126         if( & (*alarms)`first ) {
    127                 __cfadbg_print_buffer_decl(preemption, " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);
    128                 Duration delta = (*alarms)`first.alarm - currtime;
    129                 Duration capped = max(delta, 50`us);
     121        if( alarms->head ) {
     122                __cfaabi_dbg_print_buffer_decl( " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);
     123                Duration delta = alarms->head->alarm - currtime;
     124                Duration caped = max(delta, 50`us);
    130125                // itimerval tim  = { caped };
    131126                // __cfaabi_dbg_print_buffer_local( "    Values are %lu, %lu, %lu %lu.\n", delta.tv, caped.tv, tim.it_value.tv_sec, tim.it_value.tv_usec);
    132127
    133                 __kernel_set_timer( capped );
     128                __kernel_set_timer( caped );
    134129        }
    135130}
     
    163158// Kernel Signal Tools
    164159//=============================================================================================
    165 // In a user-level threading system, there are handful of thread-local variables where this problem occurs on the ARM.
    166 //
    167 // For each kernel thread running user-level threads, there is a flag variable to indicate if interrupts are
    168 // enabled/disabled for that kernel thread. Therefore, this variable is made thread local.
    169 //
    170 // For example, this code fragment sets the state of the "interrupt" variable in thread-local memory.
    171 //
    172 // _Thread_local volatile int interrupts;
    173 // int main() {
    174 //     interrupts = 0; // disable interrupts }
    175 //
    176 // which generates the following code on the ARM
    177 //
    178 // (gdb) disassemble main
    179 // Dump of assembler code for function main:
    180 //    0x0000000000000610 <+0>:  mrs     x1, tpidr_el0
    181 //    0x0000000000000614 <+4>:  mov     w0, #0x0                        // #0
    182 //    0x0000000000000618 <+8>:  add     x1, x1, #0x0, lsl #12
    183 //    0x000000000000061c <+12>: add     x1, x1, #0x10
    184 //    0x0000000000000620 <+16>: str     wzr, [x1]
    185 //    0x0000000000000624 <+20>: ret
    186 //
    187 // The mrs moves a pointer from coprocessor register tpidr_el0 into register x1.  Register w0 is set to 0. The two adds
    188 // increase the TLS pointer with the displacement (offset) 0x10, which is the location in the TSL of variable
    189 // "interrupts".  Finally, 0 is stored into "interrupts" through the pointer in register x1 that points into the
    190 // TSL. Now once x1 has the pointer to the location of the TSL for kernel thread N, it can be be preempted at a
    191 // user-level and the user thread is put on the user-level ready-queue. When the preempted thread gets to the front of
    192 // the user-level ready-queue it is run on kernel thread M. It now stores 0 into "interrupts" back on kernel thread N,
    193 // turning off interrupt on the wrong kernel thread.
    194 //
    195 // On the x86, the following code is generated for the same code fragment.
    196 //
    197 // (gdb) disassemble main
    198 // Dump of assembler code for function main:
    199 //    0x0000000000400420 <+0>:  movl   $0x0,%fs:0xfffffffffffffffc
    200 //    0x000000000040042c <+12>: xor    %eax,%eax
    201 //    0x000000000040042e <+14>: retq
    202 //
    203 // and there is base-displacement addressing used to atomically reset variable "interrupts" off of the TSL pointer in
    204 // register "fs".
    205 //
    206 // Hence, the ARM has base-displacement address for the general purpose registers, BUT not to the coprocessor
    207 // registers. As a result, generating the address for the write into variable "interrupts" is no longer atomic.
    208 //
    209 // Note this problem does NOT occur when just using multiple kernel threads because the preemption ALWAYS restarts the
    210 // thread on the same kernel thread.
    211 //
    212 // The obvious question is why does ARM use a coprocessor register to store the TSL pointer given that coprocessor
    213 // registers are second-class registers with respect to the instruction set. One possible answer is that they did not
    214 // want to dedicate one of the general registers to hold the TLS pointer and there was a free coprocessor register
    215 // available.
    216 
    217 //-----------------------------------------------------------------------------
    218 // Some assembly required
    219 #define __cfaasm_label(label, when) when: asm volatile goto(".global __cfaasm_" #label "_" #when "\n" "__cfaasm_" #label "_" #when ":":::"memory":when)
    220 
    221 //----------
    222 // special case for preemption since used often
    223 bool __preemption_enabled() {
    224         // create a assembler label before
    225         // marked as clobber all to avoid movement
    226         __cfaasm_label(check, before);
    227 
    228         // access tls as normal
    229         bool enabled = __cfaabi_tls.preemption_state.enabled;
    230 
    231         // create a assembler label after
    232         // marked as clobber all to avoid movement
    233         __cfaasm_label(check, after);
    234         return enabled;
    235 }
    236 
    237 struct asm_region {
    238         void * before;
    239         void * after;
    240 };
    241 
    242 static inline bool __cfaasm_in( void * ip, struct asm_region & region ) {
    243         return ip >= region.before && ip <= region.after;
    244 }
    245 
    246 
    247 //----------
    248 // Get data from the TLS block
    249 // struct asm_region __cfaasm_get;
    250 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__)); //no inline to avoid problems
    251 uintptr_t __cfatls_get( unsigned long int offset ) {
    252         // create a assembler label before
    253         // marked as clobber all to avoid movement
    254         __cfaasm_label(get, before);
    255 
    256         // access tls as normal (except for pointer arithmetic)
    257         uintptr_t val = *(uintptr_t*)((uintptr_t)&__cfaabi_tls + offset);
    258 
    259         // create a assembler label after
    260         // marked as clobber all to avoid movement
    261         __cfaasm_label(get, after);
    262         return val;
    263 }
     160
     161__cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; )
    264162
    265163extern "C" {
    266164        // Disable interrupts by incrementing the counter
    267165        void disable_interrupts() {
    268                 // create a assembler label before
    269                 // marked as clobber all to avoid movement
    270                 __cfaasm_label(dsable, before);
    271 
    272                 with( __cfaabi_tls.preemption_state ) {
     166                with( kernelTLS.preemption_state ) {
    273167                        #if GCC_VERSION > 50000
    274168                        static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
     
    287181                        verify( new_val < 65_000u );              // If this triggers someone is disabling interrupts without enabling them
    288182                }
    289 
    290                 // create a assembler label after
    291                 // marked as clobber all to avoid movement
    292                 __cfaasm_label(dsable, after);
    293 
    294183        }
    295184
    296185        // Enable interrupts by decrementing the counter
    297         // If counter reaches 0, execute any pending __cfactx_switch
     186        // If counter reaches 0, execute any pending CtxSwitch
    298187        void enable_interrupts( __cfaabi_dbg_ctx_param ) {
    299                 // Cache the processor now since interrupts can start happening after the atomic store
    300                 processor   * proc = __cfaabi_tls.this_processor;
    301                 /* paranoid */ verify( proc );
    302 
    303                 with( __cfaabi_tls.preemption_state ){
     188                processor   * proc = kernelTLS.this_processor; // Cache the processor now since interrupts can start happening after the atomic store
     189                thread_desc * thrd = kernelTLS.this_thread;       // Cache the thread now since interrupts can start happening after the atomic store
     190
     191                with( kernelTLS.preemption_state ){
    304192                        unsigned short prev = disable_count;
    305193                        disable_count -= 1;
    306 
    307                         // If this triggers someone is enabled already enabled interruptsverify( prev != 0u );
    308                         /* paranoid */ verify( prev != 0u );
     194                        verify( prev != 0u );                     // If this triggers someone is enabled already enabled interruptsverify( prev != 0u );
    309195
    310196                        // Check if we need to prempt the thread because an interrupt was missed
    311197                        if( prev == 1 ) {
    312198                                #if GCC_VERSION > 50000
    313                                         static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
     199                                static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
    314200                                #endif
    315201
     
    323209                                if( proc->pending_preemption ) {
    324210                                        proc->pending_preemption = false;
    325                                         force_yield( __POLL_PREEMPTION );
     211                                        BlockInternal( thrd );
    326212                                }
    327213                        }
     
    333219
    334220        // Disable interrupts by incrementint the counter
    335         // Don't execute any pending __cfactx_switch even if counter reaches 0
     221        // Don't execute any pending CtxSwitch even if counter reaches 0
    336222        void enable_interrupts_noPoll() {
    337                 unsigned short prev = __cfaabi_tls.preemption_state.disable_count;
    338                 __cfaabi_tls.preemption_state.disable_count -= 1;
    339                 // If this triggers someone is enabled already enabled interrupts
    340                 /* paranoid */ verifyf( prev != 0u, "Incremented from %u\n", prev );
     223                unsigned short prev = kernelTLS.preemption_state.disable_count;
     224                kernelTLS.preemption_state.disable_count -= 1;
     225                verifyf( prev != 0u, "Incremented from %u\n", prev );                     // If this triggers someone is enabled already enabled interrupts
    341226                if( prev == 1 ) {
    342227                        #if GCC_VERSION > 50000
    343                                 static_assert(__atomic_always_lock_free(sizeof(__cfaabi_tls.preemption_state.enabled), &__cfaabi_tls.preemption_state.enabled), "Must be lock-free");
     228                        static_assert(__atomic_always_lock_free(sizeof(kernelTLS.preemption_state.enabled), &kernelTLS.preemption_state.enabled), "Must be lock-free");
    344229                        #endif
    345230                        // Set enabled flag to true
    346231                        // should be atomic to avoid preemption in the middle of the operation.
    347232                        // use memory order RELAXED since there is no inter-thread on this variable requirements
    348                         __atomic_store_n(&__cfaabi_tls.preemption_state.enabled, true, __ATOMIC_RELAXED);
     233                        __atomic_store_n(&kernelTLS.preemption_state.enabled, true, __ATOMIC_RELAXED);
    349234
    350235                        // Signal the compiler that a fence is needed but only for signal handlers
     
    353238        }
    354239}
    355 
    356 //-----------------------------------------------------------------------------
    357 // Kernel Signal Debug
    358 void __cfaabi_check_preemption() {
    359         bool ready = __preemption_enabled();
    360         if(!ready) { abort("Preemption should be ready"); }
    361 
    362         __cfaasm_label(debug, before);
    363 
    364                 sigset_t oldset;
    365                 int ret;
    366                 ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
    367                 if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    368 
    369                 ret = sigismember(&oldset, SIGUSR1);
    370                 if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
    371                 if(ret == 1) { abort("ERROR SIGUSR1 is disabled"); }
    372 
    373                 ret = sigismember(&oldset, SIGALRM);
    374                 if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
    375                 if(ret == 0) { abort("ERROR SIGALRM is enabled"); }
    376 
    377                 ret = sigismember(&oldset, SIGTERM);
    378                 if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
    379                 if(ret == 1) { abort("ERROR SIGTERM is disabled"); }
    380 
    381         __cfaasm_label(debug, after);
    382 }
    383 
    384 #ifdef __CFA_WITH_VERIFY__
    385 bool __cfaabi_dbg_in_kernel() {
    386         return !__preemption_enabled();
    387 }
    388 #endif
    389 
    390 #undef __cfaasm_label
    391 
    392 //-----------------------------------------------------------------------------
    393 // Signal handling
    394240
    395241// sigprocmask wrapper : unblock a single signal
     
    411257
    412258        if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
    413                 abort( "internal error, pthread_sigmask" );
     259            abort( "internal error, pthread_sigmask" );
    414260        }
    415261}
     
    422268
    423269// reserved for future use
    424 static void timeout( $thread * this ) {
    425         unpark( this );
    426 }
    427 
    428 //-----------------------------------------------------------------------------
    429 // Some assembly required
    430 #if defined( __i386 )
    431         #ifdef __PIC__
    432                 #define RELOC_PRELUDE( label ) \
    433                         "calll   .Lcfaasm_prelude_" #label "$pb\n\t" \
    434                         ".Lcfaasm_prelude_" #label "$pb:\n\t" \
    435                         "popl    %%eax\n\t" \
    436                         ".Lcfaasm_prelude_" #label "_end:\n\t" \
    437                         "addl    $_GLOBAL_OFFSET_TABLE_+(.Lcfaasm_prelude_" #label "_end-.Lcfaasm_prelude_" #label "$pb), %%eax\n\t"
    438                 #define RELOC_PREFIX ""
    439                 #define RELOC_SUFFIX "@GOT(%%eax)"
    440         #else
    441                 #define RELOC_PREFIX "$"
    442                 #define RELOC_SUFFIX ""
    443         #endif
    444         #define __cfaasm_label( label ) struct asm_region label = \
    445                 ({ \
    446                         struct asm_region region; \
    447                         asm( \
    448                                 RELOC_PRELUDE( label ) \
    449                                 "movl " RELOC_PREFIX "__cfaasm_" #label "_before" RELOC_SUFFIX ", %[vb]\n\t" \
    450                                 "movl " RELOC_PREFIX "__cfaasm_" #label "_after"  RELOC_SUFFIX ", %[va]\n\t" \
    451                                  : [vb]"=r"(region.before), [va]"=r"(region.after) \
    452                         ); \
    453                         region; \
    454                 });
    455 #elif defined( __x86_64 )
    456         #ifdef __PIC__
    457                 #define RELOC_PREFIX ""
    458                 #define RELOC_SUFFIX "@GOTPCREL(%%rip)"
    459         #else
    460                 #define RELOC_PREFIX "$"
    461                 #define RELOC_SUFFIX ""
    462         #endif
    463         #define __cfaasm_label( label ) struct asm_region label = \
    464                 ({ \
    465                         struct asm_region region; \
    466                         asm( \
    467                                 "movq " RELOC_PREFIX "__cfaasm_" #label "_before" RELOC_SUFFIX ", %[vb]\n\t" \
    468                                 "movq " RELOC_PREFIX "__cfaasm_" #label "_after"  RELOC_SUFFIX ", %[va]\n\t" \
    469                                  : [vb]"=r"(region.before), [va]"=r"(region.after) \
    470                         ); \
    471                         region; \
    472                 });
    473 #elif defined( __aarch64__ )
    474         #ifdef __PIC__
    475                 // Note that this works only for gcc
    476                 #define __cfaasm_label( label ) struct asm_region label = \
    477                 ({ \
    478                         struct asm_region region; \
    479                         asm( \
    480                                 "adrp %[vb], _GLOBAL_OFFSET_TABLE_"                              "\n\t" \
    481                                 "ldr  %[vb], [%[vb], #:gotpage_lo15:__cfaasm_" #label "_before]" "\n\t" \
    482                                 "adrp %[va], _GLOBAL_OFFSET_TABLE_"                              "\n\t" \
    483                                 "ldr  %[va], [%[va], #:gotpage_lo15:__cfaasm_" #label "_after]"  "\n\t" \
    484                                  : [vb]"=r"(region.before), [va]"=r"(region.after) \
    485                         ); \
    486                         region; \
    487                 });
    488         #else
    489                 #error this is not the right thing to do
    490                 /*
    491                 #define __cfaasm_label( label ) struct asm_region label = \
    492                 ({ \
    493                         struct asm_region region; \
    494                         asm( \
    495                                 "adrp %[vb], __cfaasm_" #label "_before"              "\n\t" \
    496                                 "add  %[vb], %[vb], :lo12:__cfaasm_" #label "_before" "\n\t" \
    497                                 "adrp %[va], :got:__cfaasm_" #label "_after"          "\n\t" \
    498                                 "add  %[va], %[va], :lo12:__cfaasm_" #label "_after"  "\n\t" \
    499                                  : [vb]"=r"(region.before), [va]"=r"(region.after) \
    500                         ); \
    501                         region; \
    502                 });
    503                 */
    504         #endif
    505 #else
    506         #error unknown hardware architecture
    507 #endif
     270static void timeout( thread_desc * this ) {
     271        //TODO : implement waking threads
     272}
    508273
    509274// KERNEL ONLY
    510 // Check if a __cfactx_switch signal handler shoud defer
     275// Check if a CtxSwitch signal handler shoud defer
    511276// If true  : preemption is safe
    512277// If false : preemption is unsafe and marked as pending
    513 static inline bool preemption_ready( void * ip ) {
    514         // Get all the region for which it is not safe to preempt
    515         __cfaasm_label( get    );
    516         __cfaasm_label( check  );
    517         __cfaasm_label( dsable );
    518         __cfaasm_label( debug  );
    519 
     278static inline bool preemption_ready() {
    520279        // Check if preemption is safe
    521         bool ready = true;
    522         if( __cfaasm_in( ip, get    ) ) { ready = false; goto EXIT; };
    523         if( __cfaasm_in( ip, check  ) ) { ready = false; goto EXIT; };
    524         if( __cfaasm_in( ip, dsable ) ) { ready = false; goto EXIT; };
    525         if( __cfaasm_in( ip, debug  ) ) { ready = false; goto EXIT; };
    526         if( !__cfaabi_tls.preemption_state.enabled) { ready = false; goto EXIT; };
    527         if( __cfaabi_tls.preemption_state.in_progress ) { ready = false; goto EXIT; };
    528 
    529 EXIT:
     280        bool ready = kernelTLS.preemption_state.enabled && ! kernelTLS.preemption_state.in_progress;
     281
    530282        // Adjust the pending flag accordingly
    531         __cfaabi_tls.this_processor->pending_preemption = !ready;
     283        kernelTLS.this_processor->pending_preemption = !ready;
    532284        return ready;
    533285}
     
    539291// Startup routine to activate preemption
    540292// Called from kernel_startup
    541 void __kernel_alarm_startup() {
     293void kernel_start_preemption() {
    542294        __cfaabi_dbg_print_safe( "Kernel : Starting preemption\n" );
    543295
    544296        // Start with preemption disabled until ready
    545         __cfaabi_tls.preemption_state.enabled = false;
    546         __cfaabi_tls.preemption_state.disable_count = 1;
     297        kernelTLS.preemption_state.enabled = false;
     298        kernelTLS.preemption_state.disable_count = 1;
    547299
    548300        // Initialize the event kernel
     
    551303
    552304        // Setup proper signal handlers
    553         __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // __cfactx_switch handler
    554         __cfaabi_sigaction( SIGALRM, sigHandler_alarm    , SA_SIGINFO | SA_RESTART ); // debug handler
     305        __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // CtxSwitch handler
    555306
    556307        signal_block( SIGALRM );
    557308
    558         alarm_stack = __create_pthread( &alarm_thread, alarm_loop, 0p );
     309        alarm_stack = create_pthread( &alarm_thread, alarm_loop, 0p );
    559310}
    560311
    561312// Shutdown routine to deactivate preemption
    562313// Called from kernel_shutdown
    563 void __kernel_alarm_shutdown() {
     314void kernel_stop_preemption() {
    564315        __cfaabi_dbg_print_safe( "Kernel : Preemption stopping\n" );
    565316
     
    575326        // Wait for the preemption thread to finish
    576327
    577         __destroy_pthread( alarm_thread, alarm_stack, 0p );
     328        pthread_join( alarm_thread, 0p );
     329        free( alarm_stack );
    578330
    579331        // Preemption is now fully stopped
     
    601353// Kernel Signal Handlers
    602354//=============================================================================================
    603 __cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; )
    604355
    605356// Context switch signal handler
    606357// Receives SIGUSR1 signal and causes the current thread to yield
    607358static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) {
    608         void * ip = (void *)(cxt->uc_mcontext.CFA_REG_IP);
    609         __cfaabi_dbg_debug_do( last_interrupt = ip; )
     359        __cfaabi_dbg_debug_do( last_interrupt = (void *)(cxt->uc_mcontext.CFA_REG_IP); )
    610360
    611361        // SKULLDUGGERY: if a thread creates a processor and the immediately deletes it,
    612362        // the interrupt that is supposed to force the kernel thread to preempt might arrive
    613         // before the kernel thread has even started running. When that happens, an interrupt
    614         // with a null 'this_processor' will be caught, just ignore it.
    615         if(! __cfaabi_tls.this_processor ) return;
     363        // before the kernel thread has even started running. When that happens an iterrupt
     364        // we a null 'this_processor' will be caught, just ignore it.
     365        if(! kernelTLS.this_processor ) return;
    616366
    617367        choose(sfp->si_value.sival_int) {
    618368                case PREEMPT_NORMAL   : ;// Normal case, nothing to do here
    619                 case PREEMPT_TERMINATE: verify( __atomic_load_n( &__cfaabi_tls.this_processor->do_terminate, __ATOMIC_SEQ_CST ) );
     369                case PREEMPT_TERMINATE: verify( __atomic_load_n( &kernelTLS.this_processor->do_terminate, __ATOMIC_SEQ_CST ) );
    620370                default:
    621371                        abort( "internal error, signal value is %d", sfp->si_value.sival_int );
     
    623373
    624374        // Check if it is safe to preempt here
    625         if( !preemption_ready( ip ) ) { return; }
    626 
    627         __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p @ %p).\n", __cfaabi_tls.this_processor, __cfaabi_tls.this_thread, (void *)(cxt->uc_mcontext.CFA_REG_IP) );
     375        if( !preemption_ready() ) { return; }
     376
     377        __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p @ %p).\n", kernelTLS.this_processor, kernelTLS.this_thread, (void *)(cxt->uc_mcontext.CFA_REG_IP) );
    628378
    629379        // Sync flag : prevent recursive calls to the signal handler
    630         __cfaabi_tls.preemption_state.in_progress = true;
     380        kernelTLS.preemption_state.in_progress = true;
    631381
    632382        // Clear sighandler mask before context switching.
     
    638388        }
    639389
     390        // TODO: this should go in finish action
    640391        // Clear the in progress flag
    641         __cfaabi_tls.preemption_state.in_progress = false;
     392        kernelTLS.preemption_state.in_progress = false;
    642393
    643394        // Preemption can occur here
    644395
    645         force_yield( __ALARM_PREEMPTION ); // Do the actual __cfactx_switch
    646 }
    647 
    648 static void sigHandler_alarm( __CFA_SIGPARMS__ ) {
    649         abort("SIGALRM should never reach the signal handler");
    650 }
    651 
    652 #if !defined(__CFA_NO_STATISTICS__)
    653         int __print_alarm_stats = 0;
    654 #endif
     396        BlockInternal( kernelTLS.this_thread ); // Do the actual CtxSwitch
     397}
    655398
    656399// Main of the alarm thread
    657400// Waits on SIGALRM and send SIGUSR1 to whom ever needs it
    658401static void * alarm_loop( __attribute__((unused)) void * args ) {
    659         __processor_id_t id;
    660         id.full_proc = false;
    661         id.id = doregister(&id);
    662         __cfaabi_tls.this_proc_id = &id;
    663 
    664         #if !defined(__CFA_NO_STATISTICS__)
    665                 struct __stats_t local_stats;
    666                 __cfaabi_tls.this_stats = &local_stats;
    667                 __init_stats( &local_stats );
    668         #endif
    669 
    670402        // Block sigalrms to control when they arrive
    671403        sigset_t mask;
     
    725457EXIT:
    726458        __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" );
    727         unregister(&id);
    728 
    729         #if !defined(__CFA_NO_STATISTICS__)
    730                 if( 0 != __print_alarm_stats ) {
    731                         __print_stats( &local_stats, __print_alarm_stats, "Alarm", "Thread", 0p );
    732                 }
    733         #endif
    734459        return 0p;
    735460}
     461
     462//=============================================================================================
     463// Kernel Signal Debug
     464//=============================================================================================
     465
     466void __cfaabi_check_preemption() {
     467        bool ready = kernelTLS.preemption_state.enabled;
     468        if(!ready) { abort("Preemption should be ready"); }
     469
     470        sigset_t oldset;
     471        int ret;
     472        ret = pthread_sigmask(0, 0p, &oldset);
     473        if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
     474
     475        ret = sigismember(&oldset, SIGUSR1);
     476        if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
     477        if(ret == 1) { abort("ERROR SIGUSR1 is disabled"); }
     478
     479        ret = sigismember(&oldset, SIGALRM);
     480        if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
     481        if(ret == 0) { abort("ERROR SIGALRM is enabled"); }
     482
     483        ret = sigismember(&oldset, SIGTERM);
     484        if(ret <  0) { abort("ERROR sigismember returned %d", ret); }
     485        if(ret == 1) { abort("ERROR SIGTERM is disabled"); }
     486}
     487
     488#ifdef __CFA_WITH_VERIFY__
     489bool __cfaabi_dbg_in_kernel() {
     490        return !kernelTLS.preemption_state.enabled;
     491}
     492#endif
    736493
    737494// Local Variables: //
  • libcfa/src/concurrency/preemption.hfa

    reef8dfb rbdfc032  
    1616#pragma once
    1717
    18 #include "bits/locks.hfa"
    1918#include "alarm.hfa"
     19#include "kernel_private.hfa"
    2020
    21 struct event_kernel_t {
    22         alarm_list_t alarms;
    23         __spinlock_t lock;
    24 };
    25 
    26 extern event_kernel_t * event_kernel;
    27 
     21void kernel_start_preemption();
     22void kernel_stop_preemption();
    2823void update_preemption( processor * this, Duration duration );
    2924
  • libcfa/src/concurrency/thread.cfa

    reef8dfb rbdfc032  
    1919
    2020#include "kernel_private.hfa"
    21 #include "exception.hfa"
    2221
    2322#define __CFA_INVOKE_PRIVATE__
    2423#include "invoke.h"
    2524
     25extern "C" {
     26        #include <fenv.h>
     27        #include <stddef.h>
     28}
     29
     30//extern volatile thread_local processor * this_processor;
     31
    2632//-----------------------------------------------------------------------------
    2733// Thread ctors and dtors
    28 void ?{}($thread & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) {
     34void ?{}(thread_desc & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) {
    2935        context{ 0p, 0p };
    3036        self_cor{ name, storage, storageSize };
    31         ticket = TICKET_RUNNING;
    3237        state = Start;
    33         preempted = __NO_PREEMPTION;
    3438        curr_cor = &self_cor;
    3539        self_mon.owner = &this;
     
    3741        self_mon_p = &self_mon;
    3842        curr_cluster = &cl;
    39         link.next = 0p;
    40         link.prev = 0p;
    41         link.preferred = -1;
    42         #if defined( __CFA_WITH_VERIFY__ )
    43                 canary = 0x0D15EA5E0D15EA5Ep;
    44         #endif
    45 
    46         seqable.next = 0p;
    47         seqable.back = 0p;
     43        next = 0p;
    4844
    4945        node.next = 0p;
     
    5450}
    5551
    56 void ^?{}($thread& this) with( this ) {
    57         #if defined( __CFA_WITH_VERIFY__ )
    58                 canary = 0xDEADDEADDEADDEADp;
    59         #endif
     52void ^?{}(thread_desc& this) with( this ) {
    6053        unregister(curr_cluster, this);
    6154        ^self_cor{};
    6255}
    6356
    64 FORALL_DATA_INSTANCE(ThreadCancelled, (dtype thread_t), (thread_t))
    65 
    66 forall(dtype T)
    67 void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src) {
    68         dst->virtual_table = src->virtual_table;
    69         dst->the_thread = src->the_thread;
    70         dst->the_exception = src->the_exception;
    71 }
    72 
    73 forall(dtype T)
    74 const char * msg(ThreadCancelled(T) *) {
    75         return "ThreadCancelled";
    76 }
    77 
    78 forall(dtype T)
    79 static void default_thread_cancel_handler(ThreadCancelled(T) & ) {
    80         abort( "Unhandled thread cancellation.\n" );
    81 }
    82 
    83 forall(dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)))
    84 void ?{}( thread_dtor_guard_t & this,
    85                 T & thrd, void(*defaultResumptionHandler)(ThreadCancelled(T) &)) {
    86         $monitor * m = get_monitor(thrd);
    87         $thread * desc = get_thread(thrd);
    88 
    89         // Setup the monitor guard
    90         void (*dtor)(T& mutex this) = ^?{};
    91         bool join = defaultResumptionHandler != (void(*)(ThreadCancelled(T)&))0;
    92         (this.mg){&m, (void(*)())dtor, join};
    93 
    94 
    95         /* paranoid */ verifyf( Halted == desc->state || Cancelled == desc->state, "Expected thread to be Halted or Cancelled, was %d\n", (int)desc->state );
    96 
    97         // After the guard set-up and any wait, check for cancellation.
    98         struct _Unwind_Exception * cancellation = desc->self_cor.cancellation;
    99         if ( likely( 0p == cancellation ) ) {
    100                 return;
    101         } else if ( Cancelled == desc->state ) {
    102                 return;
    103         }
    104         desc->state = Cancelled;
    105         if (!join) {
    106                 defaultResumptionHandler = default_thread_cancel_handler;
    107         }
    108 
    109         ThreadCancelled(T) except;
    110         // TODO: Remove explitate vtable set once trac#186 is fixed.
    111         except.virtual_table = &get_exception_vtable(&except);
    112         except.the_thread = &thrd;
    113         except.the_exception = __cfaehm_cancellation_exception( cancellation );
    114         throwResume except;
    115 
    116         except.the_exception->virtual_table->free( except.the_exception );
    117         free( cancellation );
    118         desc->self_cor.cancellation = 0p;
    119 }
    120 
    121 void ^?{}( thread_dtor_guard_t & this ) {
    122         ^(this.mg){};
    123 }
    124 
    125 //-----------------------------------------------------------------------------
    126 // Starting and stopping threads
    127 forall( dtype T | is_thread(T) )
    128 void __thrd_start( T & this, void (*main_p)(T &) ) {
    129         $thread * this_thrd = get_thread(this);
    130 
    131         disable_interrupts();
    132         __cfactx_start(main_p, get_coroutine(this), this, __cfactx_invoke_thread);
    133 
    134         this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP];
    135         /* paranoid */ verify( this_thrd->context.SP );
    136 
    137         __schedule_thread( this_thrd );
    138         enable_interrupts( __cfaabi_dbg_ctx );
    139 }
    140 
    141 //-----------------------------------------------------------------------------
    142 // Support for threads that don't ues the thread keyword
    14357forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T&); } )
    14458void ?{}( scoped(T)& this ) with( this ) {
     
    15973
    16074//-----------------------------------------------------------------------------
    161 forall(dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))
    162 T & join( T & this ) {
    163         thread_dtor_guard_t guard = { this, defaultResumptionHandler };
    164         return this;
     75// Starting and stopping threads
     76forall( dtype T | is_thread(T) )
     77void __thrd_start( T & this, void (*main_p)(T &) ) {
     78        thread_desc * this_thrd = get_thread(this);
     79        thread_desc * curr_thrd = TL_GET( this_thread );
     80
     81        disable_interrupts();
     82        CtxStart(main_p, get_coroutine(this), this, CtxInvokeThread);
     83
     84        this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP];
     85        verify( this_thrd->context.SP );
     86        // CtxSwitch( &curr_thrd->context, &this_thrd->context );
     87
     88        ScheduleThread(this_thrd);
     89        enable_interrupts( __cfaabi_dbg_ctx );
    16590}
    16691
    167 uint64_t thread_rand() {
    168         disable_interrupts();
    169         uint64_t ret = __tls_rand();
    170         enable_interrupts( __cfaabi_dbg_ctx );
    171         return ret;
     92void yield( void ) {
     93        // Safety note : This could cause some false positives due to preemption
     94      verify( TL_GET( preemption_state.enabled ) );
     95        BlockInternal( TL_GET( this_thread ) );
     96        // Safety note : This could cause some false positives due to preemption
     97      verify( TL_GET( preemption_state.enabled ) );
     98}
     99
     100void yield( unsigned times ) {
     101        for( unsigned i = 0; i < times; i++ ) {
     102                yield();
     103        }
    172104}
    173105
  • libcfa/src/concurrency/thread.hfa

    reef8dfb rbdfc032  
    2222#include "kernel.hfa"
    2323#include "monitor.hfa"
    24 #include "exception.hfa"
    2524
    2625//-----------------------------------------------------------------------------
    2726// thread trait
    2827trait is_thread(dtype T) {
    29         void ^?{}(T& mutex this);
    30         void main(T& this);
    31         $thread* get_thread(T& this);
     28      void ^?{}(T& mutex this);
     29      void main(T& this);
     30      thread_desc* get_thread(T& this);
    3231};
    3332
    34 FORALL_DATA_EXCEPTION(ThreadCancelled, (dtype thread_t), (thread_t)) (
    35         thread_t * the_thread;
    36         exception_t * the_exception;
    37 );
    38 
    39 forall(dtype T)
    40 void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src);
    41 
    42 forall(dtype T)
    43 const char * msg(ThreadCancelled(T) *);
    44 
    45 // define that satisfies the trait without using the thread keyword
    46 #define DECL_THREAD(X) $thread* get_thread(X& this) __attribute__((const)) { return &this.__thrd; } void main(X& this)
    47 
    48 // Inline getters for threads/coroutines/monitors
    49 forall( dtype T | is_thread(T) )
    50 static inline $coroutine* get_coroutine(T & this) __attribute__((const)) { return &get_thread(this)->self_cor; }
     33#define DECL_THREAD(X) thread_desc* get_thread(X& this) { return &this.__thrd; } void main(X& this)
    5134
    5235forall( dtype T | is_thread(T) )
    53 static inline $monitor  * get_monitor  (T & this) __attribute__((const)) { return &get_thread(this)->self_mon; }
     36static inline coroutine_desc* get_coroutine(T & this) {
     37        return &get_thread(this)->self_cor;
     38}
    5439
    55 static inline $coroutine* get_coroutine($thread * this) __attribute__((const)) { return &this->self_cor; }
    56 static inline $monitor  * get_monitor  ($thread * this) __attribute__((const)) { return &this->self_mon; }
     40forall( dtype T | is_thread(T) )
     41static inline monitor_desc* get_monitor(T & this) {
     42        return &get_thread(this)->self_mon;
     43}
    5744
    58 //-----------------------------------------------------------------------------
    59 // forward declarations needed for threads
     45static inline coroutine_desc* get_coroutine(thread_desc * this) {
     46        return &this->self_cor;
     47}
     48
     49static inline monitor_desc* get_monitor(thread_desc * this) {
     50        return &this->self_mon;
     51}
     52
    6053extern struct cluster * mainCluster;
    6154
     
    6558//-----------------------------------------------------------------------------
    6659// Ctors and dtors
    67 void ?{}($thread & this, const char * const name, struct cluster & cl, void * storage, size_t storageSize );
    68 void ^?{}($thread & this);
     60void ?{}(thread_desc & this, const char * const name, struct cluster & cl, void * storage, size_t storageSize );
     61void ^?{}(thread_desc & this);
    6962
    70 static inline void ?{}($thread & this)                                                                  { this{ "Anonymous Thread", *mainCluster, 0p, 65000 }; }
    71 static inline void ?{}($thread & this, size_t stackSize )                                               { this{ "Anonymous Thread", *mainCluster, 0p, stackSize }; }
    72 static inline void ?{}($thread & this, void * storage, size_t storageSize )                             { this{ "Anonymous Thread", *mainCluster, storage, storageSize }; }
    73 static inline void ?{}($thread & this, struct cluster & cl )                                            { this{ "Anonymous Thread", cl, 0p, 65000 }; }
    74 static inline void ?{}($thread & this, struct cluster & cl, size_t stackSize )                          { this{ "Anonymous Thread", cl, 0p, stackSize }; }
    75 static inline void ?{}($thread & this, struct cluster & cl, void * storage, size_t storageSize )        { this{ "Anonymous Thread", cl, storage, storageSize }; }
    76 static inline void ?{}($thread & this, const char * const name)                                         { this{ name, *mainCluster, 0p, 65000 }; }
    77 static inline void ?{}($thread & this, const char * const name, struct cluster & cl )                   { this{ name, cl, 0p, 65000 }; }
    78 static inline void ?{}($thread & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; }
    79 
    80 struct thread_dtor_guard_t {
    81         monitor_dtor_guard_t mg;
    82 };
    83 
    84 forall( dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )
    85 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
    86 void ^?{}( thread_dtor_guard_t & this );
     63static inline void ?{}(thread_desc & this)                                                                  { this{ "Anonymous Thread", *mainCluster, 0p, 65000 }; }
     64static inline void ?{}(thread_desc & this, size_t stackSize )                                               { this{ "Anonymous Thread", *mainCluster, 0p, stackSize }; }
     65static inline void ?{}(thread_desc & this, void * storage, size_t storageSize )                             { this{ "Anonymous Thread", *mainCluster, storage, storageSize }; }
     66static inline void ?{}(thread_desc & this, struct cluster & cl )                                            { this{ "Anonymous Thread", cl, 0p, 65000 }; }
     67static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize )                          { this{ "Anonymous Thread", cl, 0p, stackSize }; }
     68static inline void ?{}(thread_desc & this, struct cluster & cl, void * storage, size_t storageSize )        { this{ "Anonymous Thread", cl, storage, storageSize }; }
     69static inline void ?{}(thread_desc & this, const char * const name)                                         { this{ name, *mainCluster, 0p, 65000 }; }
     70static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl )                   { this{ name, cl, 0p, 65000 }; }
     71static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; }
    8772
    8873//-----------------------------------------------------------------------------
     
    10388void ^?{}( scoped(T)& this );
    10489
    105 //-----------------------------------------------------------------------------
    106 // Scheduler API
     90void yield();
     91void yield( unsigned times );
    10792
    108 //----------
    109 // Park thread: block until corresponding call to unpark, won't block if unpark is already called
    110 void park( void );
    111 
    112 //----------
    113 // Unpark a thread, if the thread is already blocked, schedule it
    114 //                  if the thread is not yet block, signal that it should rerun immediately
    115 void unpark( $thread * this );
    116 
    117 forall( dtype T | is_thread(T) )
    118 static inline void unpark( T & this ) { if(!&this) return; unpark( get_thread( this ) );}
    119 
    120 //----------
    121 // Yield: force thread to block and be rescheduled
    122 bool force_yield( enum __Preemption_Reason );
    123 
    124 //----------
    125 // sleep: force thread to block and be rescheduled after Duration duration
    126 void sleep( Duration duration );
    127 
    128 //----------
    129 // join
    130 forall( dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) )
    131 T & join( T & this );
     93static inline struct thread_desc * active_thread () { return TL_GET( this_thread ); }
    13294
    13395// Local Variables: //
  • libcfa/src/containers/vector.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Jul  5 18:00:07 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 17 11:02:46 2020
    13 // Update Count     : 4
     12// Last Modified On : Sat Jul 22 10:01:18 2017
     13// Update Count     : 3
    1414//
    1515
    1616#pragma once
    1717
     18extern "C" {
    1819#include <stdbool.h>
     20}
    1921
    2022//------------------------------------------------------------------------------
  • libcfa/src/exception.c

    reef8dfb rbdfc032  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:13:00 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct 27 16:27:00 2020
    13 // Update Count     : 35
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Feb 22 18:17:34 2018
     13// Update Count     : 11
    1414//
    1515
    16 // Normally we would get this from the CFA prelude.
    1716#include <stddef.h> // for size_t
    1817
    19 #include <unwind.h> // for struct _Unwind_Exception {...};
    20 
    2118#include "exception.h"
     19
     20// Implementation of the secret header.
    2221
    2322#include <stdlib.h>
    2423#include <stdio.h>
     24#include <unwind.h>
    2525#include <bits/debug.hfa>
    26 #include "concurrency/invoke.h"
    27 #include "stdhdr/assert.h"
    28 
    29 #if defined( __ARM_ARCH )
    30 #warning FIX ME: temporary hack to keep ARM build working
     26
     27// FIX ME: temporary hack to keep ARM build working
    3128#ifndef _URC_FATAL_PHASE1_ERROR
    32 #define _URC_FATAL_PHASE1_ERROR 3
     29#define _URC_FATAL_PHASE1_ERROR 2
    3330#endif // ! _URC_FATAL_PHASE1_ERROR
    3431#ifndef _URC_FATAL_PHASE2_ERROR
    3532#define _URC_FATAL_PHASE2_ERROR 2
    3633#endif // ! _URC_FATAL_PHASE2_ERROR
    37 #endif // __ARM_ARCH
    3834
    3935#include "lsda.h"
    4036
    41 /* The exception class for our exceptions. Because of the vendor component
    42  * its value would not be standard.
    43  * Vendor: UWPL
    44  * Language: CFA\0
    45  */
    46 const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643;
    4737
    4838// Base exception vtable is abstract, you should not have base exceptions.
    49 struct __cfaehm_base_exception_t_vtable
    50                 ___cfaehm_base_exception_t_vtable_instance = {
     39struct __cfaabi_ehm__base_exception_t_vtable
     40                ___cfaabi_ehm__base_exception_t_vtable_instance = {
    5141        .parent = NULL,
    5242        .size = 0,
     
    5747
    5848
     49// Temperary global exception context. Does not work with concurency.
     50struct exception_context_t {
     51    struct __cfaabi_ehm__try_resume_node * top_resume;
     52    struct __cfaabi_ehm__try_resume_node * current_resume;
     53
     54    exception_t * current_exception;
     55    int current_handler_index;
     56} shared_stack = {NULL, NULL, 0, 0};
     57
    5958// Get the current exception context.
    6059// There can be a single global until multithreading occurs, then each stack
    61 // needs its own. We get this from libcfathreads (no weak attribute).
    62 __attribute__((weak)) struct exception_context_t * this_exception_context() {
    63         static struct exception_context_t shared_stack = {NULL, NULL};
     60// needs its own. It will have to be updated to handle that.
     61struct exception_context_t * this_exception_context() {
    6462        return &shared_stack;
    6563}
     64//#define SAVE_EXCEPTION_CONTEXT(to_name)
     65//struct exception_context_t * to_name = this_exception_context();
     66//exception * this_exception() {
     67//    return this_exception_context()->current_exception;
     68//}
     69
     70
     71// This macro should be the only thing that needs to change across machines.
     72// Used in the personality function, way down in termination.
     73// struct _Unwind_Context * -> _Unwind_Reason_Code(*)(exception_t *)
     74#define MATCHER_FROM_CONTEXT(ptr_to_context) \
     75        (*(_Unwind_Reason_Code(**)(exception_t *))(_Unwind_GetCFA(ptr_to_context) + 8))
    6676
    6777
    6878// RESUMPTION ================================================================
    6979
    70 static void reset_top_resume(struct __cfaehm_try_resume_node ** store) {
    71         this_exception_context()->top_resume = *store;
    72 }
    73 
    74 void __cfaehm_throw_resume(exception_t * except, void (*defaultHandler)(exception_t *)) {
    75         struct exception_context_t * context = this_exception_context();
    76 
    77         __cfadbg_print_safe(exception, "Throwing resumption exception\n");
    78 
    79         {
    80                 __attribute__((cleanup(reset_top_resume)))
    81                 struct __cfaehm_try_resume_node * original_head = context->top_resume;
    82                 struct __cfaehm_try_resume_node * current = context->top_resume;
    83 
    84                 for ( ; current ; current = current->next) {
    85                         context->top_resume = current->next;
    86                         if (current->handler(except)) {
    87                                 return;
    88                         }
     80void __cfaabi_ehm__throw_resume(exception_t * except) {
     81
     82        __cfaabi_dbg_print_safe("Throwing resumption exception\n");
     83
     84        struct __cfaabi_ehm__try_resume_node * original_head = shared_stack.current_resume;
     85        struct __cfaabi_ehm__try_resume_node * current =
     86                (original_head) ? original_head->next : shared_stack.top_resume;
     87
     88        for ( ; current ; current = current->next) {
     89                shared_stack.current_resume = current;
     90                if (current->handler(except)) {
     91                        shared_stack.current_resume = original_head;
     92                        return;
    8993                }
    90         } // End the search and return to the top of the stack.
    91 
    92         // No handler found, fall back to the default operation.
    93         __cfadbg_print_safe(exception, "Unhandled exception\n");
    94         defaultHandler(except);
     94        }
     95
     96        __cfaabi_dbg_print_safe("Unhandled exception\n");
     97        shared_stack.current_resume = original_head;
     98
     99        // Fall back to termination:
     100        __cfaabi_ehm__throw_terminate(except);
     101        // TODO: Default handler for resumption.
    95102}
    96103
     
    99106// be added after the node is built but before it is made the top node.
    100107
    101 void __cfaehm_try_resume_setup(struct __cfaehm_try_resume_node * node,
     108void __cfaabi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node,
    102109                        _Bool (*handler)(exception_t * except)) {
     110        node->next = shared_stack.top_resume;
     111        node->handler = handler;
     112        shared_stack.top_resume = node;
     113}
     114
     115void __cfaabi_ehm__try_resume_cleanup(struct __cfaabi_ehm__try_resume_node * node) {
     116        shared_stack.top_resume = node->next;
     117}
     118
     119
     120// TERMINATION ===============================================================
     121
     122// MEMORY MANAGEMENT (still for integers)
     123// May have to move to cfa for constructors and destructors (references).
     124
     125struct __cfaabi_ehm__node {
     126        struct __cfaabi_ehm__node * next;
     127};
     128
     129#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
     130#define EXCEPT_TO_NODE(except) ((struct __cfaabi_ehm__node *)(except) - 1)
     131
     132// Creates a copy of the indicated exception and sets current_exception to it.
     133static void __cfaabi_ehm__allocate_exception( exception_t * except ) {
    103134        struct exception_context_t * context = this_exception_context();
    104         node->next = context->top_resume;
    105         node->handler = handler;
    106         context->top_resume = node;
    107 }
    108 
    109 void __cfaehm_try_resume_cleanup(struct __cfaehm_try_resume_node * node) {
    110         struct exception_context_t * context = this_exception_context();
    111         context->top_resume = node->next;
    112 }
    113 
    114 
    115 // MEMORY MANAGEMENT =========================================================
    116 
    117 #define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
    118 #define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
    119 #define UNWIND_TO_NODE(unwind) ((struct __cfaehm_node *)(unwind))
    120 #define NULL_MAP(map, ptr) ((ptr) ? (map(ptr)) : NULL)
    121 
    122 // How to clean up an exception in various situations.
    123 static void __cfaehm_exception_cleanup(
    124                 _Unwind_Reason_Code reason,
    125                 struct _Unwind_Exception * exception) {
    126         switch (reason) {
    127         case _URC_FOREIGN_EXCEPTION_CAUGHT:
    128                 // This one we could clean-up to allow cross-language exceptions.
    129         case _URC_FATAL_PHASE1_ERROR:
    130         case _URC_FATAL_PHASE2_ERROR:
    131         default:
    132                 abort();
    133         }
    134 }
    135 
    136 // Creates a copy of the indicated exception and sets current_exception to it.
    137 static void __cfaehm_allocate_exception( exception_t * except ) {
    138         struct exception_context_t * context = this_exception_context();
    139135
    140136        // Allocate memory for the exception.
    141         struct __cfaehm_node * store = malloc(
    142                 sizeof( struct __cfaehm_node ) + except->virtual_table->size );
     137        struct __cfaabi_ehm__node * store = malloc(
     138                sizeof( struct __cfaabi_ehm__node ) + except->virtual_table->size );
    143139
    144140        if ( ! store ) {
     
    147143        }
    148144
    149         // Initialize the node:
    150         exception_t * except_store = NODE_TO_EXCEPT(store);
    151         store->unwind_exception.exception_class = __cfaehm_exception_class;
    152         store->unwind_exception.exception_cleanup = __cfaehm_exception_cleanup;
    153         store->handler_index = 0;
    154         except->virtual_table->copy( except_store, except );
    155 
    156145        // Add the node to the list:
    157         store->next = NULL_MAP(EXCEPT_TO_NODE, context->current_exception);
    158         context->current_exception = except_store;
     146        store->next = EXCEPT_TO_NODE(context->current_exception);
     147        context->current_exception = NODE_TO_EXCEPT(store);
     148
     149        // Copy the exception to storage.
     150        except->virtual_table->copy( context->current_exception, except );
    159151}
    160152
    161153// Delete the provided exception, unsetting current_exception if relivant.
    162 static void __cfaehm_delete_exception( exception_t * except ) {
     154static void __cfaabi_ehm__delete_exception( exception_t * except ) {
    163155        struct exception_context_t * context = this_exception_context();
    164156
    165         __cfadbg_print_safe(exception, "Deleting Exception\n");
     157        __cfaabi_dbg_print_safe("Deleting Exception\n");
    166158
    167159        // Remove the exception from the list.
    168         struct __cfaehm_node * to_free = EXCEPT_TO_NODE(except);
    169         struct __cfaehm_node * node;
     160        struct __cfaabi_ehm__node * to_free = EXCEPT_TO_NODE(except);
     161        struct __cfaabi_ehm__node * node;
    170162
    171163        if ( context->current_exception == except ) {
    172164                node = to_free->next;
    173                 context->current_exception = NULL_MAP(NODE_TO_EXCEPT, node);
     165                context->current_exception = (node) ? NODE_TO_EXCEPT(node) : 0;
    174166        } else {
    175167                node = EXCEPT_TO_NODE(context->current_exception);
    176168                // It may always be in the first or second position.
    177                 while ( to_free != node->next ) {
     169                while( to_free != node->next ) {
    178170                        node = node->next;
    179171                }
     
    186178}
    187179
    188 // CANCELLATION ==============================================================
     180// If this isn't a rethrow (*except==0), delete the provided exception.
     181void __cfaabi_ehm__cleanup_terminate( void * except ) {
     182        if ( *(void**)except ) __cfaabi_ehm__delete_exception( *(exception_t **)except );
     183}
     184
     185
     186// We need a piece of storage to raise the exception
     187struct _Unwind_Exception this_exception_storage;
    189188
    190189// Function needed by force unwind
     
    193192                int version,
    194193                _Unwind_Action actions,
    195                 _Unwind_Exception_Class exception_class,
     194                _Unwind_Exception_Class exceptionClass,
    196195                struct _Unwind_Exception * unwind_exception,
    197                 struct _Unwind_Context * unwind_context,
    198                 void * stop_param) {
    199         // Verify actions follow the rules we expect.
    200         verify(actions & _UA_CLEANUP_PHASE);
    201         verify(actions & _UA_FORCE_UNWIND);
    202         verify(!(actions & _UA_SEARCH_PHASE));
    203         verify(!(actions & _UA_HANDLER_FRAME));
    204 
    205         if ( actions & _UA_END_OF_STACK ) {
    206                 abort();
    207         } else {
    208                 return _URC_NO_REASON;
    209         }
    210 }
    211 
    212 __attribute__((weak)) _Unwind_Reason_Code
    213 __cfaehm_cancellation_unwind( struct _Unwind_Exception * exception ) {
    214         return _Unwind_ForcedUnwind( exception, _Stop_Fn, (void*)0x22 );
    215 }
    216 
    217 // Cancel the current stack, prefroming approprate clean-up and messaging.
    218 void __cfaehm_cancel_stack( exception_t * exception ) {
    219         __cfaehm_allocate_exception( exception );
    220 
    221         struct exception_context_t * context = this_exception_context();
    222         struct __cfaehm_node * node = EXCEPT_TO_NODE(context->current_exception);
    223 
    224         // Preform clean-up of any extra active exceptions.
    225         while ( node->next ) {
    226                 struct __cfaehm_node * to_free = node->next;
    227                 node->next = to_free->next;
    228                 exception_t * except = NODE_TO_EXCEPT( to_free );
    229                 except->virtual_table->free( except );
    230             free( to_free );
    231         }
    232 
    233         _Unwind_Reason_Code ret;
    234         ret = __cfaehm_cancellation_unwind( &node->unwind_exception );
    235         printf("UNWIND ERROR %d after force unwind\n", ret);
    236         abort();
    237 }
    238 
    239 
    240 // TERMINATION ===============================================================
    241 
    242 // If this isn't a rethrow (*except==0), delete the provided exception.
    243 void __cfaehm_cleanup_terminate( void * except ) {
    244         if ( *(void**)except ) __cfaehm_delete_exception( *(exception_t **)except );
    245 }
    246 
    247 static void __cfaehm_cleanup_default( exception_t ** except ) {
    248         __cfaehm_delete_exception( *except );
    249         *except = NULL;
     196                struct _Unwind_Context * context,
     197                void * some_param) {
     198        if( actions & _UA_END_OF_STACK  ) exit(1);
     199        if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
     200
     201        return _URC_FATAL_PHASE2_ERROR;
    250202}
    251203
    252204// The exception that is being thrown must already be stored.
    253 static void __cfaehm_begin_unwind(void(*defaultHandler)(exception_t *)) {
    254         struct exception_context_t * context = this_exception_context();
    255         if ( NULL == context->current_exception ) {
     205__attribute__((noreturn)) void __cfaabi_ehm__begin_unwind(void) {
     206        if ( ! this_exception_context()->current_exception ) {
    256207                printf("UNWIND ERROR missing exception in begin unwind\n");
    257208                abort();
    258209        }
    259         struct _Unwind_Exception * storage =
    260                 &EXCEPT_TO_NODE(context->current_exception)->unwind_exception;
     210
    261211
    262212        // Call stdlibc to raise the exception
    263         __cfadbg_print_safe(exception, "Begin unwinding (storage &p, context %p)\n", storage, context);
    264         _Unwind_Reason_Code ret = _Unwind_RaiseException( storage );
     213        _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
    265214
    266215        // If we reach here it means something happened. For resumption to work we need to find a way
     
    271220        // the whole stack.
    272221
     222        if( ret == _URC_END_OF_STACK ) {
     223                // No proper handler was found. This can be handled in many ways, C++ calls std::terminate.
     224                // Here we force unwind the stack, basically raising a cancellation.
     225                printf("Uncaught exception %p\n", &this_exception_storage);
     226
     227                ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
     228                printf("UNWIND ERROR %d after force unwind\n", ret);
     229                abort();
     230        }
     231
    273232        // We did not simply reach the end of the stack without finding a handler. This is an error.
    274         if ( ret != _URC_END_OF_STACK ) {
    275                 printf("UNWIND ERROR %d after raise exception\n", ret);
    276                 abort();
    277         }
    278 
    279         // No handler found, go to the default operation.
    280         __cfadbg_print_safe(exception, "Uncaught exception %p\n", storage);
    281 
    282         __attribute__((cleanup(__cfaehm_cleanup_default)))
    283         exception_t * exception = context->current_exception;
    284         defaultHandler( exception );
    285 }
    286 
    287 void __cfaehm_throw_terminate( exception_t * val, void (*defaultHandler)(exception_t *) ) {
    288         __cfadbg_print_safe(exception, "Throwing termination exception\n");
    289 
    290         __cfaehm_allocate_exception( val );
    291         __cfaehm_begin_unwind( defaultHandler );
    292 }
    293 
    294 static __attribute__((noreturn)) void __cfaehm_rethrow_adapter( exception_t * except ) {
    295         // TODO: Print some error message.
    296         (void)except;
     233        printf("UNWIND ERROR %d after raise exception\n", ret);
    297234        abort();
    298235}
    299236
    300 void __cfaehm_rethrow_terminate(void) {
    301         __cfadbg_print_safe(exception, "Rethrowing termination exception\n");
    302 
    303         __cfaehm_begin_unwind( __cfaehm_rethrow_adapter );
     237void __cfaabi_ehm__throw_terminate( exception_t * val ) {
     238        __cfaabi_dbg_print_safe("Throwing termination exception\n");
     239
     240        __cfaabi_ehm__allocate_exception( val );
     241        __cfaabi_ehm__begin_unwind();
     242}
     243
     244void __cfaabi_ehm__rethrow_terminate(void) {
     245        __cfaabi_dbg_print_safe("Rethrowing termination exception\n");
     246
     247        __cfaabi_ehm__begin_unwind();
     248}
     249
     250#if defined(PIC)
     251#warning Exceptions not yet supported when using Position-Independent Code
     252__attribute__((noinline))
     253void __cfaabi_ehm__try_terminate(void (*try_block)(),
     254                void (*catch_block)(int index, exception_t * except),
     255                __attribute__((unused)) int (*match_block)(exception_t * except)) {
    304256        abort();
    305257}
    306 
    307 #if defined( __x86_64 ) || defined( __i386 )
     258#else // PIC
    308259// This is our personality routine. For every stack frame annotated with
    309260// ".cfi_personality 0x3,__gcfa_personality_v0" this function will be called twice when unwinding.
    310261//  Once in the search phase and once in the cleanup phase.
    311 _Unwind_Reason_Code __gcfa_personality_v0(
    312                 int version,
    313                 _Unwind_Action actions,
    314                 unsigned long long exception_class,
    315                 struct _Unwind_Exception * unwind_exception,
    316                 struct _Unwind_Context * unwind_context)
     262_Unwind_Reason_Code __gcfa_personality_v0 (
     263                int version, _Unwind_Action actions, unsigned long long exceptionClass,
     264                struct _Unwind_Exception* unwind_exception,
     265                struct _Unwind_Context* context)
    317266{
    318267
    319         //__cfadbg_print_safe(exception, "CFA: 0x%lx\n", _Unwind_GetCFA(context));
    320         __cfadbg_print_safe(exception, "Personality function (%d, %x, %llu, %p, %p):",
    321                         version, actions, exception_class, unwind_exception, unwind_context);
    322 
    323         // Verify that actions follow the rules we expect.
    324         // This function should never be called at the end of the stack.
    325         verify(!(actions & _UA_END_OF_STACK));
    326         // Either only the search phase flag is set or...
     268        //__cfaabi_dbg_print_safe("CFA: 0x%lx\n", _Unwind_GetCFA(context));
     269        __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):",
     270                        version, actions, exceptionClass, unwind_exception, context);
     271
     272        // If we've reached the end of the stack then there is nothing much we can do...
     273        if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
     274
    327275        if (actions & _UA_SEARCH_PHASE) {
    328                 verify(actions == _UA_SEARCH_PHASE);
    329                 __cfadbg_print_safe(exception, " lookup phase");
    330         // ... we are in clean-up phase.
    331         } else {
    332                 verify(actions & _UA_CLEANUP_PHASE);
    333                 __cfadbg_print_safe(exception, " cleanup phase");
    334                 // We shouldn't be the handler frame during forced unwind.
    335                 if (actions & _UA_HANDLER_FRAME) {
    336                         verify(!(actions & _UA_FORCE_UNWIND));
    337                         __cfadbg_print_safe(exception, " (handler frame)");
    338                 } else if (actions & _UA_FORCE_UNWIND) {
    339                         __cfadbg_print_safe(exception, " (force unwind)");
    340                 }
     276                __cfaabi_dbg_print_safe(" lookup phase");
     277        }
     278        else if (actions & _UA_CLEANUP_PHASE) {
     279                __cfaabi_dbg_print_safe(" cleanup phase");
     280        }
     281        // Just in case, probably can't actually happen
     282        else {
     283                printf(" error\n");
     284                return _URC_FATAL_PHASE1_ERROR;
    341285        }
    342286
    343287        // Get a pointer to the language specific data from which we will read what we need
    344         const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context );
    345 
    346         if ( !lsd ) {   //Nothing to do, keep unwinding
     288        const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
     289
     290        if( !lsd ) {    //Nothing to do, keep unwinding
    347291                printf(" no LSD");
    348292                goto UNWIND;
     
    351295        // Get the instuction pointer and a reading pointer into the exception table
    352296        lsda_header_info lsd_info;
    353         const unsigned char * cur_ptr = parse_lsda_header(unwind_context, lsd, &lsd_info);
    354         _Unwind_Ptr instruction_ptr = _Unwind_GetIP(unwind_context);
    355 
    356         struct exception_context_t * context = this_exception_context();
     297        const unsigned char * cur_ptr = parse_lsda_header(context, lsd, &lsd_info);
     298        _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
    357299
    358300        // Linearly search the table for stuff to do
    359         while ( cur_ptr < lsd_info.action_table ) {
     301        while( cur_ptr < lsd_info.action_table ) {
    360302                _Unwind_Ptr callsite_start;
    361303                _Unwind_Ptr callsite_len;
     
    370312
    371313                // Have we reach the correct frame info yet?
    372                 if ( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
     314                if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
    373315#ifdef __CFA_DEBUG_PRINT__
    374316                        void * ls = (void*)lsd_info.Start;
     
    378320                        void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
    379321                        void * ip = (void*)instruction_ptr;
    380                         __cfadbg_print_safe(exception, "\nfound %p - %p (%p, %p, %p), looking for %p\n",
     322                        __cfaabi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n",
    381323                                        bp, ep, ls, cs, cl, ip);
    382324#endif // __CFA_DEBUG_PRINT__
     
    385327
    386328                // Have we gone too far?
    387                 if ( lsd_info.Start + callsite_start > instruction_ptr ) {
     329                if( lsd_info.Start + callsite_start > instruction_ptr ) {
    388330                        printf(" gone too far");
    389331                        break;
    390332                }
    391333
    392                 // Check for what we must do:
    393                 if ( 0 == callsite_landing_pad ) {
    394                         // Nothing to do, move along
    395                         __cfadbg_print_safe(exception, " no landing pad");
    396                 } else if (actions & _UA_SEARCH_PHASE) {
    397                         // In search phase, these means we found a potential handler we must check.
    398 
    399                         // We have arbitrarily decided that 0 means nothing to do and 1 means there is
    400                         // a potential handler. This doesn't seem to conflict the gcc default behavior.
    401                         if (callsite_action != 0) {
    402                                 // Now we want to run some code to see if the handler matches
    403                                 // This is the tricky part where we want to the power to run arbitrary code
    404                                 // However, generating a new exception table entry and try routine every time
    405                                 // is way more expansive than we might like
    406                                 // The information we have is :
    407                                 //  - The GR (Series of registers)
    408                                 //    GR1=GP Global Pointer of frame ref by context
    409                                 //  - The instruction pointer
    410                                 //  - The instruction pointer info (???)
    411                                 //  - The CFA (Canonical Frame Address)
    412                                 //  - The BSP (Probably the base stack pointer)
    413 
    414                                 // The current apprach uses one exception table entry per try block
    415                                 _uleb128_t imatcher;
    416                                 // Get the relative offset to the {...}?
    417                                 cur_ptr = read_uleb128(cur_ptr, &imatcher);
    418 
    419                                 _Unwind_Word match_pos =
    420 #                               if defined( __x86_64 )
    421                                     _Unwind_GetCFA(unwind_context) + 8;
    422 #                               elif defined( __i386 )
    423                                     _Unwind_GetCFA(unwind_context) + 24;
    424 #                               elif defined( __ARM_ARCH )
    425 #                                   warning FIX ME: check if anything needed for ARM
    426                                     42;
    427 #                               endif
    428                                 int (*matcher)(exception_t *) = *(int(**)(exception_t *))match_pos;
    429 
    430                                 int index = matcher(context->current_exception);
    431                                 _Unwind_Reason_Code ret = (0 == index)
    432                                         ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
    433                                 UNWIND_TO_NODE(unwind_exception)->handler_index = index;
    434 
    435                                 // Based on the return value, check if we matched the exception
    436                                 if (ret == _URC_HANDLER_FOUND) {
    437                                         __cfadbg_print_safe(exception, " handler found\n");
    438                                 } else {
    439                                         // TODO: Continue the search if there is more in the table.
    440                                         __cfadbg_print_safe(exception, " no handler\n");
     334                // Something to do?
     335                if( callsite_landing_pad ) {
     336                        // Which phase are we in
     337                        if (actions & _UA_SEARCH_PHASE) {
     338                                // In search phase, these means we found a potential handler we must check.
     339
     340                                // We have arbitrarily decided that 0 means nothing to do and 1 means there is
     341                                // a potential handler. This doesn't seem to conflict the gcc default behavior.
     342                                if (callsite_action != 0) {
     343                                        // Now we want to run some code to see if the handler matches
     344                                        // This is the tricky part where we want to the power to run arbitrary code
     345                                        // However, generating a new exception table entry and try routine every time
     346                                        // is way more expansive than we might like
     347                                        // The information we have is :
     348                                        //  - The GR (Series of registers)
     349                                        //    GR1=GP Global Pointer of frame ref by context
     350                                        //  - The instruction pointer
     351                                        //  - The instruction pointer info (???)
     352                                        //  - The CFA (Canonical Frame Address)
     353                                        //  - The BSP (Probably the base stack pointer)
     354
     355
     356                                        // The current apprach uses one exception table entry per try block
     357                                        _uleb128_t imatcher;
     358                                        // Get the relative offset to the {...}?
     359                                        cur_ptr = read_uleb128(cur_ptr, &imatcher);
     360
     361                                        _Unwind_Reason_Code (*matcher)(exception_t *) =
     362                                                MATCHER_FROM_CONTEXT(context);
     363                                        int index = matcher(shared_stack.current_exception);
     364                                        _Unwind_Reason_Code ret = (0 == index)
     365                                                ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
     366                                        shared_stack.current_handler_index = index;
     367
     368                                        // Based on the return value, check if we matched the exception
     369                                        if( ret == _URC_HANDLER_FOUND) {
     370                                                __cfaabi_dbg_print_safe(" handler found\n");
     371                                        } else {
     372                                                __cfaabi_dbg_print_safe(" no handler\n");
     373                                        }
     374                                        return ret;
    441375                                }
    442                                 return ret;
     376
     377                                // This is only a cleanup handler, ignore it
     378                                __cfaabi_dbg_print_safe(" no action");
    443379                        }
    444 
    445                         // This is only a cleanup handler, ignore it
    446                         __cfadbg_print_safe(exception, " no action");
    447                 } else {
    448                         // In clean-up phase, no destructors here but this could be the handler.
    449 
    450                         if ( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
    451                                 // If this is a potential exception handler
    452                                 // but not the one that matched the exception in the seach phase,
    453                                 // just ignore it
    454                                 goto UNWIND;
     380                        else if (actions & _UA_CLEANUP_PHASE) {
     381
     382                                if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
     383                                        // If this is a potential exception handler
     384                                        // but not the one that matched the exception in the seach phase,
     385                                        // just ignore it
     386                                        goto UNWIND;
     387                                }
     388
     389                                // We need to run some clean-up or a handler
     390                                // These statment do the right thing but I don't know any specifics at all
     391                                _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );
     392                                _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );
     393
     394                                // I assume this sets the instruction pointer to the adress of the landing pad
     395                                // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
     396                                _Unwind_SetIP( context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
     397
     398                                __cfaabi_dbg_print_safe(" action\n");
     399
     400                                // Return have some action to run
     401                                return _URC_INSTALL_CONTEXT;
    455402                        }
    456 
    457                         // We need to run some clean-up or a handler
    458                         // These statment do the right thing but I don't know any specifics at all
    459                         _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(0),
    460                                 (_Unwind_Ptr)unwind_exception );
    461                         _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(1), 0 );
    462 
    463                         // I assume this sets the instruction pointer to the adress of the landing pad
    464                         // It doesn't actually set it, it only state the value that needs to be set once we
    465                         // return _URC_INSTALL_CONTEXT
    466                         _Unwind_SetIP( unwind_context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
    467 
    468                         __cfadbg_print_safe(exception, " action\n");
    469 
    470                         // Return have some action to run
    471                         return _URC_INSTALL_CONTEXT;
    472403                }
     404
     405                // Nothing to do, move along
     406                __cfaabi_dbg_print_safe(" no landing pad");
    473407        }
    474408        // No handling found
    475         __cfadbg_print_safe(exception, " table end reached");
     409        __cfaabi_dbg_print_safe(" table end reached\n");
    476410
    477411        UNWIND:
    478         __cfadbg_print_safe(exception, " unwind\n");
     412        __cfaabi_dbg_print_safe(" unwind\n");
    479413
    480414        // Keep unwinding the stack
    481415        return _URC_CONTINUE_UNWIND;
    482416}
    483 
    484 #pragma GCC push_options
    485 #pragma GCC optimize(0)
    486417
    487418// Try statements are hoisted out see comments for details. While this could probably be unique
    488419// and simply linked from libcfa but there is one problem left, see the exception table for details
    489420__attribute__((noinline))
    490 void __cfaehm_try_terminate(void (*try_block)(),
     421void __cfaabi_ehm__try_terminate(void (*try_block)(),
    491422                void (*catch_block)(int index, exception_t * except),
    492423                __attribute__((unused)) int (*match_block)(exception_t * except)) {
     
    494425        //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy);
    495426
     427        // Setup statments: These 2 statments won't actually result in any code, they only setup global tables.
     428        // However, they clobber gcc cancellation support from gcc.  We can replace the personality routine but
     429        // replacing the exception table gcc generates is not really doable, it generates labels based on how the
     430        // assembly works.
     431
    496432        // Setup the personality routine and exception table.
    497         // Unforturnately these clobber gcc cancellation support which means we can't get access to
    498         // the attribute cleanup tables at the same time. We would have to inspect the assembly to
    499         // create a new set ourselves.
    500 #ifdef __PIC__
    501         asm volatile (".cfi_personality 0x9b,CFA.ref.__gcfa_personality_v0");
    502         asm volatile (".cfi_lsda 0x1b, .LLSDACFA2");
    503 #else
    504433        asm volatile (".cfi_personality 0x3,__gcfa_personality_v0");
    505434        asm volatile (".cfi_lsda 0x3, .LLSDACFA2");
    506 #endif
    507435
    508436        // Label which defines the start of the area for which the handler is setup.
     
    522450        // Label which defines the end of the area for which the handler is setup.
    523451        asm volatile (".TRYEND:");
    524         // Label which defines the start of the exception landing pad. Basically what is called when
    525         // the exception is caught. Note, if multiple handlers are given, the multiplexing should be
    526         // done by the generated code, not the exception runtime.
     452        // Label which defines the start of the exception landing pad.  Basically what is called when the exception is
     453        // caught.  Note, if multiple handlers are given, the multiplexing should be done by the generated code, not the
     454        // exception runtime.
    527455        asm volatile (".CATCH:");
    528456
    529457        // Exception handler
    530         // Note: Saving the exception context on the stack breaks termination exceptions.
    531         catch_block( EXCEPT_TO_NODE( this_exception_context()->current_exception )->handler_index,
    532                      this_exception_context()->current_exception );
     458        catch_block( shared_stack.current_handler_index,
     459                     shared_stack.current_exception );
    533460}
    534461
     
    537464// have a single call to the try routine.
    538465
    539 #ifdef __PIC__
    540 asm (
    541         // HEADER
    542         ".LFECFA1:\n"
    543         "       .globl  __gcfa_personality_v0\n"
    544         "       .section        .gcc_except_table,\"a\",@progbits\n"
    545         // TABLE HEADER (important field is the BODY length at the end)
    546         ".LLSDACFA2:\n"
    547         "       .byte   0xff\n"
    548         "       .byte   0xff\n"
    549         "       .byte   0x1\n"
    550         "       .uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"
    551         // BODY (language specific data)
    552         // This uses language specific data and can be modified arbitrarily
    553         // We use handled area offset, handled area length,
    554         // handler landing pad offset and 1 (action code, gcc seems to use 0).
    555         ".LLSDACSBCFA2:\n"
    556         "       .uleb128 .TRYSTART-__cfaehm_try_terminate\n"
    557         "       .uleb128 .TRYEND-.TRYSTART\n"
    558         "       .uleb128 .CATCH-__cfaehm_try_terminate\n"
    559         "       .uleb128 1\n"
    560         ".LLSDACSECFA2:\n"
    561         // TABLE FOOTER
    562         "       .text\n"
    563         "       .size   __cfaehm_try_terminate, .-__cfaehm_try_terminate\n"
    564 );
    565 
    566 // Somehow this piece of helps with the resolution of debug symbols.
    567 __attribute__((unused)) static const int dummy = 0;
    568 
    569 asm (
    570         // Add a hidden symbol which points at the function.
    571         "       .hidden CFA.ref.__gcfa_personality_v0\n"
    572         "       .weak   CFA.ref.__gcfa_personality_v0\n"
    573         // No clue what this does specifically
    574         "       .section        .data.rel.local.CFA.ref.__gcfa_personality_v0,\"awG\",@progbits,CFA.ref.__gcfa_personality_v0,comdat\n"
    575         "       .align 8\n"
    576         "       .type CFA.ref.__gcfa_personality_v0, @object\n"
    577         "       .size CFA.ref.__gcfa_personality_v0, 8\n"
    578         "CFA.ref.__gcfa_personality_v0:\n"
    579 #if defined( __x86_64 )
    580         "       .quad __gcfa_personality_v0\n"
    581 #else // then __i386
    582         "       .long __gcfa_personality_v0\n"
    583 #endif
    584 );
    585 #else // __PIC__
     466#if defined( __i386 ) || defined( __x86_64 )
    586467asm (
    587468        // HEADER
     
    598479        ".LLSDACSBCFA2:\n"
    599480        //      Handled area start (relative to start of function)
    600         "       .uleb128 .TRYSTART-__cfaehm_try_terminate\n"
     481        "       .uleb128 .TRYSTART-__cfaabi_ehm__try_terminate\n"
    601482        //      Handled area length
    602483        "       .uleb128 .TRYEND-.TRYSTART\n"
    603484        //      Handler landing pad address (relative to start of function)
    604         "       .uleb128 .CATCH-__cfaehm_try_terminate\n"
     485        "       .uleb128 .CATCH-__cfaabi_ehm__try_terminate\n"
    605486        //      Action code, gcc seems to always use 0.
    606487        "       .uleb128 1\n"
     
    608489        ".LLSDACSECFA2:\n"
    609490        "       .text\n"
    610         "       .size   __cfaehm_try_terminate, .-__cfaehm_try_terminate\n"
     491        "       .size   __cfaabi_ehm__try_terminate, .-__cfaabi_ehm__try_terminate\n"
    611492        "       .ident  \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
    612         "       .section        .note.GNU-stack,\"x\",@progbits\n"
     493//      "       .section        .note.GNU-stack,\"x\",@progbits\n"
    613494);
    614 #endif // __PIC__
    615 
    616 #pragma GCC pop_options
    617 
    618 #elif defined( __ARM_ARCH )
    619 _Unwind_Reason_Code __gcfa_personality_v0(
    620                 int version,
    621                 _Unwind_Action actions,
    622                 unsigned long long exception_class,
    623                 struct _Unwind_Exception * unwind_exception,
    624                 struct _Unwind_Context * unwind_context) {
    625         return _URC_CONTINUE_UNWIND;
    626 }
    627 
    628 __attribute__((noinline))
    629 void __cfaehm_try_terminate(void (*try_block)(),
    630                 void (*catch_block)(int index, exception_t * except),
    631                 __attribute__((unused)) int (*match_block)(exception_t * except)) {
    632 }
    633 #else
    634         #error unsupported hardware architecture
    635 #endif // __x86_64 || __i386
     495#endif // __i386 || __x86_64
     496#endif // PIC
  • libcfa/src/exception.h

    reef8dfb rbdfc032  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // exception.h -- Internal exception handling definitions.
     7// exception.h -- Builtins for exception handling.
    88//
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:11:00 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct 27 14:45:00 2020
    13 // Update Count     : 11
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Feb 22 18:11:15 2018
     13// Update Count     : 8
    1414//
    1515
    1616#pragma once
    1717
    18 // This could be considered several headers. All are internal to the exception
    19 // system but needed to depending on whether they are C/Cforall code and
    20 // whether or not they are part of the builtins.
    2118
    2219#ifdef __cforall
     
    2421#endif
    2522
    26 // Included in C code or the built-ins.
    27 #if !defined(__cforall) || defined(__cforall_builtins__)
    28 
    29 struct __cfaehm_base_exception_t;
    30 typedef struct __cfaehm_base_exception_t exception_t;
    31 struct __cfaehm_base_exception_t_vtable {
    32         const struct __cfaehm_base_exception_t_vtable * parent;
     23struct __cfaabi_ehm__base_exception_t;
     24typedef struct __cfaabi_ehm__base_exception_t exception_t;
     25struct __cfaabi_ehm__base_exception_t_vtable {
     26        const struct __cfaabi_ehm__base_exception_t_vtable * parent;
    3327        size_t size;
    34         void (*copy)(struct __cfaehm_base_exception_t *this,
    35                      struct __cfaehm_base_exception_t * other);
    36         void (*free)(struct __cfaehm_base_exception_t *this);
    37         const char * (*msg)(struct __cfaehm_base_exception_t *this);
     28        void (*copy)(struct __cfaabi_ehm__base_exception_t *this,
     29                     struct __cfaabi_ehm__base_exception_t * other);
     30        void (*free)(struct __cfaabi_ehm__base_exception_t *this);
     31        const char * (*msg)(struct __cfaabi_ehm__base_exception_t *this);
    3832};
    39 struct __cfaehm_base_exception_t {
    40         struct __cfaehm_base_exception_t_vtable const * virtual_table;
     33struct __cfaabi_ehm__base_exception_t {
     34        struct __cfaabi_ehm__base_exception_t_vtable const * virtual_table;
    4135};
    42 extern struct __cfaehm_base_exception_t_vtable
    43         ___cfaehm_base_exception_t_vtable_instance;
     36extern struct __cfaabi_ehm__base_exception_t_vtable
     37        ___cfaabi_ehm__base_exception_t_vtable_instance;
    4438
    4539
    46 void __cfaehm_cancel_stack(exception_t * except) __attribute__((noreturn));
    47 
    4840// Used in throw statement translation.
    49 void __cfaehm_throw_terminate(exception_t * except, void (*)(exception_t *));
    50 void __cfaehm_rethrow_terminate() __attribute__((noreturn));
    51 void __cfaehm_throw_resume(exception_t * except, void (*)(exception_t *));
     41void __cfaabi_ehm__throw_terminate(exception_t * except) __attribute__((noreturn));
     42void __cfaabi_ehm__rethrow_terminate() __attribute__((noreturn));
     43void __cfaabi_ehm__throw_resume(exception_t * except);
    5244
    5345// Function catches termination exceptions.
    54 void __cfaehm_try_terminate(
    55         void (*try_block)(),
    56         void (*catch_block)(int index, exception_t * except),
    57         int (*match_block)(exception_t * except));
     46void __cfaabi_ehm__try_terminate(
     47    void (*try_block)(),
     48    void (*catch_block)(int index, exception_t * except),
     49    int (*match_block)(exception_t * except));
    5850
    5951// Clean-up the exception in catch blocks.
    60 void __cfaehm_cleanup_terminate(void * except);
     52void __cfaabi_ehm__cleanup_terminate(void * except);
    6153
    6254// Data structure creates a list of resume handlers.
    63 struct __cfaehm_try_resume_node {
    64         struct __cfaehm_try_resume_node * next;
    65         _Bool (*handler)(exception_t * except);
     55struct __cfaabi_ehm__try_resume_node {
     56    struct __cfaabi_ehm__try_resume_node * next;
     57    _Bool (*handler)(exception_t * except);
    6658};
    6759
    6860// These act as constructor and destructor for the resume node.
    69 void __cfaehm_try_resume_setup(
    70         struct __cfaehm_try_resume_node * node,
    71         _Bool (*handler)(exception_t * except));
    72 void __cfaehm_try_resume_cleanup(
    73         struct __cfaehm_try_resume_node * node);
     61void __cfaabi_ehm__try_resume_setup(
     62    struct __cfaabi_ehm__try_resume_node * node,
     63    _Bool (*handler)(exception_t * except));
     64void __cfaabi_ehm__try_resume_cleanup(
     65    struct __cfaabi_ehm__try_resume_node * node);
    7466
    7567// Check for a standard way to call fake deconstructors.
    76 struct __cfaehm_cleanup_hook {};
    77 
    78 #endif
    79 
    80 // Included in C code and the library.
    81 #if !defined(__cforall) || !defined(__cforall_builtins__)
    82 struct __cfaehm_node {
    83         struct _Unwind_Exception unwind_exception;
    84         struct __cfaehm_node * next;
    85         int handler_index;
    86 };
    87 
    88 static inline exception_t * __cfaehm_cancellation_exception(
    89                 struct _Unwind_Exception * unwind_exception ) {
    90         return (exception_t *)(1 + (struct __cfaehm_node *)unwind_exception);
    91 }
    92 #endif
     68struct __cfaabi_ehm__cleanup_hook {};
    9369
    9470#ifdef __cforall
    9571}
    96 
    97 // Built-ins not visible in C.
    98 #if defined(__cforall_builtins__)
    99 
    100 // Not all the built-ins can be expressed in C. These can't be
    101 // implemented in the .c file either so they all have to be inline.
    102 
    103 trait is_exception(dtype exceptT, dtype virtualT) {
    104         /* The first field must be a pointer to a virtual table.
    105          * That virtual table must be a decendent of the base exception virtual table.
    106          */
    107         virtualT const & get_exception_vtable(exceptT *);
    108         // Always returns the virtual table for this type (associated types hack).
    109 };
    110 
    111 trait is_termination_exception(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT)) {
    112         void defaultTerminationHandler(exceptT &);
    113 };
    114 
    115 trait is_resumption_exception(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT)) {
    116         void defaultResumptionHandler(exceptT &);
    117 };
    118 
    119 forall(dtype exceptT, dtype virtualT | is_termination_exception(exceptT, virtualT))
    120 static inline void $throw(exceptT & except) {
    121         __cfaehm_throw_terminate(
    122                 (exception_t *)&except,
    123                 (void(*)(exception_t *))defaultTerminationHandler
    124         );
    125 }
    126 
    127 forall(dtype exceptT, dtype virtualT | is_resumption_exception(exceptT, virtualT))
    128 static inline void $throwResume(exceptT & except) {
    129         __cfaehm_throw_resume(
    130                 (exception_t *)&except,
    131                 (void(*)(exception_t *))defaultResumptionHandler
    132         );
    133 }
    134 
    135 forall(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT))
    136 static inline void cancel_stack(exceptT & except) __attribute__((noreturn)) {
    137         __cfaehm_cancel_stack( (exception_t *)&except );
    138 }
    139 
    140 forall(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT))
    141 static inline void defaultTerminationHandler(exceptT & except) {
    142         return cancel_stack( except );
    143 }
    144 
    145 forall(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT))
    146 static inline void defaultResumptionHandler(exceptT & except) {
    147         throw except;
    148 }
    149 
    15072#endif
    151 
    152 #endif
  • libcfa/src/executor.cfa

    reef8dfb rbdfc032  
    44// buffer.
    55
     6#include <bits/containers.hfa>
    67#include <thread.hfa>
    7 #include <containers/list.hfa>
     8#include <stdio.h>
    89
    9 forall( dtype T | $dlistable(T, T) ) {
    10         monitor Buffer {                                                                        // unbounded buffer
    11                 dlist( T, T ) queue;                                                    // unbounded list of work requests
    12                 condition delay;
    13         }; // Buffer
     10forall( dtype T )
     11monitor Buffer {                                        // unbounded buffer
     12    __queue_t( T ) queue;                               // unbounded list of work requests
     13    condition delay;
     14}; // Buffer
     15forall( dtype T | is_node(T) ) {
     16    void insert( Buffer( T ) & mutex buf, T * elem ) with(buf) {
     17        append( queue, elem );                          // insert element into buffer
     18        signal( delay );                                // restart
     19    } // insert
    1420
    15         void insert( Buffer(T) & mutex buf, T * elem ) with(buf) {
    16                 dlist( T, T ) * qptr = &queue;                                  // workaround https://cforall.uwaterloo.ca/trac/ticket/166
    17                 insert_last( *qptr, *elem );                                    // insert element into buffer
    18                 signal( delay );                                                                // restart
    19         } // insert
     21    T * remove( Buffer( T ) & mutex buf ) with(buf) {
     22        if ( queue.head != 0 ) wait( delay );                   // no request to process ? => wait
     23//      return pop_head( queue );
     24    } // remove
     25} // distribution
    2026
    21         T * remove( Buffer(T) & mutex buf ) with(buf) {
    22                 dlist( T, T ) * qptr = &queue;                                  // workaround https://cforall.uwaterloo.ca/trac/ticket/166
    23                 // if ( (*qptr)`is_empty ) wait( delay );                       // no request to process ? => wait
    24           if ( (*qptr)`is_empty ) return 0p;                            // no request to process ? => wait
    25                 return &pop_first( *qptr );
    26         } // remove
    27 } // forall
     27struct WRequest {                                       // client request, no return
     28    void (* action)( void );
     29    WRequest * next;                                    // intrusive queue field
     30}; // WRequest
    2831
    29 struct WRequest {                                                                               // client request, no return
    30         void (* action)( void );
    31         DLISTED_MGD_IMPL_IN(WRequest)
    32 }; // WRequest
    33 DLISTED_MGD_IMPL_OUT(WRequest)
    34 
    35 void ?{}( WRequest & req ) with(req) { action = 0; }
    36 void ?{}( WRequest & req, void (* action)( void ) ) with(req) { req.action = action; }
     32WRequest *& get_next( WRequest & this ) { return this.next; }
     33void ?{}( WRequest & req ) with(req) { action = 0; next = 0; }
     34void ?{}( WRequest & req, void (* action)( void ) ) with(req) { req.action = action; next = 0; }
    3735bool stop( WRequest & req ) { return req.action == 0; }
    3836void doit( WRequest & req ) { req.action(); }
    3937
    40 // Each worker has its own set (when requests buffers > workers) of work buffers to reduce contention between client
    41 // and server, where work requests arrive and are distributed into buffers in a roughly round-robin order.
     38// Each worker has its own work buffer to reduce contention between client and server. Hence, work requests arrive and
     39// are distributed into buffers in a roughly round-robin order.
    4240
    4341thread Worker {
    44         Buffer(WRequest) * requests;
    45         WRequest * request;
    46         unsigned int start, range;
     42    Buffer( WRequest ) * requests;
     43    unsigned int start, range;
    4744}; // Worker
    4845
    4946void main( Worker & w ) with(w) {
    50         for ( int i = 0;; i = (i + 1) % range ) {
    51                 request = remove( requests[i + start] );
    52           if ( ! request ) { yield(); continue; }
    53           if ( stop( *request ) ) break;
    54                 doit( *request );
    55                 delete( request );
    56         } // for
     47    for ( int i = 0;; i = (i + 1) % range ) {
     48        WRequest * request = remove( requests[i + start] );
     49      if ( ! request ) { yield(); continue; }
     50      if ( stop( *request ) ) break;
     51        doit( *request );
     52        delete( request );
     53    } // for
    5754} // Worker::main
    5855
    59 void ?{}( Worker & worker, cluster * wc, Buffer(WRequest) * requests, unsigned int start, unsigned int range ) {
    60         ((thread &)worker){ *wc };
    61         worker.[requests, request, start, range] = [requests, 0p, start, range];
     56void ?{}( Worker & worker, cluster * wc, Buffer( WRequest ) * requests, unsigned int start, unsigned int range ) {
     57    (*get_thread(worker)){ *wc };                       // create on given cluster
     58    worker.[requests, start, range] = [requests, start, range];
    6259} // ?{}
    6360
    64 WRequest * current_request( Worker & worker ) { return worker.request; }
    65 
    6661struct Executor {
    67         cluster * cluster;                                                                      // if workers execute on separate cluster
    68         processor ** processors;                                                        // array of virtual processors adding parallelism for workers
    69         Buffer(WRequest) * requests;                                            // list of work requests
    70         Worker ** workers;                                                                      // array of workers executing work requests
    71         unsigned int nprocessors, nworkers, nrqueues;           // number of processors/threads/request queues
    72         bool sepClus;                                                                           // use same or separate cluster for executor
    73         unsigned int next;                                                                      // demultiplexed across worker buffers
     62    cluster * cluster;                                  // if workers execute on separate cluster
     63    processor ** processors;                            // array of virtual processors adding parallelism for workers
     64    Buffer( WRequest ) * requests;                      // list of work requests
     65    Worker ** workers;                                  // array of workers executing work requests
     66    unsigned int nprocessors, nworkers, nmailboxes;     // number of mailboxes/workers/processor tasks
     67    bool sepClus;                                       // use same or separate cluster for executor
    7468}; // Executor
    7569
     70static thread_local unsigned int next;                  // demultiplexed across worker buffers
    7671unsigned int tickets( Executor & ex ) with(ex) {
    77         //return uFetchAdd( next, 1 ) % nrqueues;
    78         return next++ % nrqueues;                                                       // no locking, interference randomizes
     72    //return uFetchAdd( next, 1 ) % nmailboxes;
     73    return next++ % nmailboxes;                         // no locking, interference randomizes
    7974} // tickets
    8075
    81 void ?{}( Executor & ex, unsigned int np, unsigned int nw, unsigned int nr, bool sc = false ) with(ex) {
    82         [nprocessors, nworkers, nrqueues, sepClus] = [np, nw, nr, sc];
    83         assert( nrqueues >= nworkers );
    84         cluster = sepClus ? new( "Executor" ) : active_cluster();
    85         processors = aalloc( nprocessors );
    86         requests = anew( nrqueues );
    87         workers = aalloc( nworkers );
     76void ?{}( Executor & ex, unsigned int np, unsigned int nw, unsigned int nm, bool sc = false ) with(ex) {
     77    [nprocessors, nworkers, nmailboxes, sepClus] = [np, nw, nm, sc];
     78    assert( nmailboxes >= nworkers );
     79    cluster = sepClus ? new( "Executor" ) : active_cluster();
     80    processors = (processor **)anew( nprocessors );
     81    requests = anew( nmailboxes );
     82    workers = (Worker **)anew( nworkers );
    8883
    89         for ( i; nprocessors ) {
    90                 processors[i] = new( *cluster );
    91         } // for
     84    for ( i; nprocessors ) {
     85        processors[ i ] = new( *cluster );
     86    } // for
    9287
    93         unsigned int reqPerWorker = nrqueues / nworkers, extras = nrqueues % nworkers;
    94 //      for ( unsigned int i = 0, start = 0, range; i < nworkers; i += 1, start += range ) {
    95     for ( i; nworkers : start; 0u ~ @ ~ range : range; ) {
    96             range = reqPerWorker + ( i < extras ? 1 : 0 );
    97                 workers[i] = new( cluster, requests, start, range );
    98         } // for
     88    unsigned int reqPerWorker = nmailboxes / nworkers, extras = nmailboxes % nworkers;
     89    for ( unsigned int i = 0, step = 0; i < nworkers; i += 1, step += reqPerWorker + ( i < extras ? 1 : 0 ) ) {
     90        workers[ i ] = new( cluster, requests, step, reqPerWorker + ( i < extras ? 1 : 0 ) );
     91    } // for
    9992} // ?{}
    10093
    10194void ?{}( Executor & ex, unsigned int nprocessors, unsigned int nworkers, bool sepClus = false ) {
    102         ex{ nprocessors, nworkers, nworkers, sepClus };
     95    ex{ nprocessors, nworkers, nworkers, sepClus };
    10396}
    10497void ?{}( Executor & ex, unsigned int nprocessors, bool sepClus = false ) {
    105         ex{ nprocessors, nprocessors, nprocessors, sepClus };
     98    ex{ nprocessors, nprocessors, nprocessors, sepClus };
    10699}
    107 void ?{}( Executor & ex ) {                                                             // special for current cluster, no processors added
    108         ex{ 0, active_cluster()->nprocessors, false };
     100void ?{}( Executor & ex ) {                             // special for current cluster
     101    ex{ 0, active_cluster()->nprocessors, false };
    109102}
    110103void ^?{}( Executor & ex ) with(ex) {
    111         // Add one sentinel per worker to stop them. Since in destructor, no new external work should be queued.  Cannot
    112         // combine next two loops and only have a single sentinel because workers arrive in arbitrary order, so worker1 may
    113         // take the single sentinel while waiting for worker 0 to end.
     104    // Add one sentinel per worker to stop them. Since in destructor, no new work should be queued.  Cannot combine next
     105    // two loops and only have a single sentinel because workers arrive in arbitrary order, so worker1 may take the
     106    // single sentinel while waiting for worker 0 to end.
    114107
    115         WRequest sentinel[nworkers];
    116         unsigned int reqPerWorker = nrqueues / nworkers;
    117         for ( unsigned int i = 0, step = 0; i < nworkers; i += 1, step += reqPerWorker ) {
    118                 insert( requests[step], &sentinel[i] );                 // force eventually termination
    119         } // for
    120         for ( i; nworkers ) {
    121                 delete( workers[i] );
    122         } // for
    123         for ( i; nprocessors ) {
    124                 delete( processors[i] );
    125         } // for
     108    WRequest sentinel[nworkers];
     109    unsigned int reqPerWorker = nmailboxes / nworkers;
     110    for ( unsigned int i = 0, step = 0; i < nworkers; i += 1, step += reqPerWorker ) {
     111        insert( requests[step], &sentinel[i] );         // force eventually termination
     112    } // for
     113    for ( i; nworkers ) {
     114        delete( workers[ i ] );
     115    } // for
     116    for ( i; nprocessors ) {
     117        delete( processors[ i ] );
     118    } // for
    126119
    127         free( workers );
    128 //      adelete( nrqueues, requests );
    129         for ( i; nrqueues ) ^?{}( requests[i] );                        // FIX ME: problem with resolver
    130         free( requests );
    131         free( processors );
    132         if ( sepClus ) { delete( cluster ); }
     120    delete( workers );
     121    delete( requests );
     122    delete( processors );
     123    if ( sepClus ) { delete( cluster ); }
    133124} // ^?{}
    134125
    135126void send( Executor & ex, void (* action)( void ) ) {   // asynchronous call, no return value
    136         WRequest * node = new( action );
    137         insert( ex.requests[tickets( ex )], node );
     127    WRequest * node = new( action );
     128    insert( ex.requests[tickets( ex )], node );
    138129} // send
    139 
    140130
    141131int counter = 0;
    142132
    143 void work( void ) {
    144         __atomic_add_fetch( &counter, 1, __ATOMIC_SEQ_CST );
    145         // fprintf( stderr, "workie\n" );
     133void workie( void ) {
     134    __atomic_add_fetch( &counter, 1, __ATOMIC_SEQ_CST );
     135//    fprintf( stderr, "workie\n" );
    146136}
    147137
    148 int main( int argc, char * argv[] ) {
    149         int times = 1_000_000;
    150         if ( argc == 2 ) times = atoi( argv[1] );
    151         processor p[7];
    152         {
    153                 Executor exector;
    154                 for ( i; times ) {
    155                         send( exector, work );
    156                         if ( i % 100 == 0 ) yield();
    157                 } // for
    158         }
    159         printf( "%d\n", counter );
     138int main() {
     139    {
     140        Executor exector;
     141        for ( i; 3000 ) {
     142            send( exector, workie );
     143            if ( i % 100 ) yield();
     144        } // for
     145    }
     146    printf( "%d\n", counter );
    160147}
    161148
    162149// Local Variables: //
    163 // tab-width: 4" //
    164150// compile-command: "cfa executor.cfa" //
    165151// End: //
  • libcfa/src/fstream.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 19 16:24:54 2020
    13 // Update Count     : 384
     12// Last Modified On : Fri Nov 29 06:56:46 2019
     13// Update Count     : 355
    1414//
    1515
     
    2626
    2727
    28 // *********************************** ofstream ***********************************
     28//*********************************** ofstream ***********************************
    2929
    3030
     
    3232
    3333void ?{}( ofstream & os, void * file ) {
    34         os.$file = file;
    35         os.$sepDefault = true;
    36         os.$sepOnOff = false;
    37         os.$nlOnOff = true;
    38         os.$prt = false;
    39         os.$sawNL = false;
    40         $sepSetCur( os, sepGet( os ) );
     34        os.file = file;
     35        os.sepDefault = true;
     36        os.sepOnOff = false;
     37        os.nlOnOff = true;
     38        os.prt = false;
     39        os.sawNL = false;
    4140        sepSet( os, " " );
     41        sepSetCur( os, sepGet( os ) );
    4242        sepSetTuple( os, ", " );
    4343} // ?{}
    4444
    4545// private
    46 bool $sepPrt( ofstream & os ) { $setNL( os, false ); return os.$sepOnOff; }
    47 void $sepReset( ofstream & os ) { os.$sepOnOff = os.$sepDefault; }
    48 void $sepReset( ofstream & os, bool reset ) { os.$sepDefault = reset; os.$sepOnOff = os.$sepDefault; }
    49 const char * $sepGetCur( ofstream & os ) { return os.$sepCur; }
    50 void $sepSetCur( ofstream & os, const char sepCur[] ) { os.$sepCur = sepCur; }
    51 bool $getNL( ofstream & os ) { return os.$sawNL; }
    52 void $setNL( ofstream & os, bool state ) { os.$sawNL = state; }
    53 bool $getANL( ofstream & os ) { return os.$nlOnOff; }
    54 bool $getPrt( ofstream & os ) { return os.$prt; }
    55 void $setPrt( ofstream & os, bool state ) { os.$prt = state; }
     46bool sepPrt( ofstream & os ) { setNL( os, false ); return os.sepOnOff; }
     47void sepReset( ofstream & os ) { os.sepOnOff = os.sepDefault; }
     48void sepReset( ofstream & os, bool reset ) { os.sepDefault = reset; os.sepOnOff = os.sepDefault; }
     49const char * sepGetCur( ofstream & os ) { return os.sepCur; }
     50void sepSetCur( ofstream & os, const char * sepCur ) { os.sepCur = sepCur; }
     51bool getNL( ofstream & os ) { return os.sawNL; }
     52void setNL( ofstream & os, bool state ) { os.sawNL = state; }
     53bool getANL( ofstream & os ) { return os.nlOnOff; }
     54bool getPrt( ofstream & os ) { return os.prt; }
     55void setPrt( ofstream & os, bool state ) { os.prt = state; }
    5656
    5757// public
    58 void ?{}( ofstream & os ) { os.$file = 0p; }
    59 
    60 void ?{}( ofstream & os, const char name[], const char mode[] ) {
     58void ?{}( ofstream & os ) { os.file = 0; }
     59
     60void ?{}( ofstream & os, const char * name, const char * mode ) {
    6161        open( os, name, mode );
    6262} // ?{}
    6363
    64 void ?{}( ofstream & os, const char name[] ) {
     64void ?{}( ofstream & os, const char * name ) {
    6565        open( os, name, "w" );
    6666} // ?{}
     
    7070} // ^?{}
    7171
    72 void sepOn( ofstream & os ) { os.$sepOnOff = ! $getNL( os ); }
    73 void sepOff( ofstream & os ) { os.$sepOnOff = false; }
     72void sepOn( ofstream & os ) { os.sepOnOff = ! getNL( os ); }
     73void sepOff( ofstream & os ) { os.sepOnOff = false; }
    7474
    7575bool sepDisable( ofstream & os ) {
    76         bool temp = os.$sepDefault;
    77         os.$sepDefault = false;
    78         $sepReset( os );
     76        bool temp = os.sepDefault;
     77        os.sepDefault = false;
     78        sepReset( os );
    7979        return temp;
    8080} // sepDisable
    8181
    8282bool sepEnable( ofstream & os ) {
    83         bool temp = os.$sepDefault;
    84         os.$sepDefault = true;
    85         if ( os.$sepOnOff ) $sepReset( os );                            // start of line ?
     83        bool temp = os.sepDefault;
     84        os.sepDefault = true;
     85        if ( os.sepOnOff ) sepReset( os );                                      // start of line ?
    8686        return temp;
    8787} // sepEnable
    8888
    89 void nlOn( ofstream & os ) { os.$nlOnOff = true; }
    90 void nlOff( ofstream & os ) { os.$nlOnOff = false; }
    91 
    92 const char * sepGet( ofstream & os ) { return os.$separator; }
    93 void sepSet( ofstream & os, const char s[] ) {
     89void nlOn( ofstream & os ) { os.nlOnOff = true; }
     90void nlOff( ofstream & os ) { os.nlOnOff = false; }
     91
     92const char * sepGet( ofstream & os ) { return os.separator; }
     93void sepSet( ofstream & os, const char * s ) {
    9494        assert( s );
    95         strncpy( os.$separator, s, sepSize - 1 );
    96         os.$separator[sepSize - 1] = '\0';
     95        strncpy( os.separator, s, sepSize - 1 );
     96        os.separator[sepSize - 1] = '\0';
    9797} // sepSet
    9898
    99 const char * sepGetTuple( ofstream & os ) { return os.$tupleSeparator; }
    100 void sepSetTuple( ofstream & os, const char s[] ) {
     99const char * sepGetTuple( ofstream & os ) { return os.tupleSeparator; }
     100void sepSetTuple( ofstream & os, const char * s ) {
    101101        assert( s );
    102         strncpy( os.$tupleSeparator, s, sepSize - 1 );
    103         os.$tupleSeparator[sepSize - 1] = '\0';
     102        strncpy( os.tupleSeparator, s, sepSize - 1 );
     103        os.tupleSeparator[sepSize - 1] = '\0';
    104104} // sepSet
    105105
    106106void ends( ofstream & os ) {
    107         if ( $getANL( os ) ) nl( os );
    108         else $setPrt( os, false );                                                      // turn off
     107        if ( getANL( os ) ) nl( os );
     108        else setPrt( os, false );                                                       // turn off
    109109        if ( &os == &exit ) exit( EXIT_FAILURE );
    110110        if ( &os == &abort ) abort();
     
    112112
    113113int fail( ofstream & os ) {
    114         return os.$file == 0 || ferror( (FILE *)(os.$file) );
     114        return os.file == 0 || ferror( (FILE *)(os.file) );
    115115} // fail
    116116
    117117int flush( ofstream & os ) {
    118         return fflush( (FILE *)(os.$file) );
     118        return fflush( (FILE *)(os.file) );
    119119} // flush
    120120
    121 void open( ofstream & os, const char name[], const char mode[] ) {
     121void open( ofstream & os, const char * name, const char * mode ) {
    122122        FILE * file = fopen( name, mode );
    123123        #ifdef __CFA_DEBUG__
    124         if ( file == 0p ) {
    125                 throw (Open_Failure){ os };
    126                 // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
     124        if ( file == 0 ) {
     125                abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
    127126        } // if
    128127        #endif // __CFA_DEBUG__
     
    130129} // open
    131130
    132 void open( ofstream & os, const char name[] ) {
     131void open( ofstream & os, const char * name ) {
    133132        open( os, name, "w" );
    134133} // open
    135134
    136135void close( ofstream & os ) {
    137   if ( (FILE *)(os.$file) == 0p ) return;
    138   if ( (FILE *)(os.$file) == (FILE *)stdout || (FILE *)(os.$file) == (FILE *)stderr ) return;
    139 
    140         if ( fclose( (FILE *)(os.$file) ) == EOF ) {
     136        if ( (FILE *)(os.file) == stdout || (FILE *)(os.file) == stderr ) return;
     137
     138        if ( fclose( (FILE *)(os.file) ) == EOF ) {
    141139                abort | IO_MSG "close output" | nl | strerror( errno );
    142140        } // if
    143         os.$file = 0p;
    144141} // close
    145142
    146 ofstream & write( ofstream & os, const char data[], size_t size ) {
     143ofstream & write( ofstream & os, const char * data, size_t size ) {
    147144        if ( fail( os ) ) {
    148145                abort | IO_MSG "attempt write I/O on failed stream";
    149146        } // if
    150147
    151         if ( fwrite( data, 1, size, (FILE *)(os.$file) ) != size ) {
     148        if ( fwrite( data, 1, size, (FILE *)(os.file) ) != size ) {
    152149                abort | IO_MSG "write" | nl | strerror( errno );
    153150        } // if
     
    158155        va_list args;
    159156        va_start( args, format );
    160         int len = vfprintf( (FILE *)(os.$file), format, args );
     157        int len = vfprintf( (FILE *)(os.file), format, args );
    161158        if ( len == EOF ) {
    162                 if ( ferror( (FILE *)(os.$file) ) ) {
     159                if ( ferror( (FILE *)(os.file) ) ) {
    163160                        abort | IO_MSG "invalid write";
    164161                } // if
     
    166163        va_end( args );
    167164
    168         $setPrt( os, true );                                                            // called in output cascade
    169         $sepReset( os );                                                                        // reset separator
     165        setPrt( os, true );                                                                     // called in output cascade
     166        sepReset( os );                                                                         // reset separator
    170167        return len;
    171168} // fmt
     
    182179
    183180
    184 // *********************************** ifstream ***********************************
     181//*********************************** ifstream ***********************************
    185182
    186183
    187184// private
    188185void ?{}( ifstream & is, void * file ) {
    189         is.$file = file;
    190         is.$nlOnOff = false;
     186        is.file = file;
     187        is.nlOnOff = false;
    191188} // ?{}
    192189
    193190// public
    194 void ?{}( ifstream & is ) { is.$file = 0p; }
    195 
    196 void ?{}( ifstream & is, const char name[], const char mode[] ) {
     191void ?{}( ifstream & is ) {     is.file = 0; }
     192
     193void ?{}( ifstream & is, const char * name, const char * mode ) {
    197194        open( is, name, mode );
    198195} // ?{}
    199196
    200 void ?{}( ifstream & is, const char name[] ) {
     197void ?{}( ifstream & is, const char * name ) {
    201198        open( is, name, "r" );
    202199} // ?{}
     
    206203} // ^?{}
    207204
    208 void nlOn( ifstream & os ) { os.$nlOnOff = true; }
    209 void nlOff( ifstream & os ) { os.$nlOnOff = false; }
    210 bool getANL( ifstream & os ) { return os.$nlOnOff; }
     205void nlOn( ifstream & os ) { os.nlOnOff = true; }
     206void nlOff( ifstream & os ) { os.nlOnOff = false; }
     207bool getANL( ifstream & os ) { return os.nlOnOff; }
    211208
    212209int fail( ifstream & is ) {
    213         return is.$file == 0p || ferror( (FILE *)(is.$file) );
     210        return is.file == 0 || ferror( (FILE *)(is.file) );
    214211} // fail
    215212
    216213int eof( ifstream & is ) {
    217         return feof( (FILE *)(is.$file) );
     214        return feof( (FILE *)(is.file) );
    218215} // eof
    219216
    220 void open( ifstream & is, const char name[], const char mode[] ) {
     217void open( ifstream & is, const char * name, const char * mode ) {
    221218        FILE * file = fopen( name, mode );
    222219        #ifdef __CFA_DEBUG__
    223         if ( file == 0p ) {
    224                 throw (Open_Failure){ is };
    225                 // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
     220        if ( file == 0 ) {
     221                abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
    226222        } // if
    227223        #endif // __CFA_DEBUG__
    228         is.$file = file;
    229 } // open
    230 
    231 void open( ifstream & is, const char name[] ) {
     224        is.file = file;
     225} // open
     226
     227void open( ifstream & is, const char * name ) {
    232228        open( is, name, "r" );
    233229} // open
    234230
    235231void close( ifstream & is ) {
    236   if ( (FILE *)(is.$file) == 0p ) return;
    237   if ( (FILE *)(is.$file) == (FILE *)stdin ) return;
    238 
    239         if ( fclose( (FILE *)(is.$file) ) == EOF ) {
     232        if ( (FILE *)(is.file) == stdin ) return;
     233
     234        if ( fclose( (FILE *)(is.file) ) == EOF ) {
    240235                abort | IO_MSG "close input" | nl | strerror( errno );
    241236        } // if
    242         is.$file = 0p;
    243237} // close
    244238
     
    248242        } // if
    249243
    250         if ( fread( data, size, 1, (FILE *)(is.$file) ) == 0 ) {
     244        if ( fread( data, size, 1, (FILE *)(is.file) ) == 0 ) {
    251245                abort | IO_MSG "read" | nl | strerror( errno );
    252246        } // if
     
    259253        } // if
    260254
    261         if ( ungetc( c, (FILE *)(is.$file) ) == EOF ) {
     255        if ( ungetc( c, (FILE *)(is.file) ) == EOF ) {
    262256                abort | IO_MSG "ungetc" | nl | strerror( errno );
    263257        } // if
     
    269263
    270264        va_start( args, format );
    271         int len = vfscanf( (FILE *)(is.$file), format, args );
     265        int len = vfscanf( (FILE *)(is.file), format, args );
    272266        if ( len == EOF ) {
    273                 if ( ferror( (FILE *)(is.$file) ) ) {
     267                if ( ferror( (FILE *)(is.file) ) ) {
    274268                        abort | IO_MSG "invalid read";
    275269                } // if
     
    282276ifstream & sin = sinFile, & stdin = sinFile;
    283277
    284 
    285 // *********************************** exceptions ***********************************
    286 
    287 
    288 void ?{}( Open_Failure & this, ofstream & ostream ) {
    289         VTABLE_INIT(this, Open_Failure);
    290         this.ostream = &ostream;
    291         this.tag = 1;
    292 }
    293 void ?{}( Open_Failure & this, ifstream & istream ) {
    294         VTABLE_INIT(this, Open_Failure);
    295         this.istream = &istream;
    296         this.tag = 0;
    297 }
    298 const char * Open_Failure_msg(Open_Failure * this) {
    299         return "Open_Failure";
    300 }
    301 VTABLE_INSTANCE(Open_Failure)(Open_Failure_msg);
    302 void throwOpen_Failure( ofstream & ostream ) {
    303         Open_Failure exc = { ostream };
    304 }
    305 void throwOpen_Failure( ifstream & istream ) {
    306         Open_Failure exc = { istream };
    307 }
    308 
    309278// Local Variables: //
    310279// tab-width: 4 //
  • libcfa/src/fstream.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 19 16:29:17 2020
    13 // Update Count     : 189
     12// Last Modified On : Fri Nov 29 06:56:02 2019
     13// Update Count     : 168
    1414//
    1515
     
    1717
    1818#include "iostream.hfa"
    19 #include <exception.hfa>
    2019
    2120
    22 // *********************************** ofstream ***********************************
     21//*********************************** ofstream ***********************************
    2322
    2423
    2524enum { sepSize = 16 };
    2625struct ofstream {
    27         void * $file;
    28         bool $sepDefault;
    29         bool $sepOnOff;
    30         bool $nlOnOff;
    31         bool $prt;                                                                                      // print text
    32         bool $sawNL;
    33         const char * $sepCur;
    34         char $separator[sepSize];
    35         char $tupleSeparator[sepSize];
     26        void * file;
     27        bool sepDefault;
     28        bool sepOnOff;
     29        bool nlOnOff;
     30        bool prt;                                                                                       // print text
     31        bool sawNL;
     32        const char * sepCur;
     33        char separator[sepSize];
     34        char tupleSeparator[sepSize];
    3635}; // ofstream
    3736
    3837// private
    39 bool $sepPrt( ofstream & );
    40 void $sepReset( ofstream & );
    41 void $sepReset( ofstream &, bool );
    42 const char * $sepGetCur( ofstream & );
    43 void $sepSetCur( ofstream &, const char [] );
    44 bool $getNL( ofstream & );
    45 void $setNL( ofstream &, bool );
    46 bool $getANL( ofstream & );
    47 bool $getPrt( ofstream & );
    48 void $setPrt( ofstream &, bool );
     38bool sepPrt( ofstream & );
     39void sepReset( ofstream & );
     40void sepReset( ofstream &, bool );
     41const char * sepGetCur( ofstream & );
     42void sepSetCur( ofstream &, const char * );
     43bool getNL( ofstream & );
     44void setNL( ofstream &, bool );
     45bool getANL( ofstream & );
     46bool getPrt( ofstream & );
     47void setPrt( ofstream &, bool );
    4948
    5049// public
     
    5756
    5857const char * sepGet( ofstream & );
    59 void sepSet( ofstream &, const char [] );
     58void sepSet( ofstream &, const char * );
    6059const char * sepGetTuple( ofstream & );
    61 void sepSetTuple( ofstream &, const char [] );
     60void sepSetTuple( ofstream &, const char * );
    6261
    6362void ends( ofstream & os );
    6463int fail( ofstream & );
    6564int flush( ofstream & );
    66 void open( ofstream &, const char name[], const char mode[] );
    67 void open( ofstream &, const char name[] );
     65void open( ofstream &, const char * name, const char * mode );
     66void open( ofstream &, const char * name );
    6867void close( ofstream & );
    69 ofstream & write( ofstream &, const char data[], size_t size );
    70 int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
     68ofstream & write( ofstream &, const char * data, size_t size );
     69int fmt( ofstream &, const char format[], ... );
    7170
    7271void ?{}( ofstream & os );
    73 void ?{}( ofstream & os, const char name[], const char mode[] );
    74 void ?{}( ofstream & os, const char name[] );
     72void ?{}( ofstream & os, const char * name, const char * mode );
     73void ?{}( ofstream & os, const char * name );
    7574void ^?{}( ofstream & os );
    7675
     
    7978
    8079
    81 // *********************************** ifstream ***********************************
     80//*********************************** ifstream ***********************************
    8281
    8382
    8483struct ifstream {
    85         void * $file;
    86         bool $nlOnOff;
     84        void * file;
     85        bool nlOnOff;
    8786}; // ifstream
    8887
     
    9392int fail( ifstream & is );
    9493int eof( ifstream & is );
    95 void open( ifstream & is, const char name[], const char mode[] );
    96 void open( ifstream & is, const char name[] );
     94void open( ifstream & is, const char * name, const char * mode );
     95void open( ifstream & is, const char * name );
    9796void close( ifstream & is );
    9897ifstream & read( ifstream & is, char * data, size_t size );
    9998ifstream & ungetc( ifstream & is, char c );
    100 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     99int fmt( ifstream &, const char format[], ... );
    101100
    102101void ?{}( ifstream & is );
    103 void ?{}( ifstream & is, const char name[], const char mode[] );
    104 void ?{}( ifstream & is, const char name[] );
     102void ?{}( ifstream & is, const char * name, const char * mode );
     103void ?{}( ifstream & is, const char * name );
    105104void ^?{}( ifstream & is );
    106105
    107106extern ifstream & sin, & stdin;                                                 // aliases
    108 
    109 
    110 // *********************************** exceptions ***********************************
    111 
    112 
    113 DATA_EXCEPTION(Open_Failure)(
    114         union {
    115                 ofstream * ostream;
    116                 ifstream * istream;
    117         };
    118         // TEMPORARY: need polymorphic exceptions
    119         int tag;                                                                                        // 1 => ostream; 0 => istream
    120 );
    121 
    122 void ?{}( Open_Failure & this, ofstream & ostream );
    123 void ?{}( Open_Failure & this, ifstream & istream );
    124107
    125108// Local Variables: //
  • libcfa/src/gmp.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Apr 19 08:43:43 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb  9 09:56:54 2020
    13 // Update Count     : 31
     12// Last Modified On : Sat Jul 13 15:25:05 2019
     13// Update Count     : 27
    1414//
    1515
     
    2424
    2525static inline {
    26         // constructor, zero_t/one_t are unnecessary because of relationship with signed/unsigned int
     26        // constructor
    2727        void ?{}( Int & this ) { mpz_init( this.mpz ); }
    2828        void ?{}( Int & this, Int init ) { mpz_init_set( this.mpz, init.mpz ); }
     29        void ?{}( Int & this, zero_t ) { mpz_init_set_si( this.mpz, 0 ); }
     30        void ?{}( Int & this, one_t ) { mpz_init_set_si( this.mpz, 1 ); }
    2931        void ?{}( Int & this, signed long int init ) { mpz_init_set_si( this.mpz, init ); }
    3032        void ?{}( Int & this, unsigned long int init ) { mpz_init_set_ui( this.mpz, init ); }
    31         void ?{}( Int & this, const char val[] ) { if ( mpz_init_set_str( this.mpz, val, 0 ) ) abort(); }
     33        void ?{}( Int & this, const char * val ) { if ( mpz_init_set_str( this.mpz, val, 0 ) ) abort(); }
    3234        void ^?{}( Int & this ) { mpz_clear( this.mpz ); }
    3335
     
    3537        Int ?`mp( signed long int init ) { return (Int){ init }; }
    3638        Int ?`mp( unsigned long int init ) { return (Int){ init }; }
    37         Int ?`mp( const char init[] ) { return (Int){ init }; }
     39        Int ?`mp( const char * init ) { return (Int){ init }; }
    3840
    3941        // assignment
     
    4143        Int ?=?( Int & lhs, long int rhs ) { mpz_set_si( lhs.mpz, rhs ); return lhs; }
    4244        Int ?=?( Int & lhs, unsigned long int rhs ) { mpz_set_ui( lhs.mpz, rhs ); return lhs; }
    43         Int ?=?( Int & lhs, const char rhs[] ) { if ( mpz_set_str( lhs.mpz, rhs, 0 ) ) { abort | "invalid string conversion"; } return lhs; }
     45        Int ?=?( Int & lhs, const char * rhs ) { if ( mpz_set_str( lhs.mpz, rhs, 0 ) ) { abort | "invalid string conversion"; } return lhs; }
    4446
    4547        char ?=?( char & lhs, Int rhs ) { char val = mpz_get_si( rhs.mpz ); lhs = val; return lhs; }
     
    263265        forall( dtype ostype | ostream( ostype ) ) {
    264266                ostype & ?|?( ostype & os, Int mp ) {
    265                         if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     267                        if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    266268                        gmp_printf( "%Zd", mp.mpz );
    267269                        sepOn( os );
  • libcfa/src/heap.cfa

    reef8dfb rbdfc032  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // heap.cfa --
     7// heap.c --
    88//
    99// Author           : Peter A. Buhr
    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 : Sun Dec  8 21:01:31 2019
     13// Update Count     : 647
    1414//
    1515
    1616#include <unistd.h>                                                                             // sbrk, sysconf
    17 #include <stdlib.h>                                                                             // EXIT_FAILURE
    1817#include <stdbool.h>                                                                    // true, false
    1918#include <stdio.h>                                                                              // snprintf, fileno
    2019#include <errno.h>                                                                              // errno
    2120#include <string.h>                                                                             // memset, memcpy
    22 #include <limits.h>                                                                             // ULONG_MAX
    23 #include <malloc.h>                                                                             // memalign, malloc_usable_size
     21extern "C" {
    2422#include <sys/mman.h>                                                                   // mmap, munmap
    25 
    26 #include "bits/align.hfa"                                                               // libAlign
     23} // extern "C"
     24
     25// #comment TD : Many of these should be merged into math I believe
     26#include "bits/align.hfa"                                                               // libPow2
    2727#include "bits/defs.hfa"                                                                // likely, unlikely
    2828#include "bits/locks.hfa"                                                               // __spinlock_t
    2929#include "startup.hfa"                                                                  // STARTUP_PRIORITY_MEMORY
    30 #include "math.hfa"                                                                             // ceiling
    31 #include "bitmanip.hfa"                                                                 // is_pow2, ceiling2
     30//#include "stdlib.hfa"                                                                 // bsearchl
     31#include "malloc.h"
     32
     33#define MIN(x, y) (y > x ? x : y)
    3234
    3335static bool traceHeap = false;
     
    7274        // Define the default extension heap amount in units of bytes. When the uC++ supplied heap reaches the brk address,
    7375        // the brk address is extended by the extension amount.
    74         __CFA_DEFAULT_HEAP_EXPANSION__ = (10 * 1024 * 1024),
     76        __CFA_DEFAULT_HEAP_EXPANSION__ = (1 * 1024 * 1024),
    7577
    7678        // Define the mmap crossover point during allocation. Allocations less than this amount are allocated from buckets;
     
    8991
    9092#ifdef __CFA_DEBUG__
    91 static size_t allocUnfreed;                                                             // running total of allocations minus frees
     93static unsigned int allocFree;                                                  // running total of allocations minus frees
    9294
    9395static void prtUnfreed() {
    94         if ( allocUnfreed != 0 ) {
     96        if ( allocFree != 0 ) {
    9597                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    9698                char helpText[512];
    97                 int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %zu(0x%zx) bytes of storage allocated but not freed.\n"
     99                int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %u(0x%x) bytes of storage allocated but not freed.\n"
    98100                                                        "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
    99                                                         (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid
     101                                                        (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid
    100102                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    101103        } // if
     
    104106extern "C" {
    105107        void heapAppStart() {                                                           // called by __cfaabi_appready_startup
    106                 allocUnfreed = 0;
     108                allocFree = 0;
    107109        } // heapAppStart
    108110
     
    116118
    117119// statically allocated variables => zero filled.
    118 size_t __page_size;                                                                             // architecture pagesize
    119 int __map_prot;                                                                                 // common mmap/mprotect protection
     120static size_t pageSize;                                                                 // architecture pagesize
    120121static size_t heapExpand;                                                               // sbrk advance
    121122static size_t mmapStart;                                                                // cross over point for mmap
     
    126127#define LOCKFREE 1
    127128#define BUCKETLOCK SPINLOCK
    128 #if BUCKETLOCK == SPINLOCK
    129 #elif BUCKETLOCK == LOCKFREE
    130 #include <stackLockFree.hfa>
    131 #else
    132         #error undefined lock type for bucket lock
     129#if BUCKETLOCK == LOCKFREE
     130#include <uStackLF.h>
    133131#endif // LOCKFREE
    134132
     
    138136
    139137struct HeapManager {
     138//      struct FreeHeader;                                                                      // forward declaration
     139
    140140        struct Storage {
    141141                struct Header {                                                                 // header
     
    145145                                                struct {                                                // 4-byte word => 8-byte header, 8-byte word => 16-byte header
    146146                                                        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4
    147                                                         uint64_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
     147                                                        uint32_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
    148148                                                        #endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4
    149149
    150150                                                        union {
    151                                                                 // FreeHeader * home;           // allocated block points back to home locations (must overlay alignment)
    152                                                                 // 2nd low-order bit => zero filled
     151//                                                              FreeHeader * home;              // allocated block points back to home locations (must overlay alignment)
    153152                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    154153                                                                size_t blockSize;               // size for munmap (must overlay alignment)
    155                                                                 #if BUCKETLOCK == SPINLOCK
     154                                                                #if BUCKLOCK == SPINLOCK
    156155                                                                Storage * next;                 // freed block points next freed block of same size
    157156                                                                #endif // SPINLOCK
    158157                                                        };
    159                                                         size_t size;                            // allocation size in bytes
    160158
    161159                                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4
    162                                                         uint64_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
     160                                                        uint32_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
    163161                                                        #endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4
    164162                                                };
    165                                                 #if BUCKETLOCK == LOCKFREE
    166                                                 Link(Storage) next;                             // freed block points next freed block of same size (double-wide)
     163                                                // future code
     164                                                #if BUCKLOCK == LOCKFREE
     165                                                Stack<Storage>::Link next;              // freed block points next freed block of same size (double-wide)
    167166                                                #endif // LOCKFREE
    168167                                        };
    169168                                } real; // RealHeader
    170 
    171169                                struct FakeHeader {
    172170                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    173                                         uint32_t alignment;                                     // 1st low-order bit => fake header & alignment
     171                                        uint32_t alignment;                                     // low-order bits of home/blockSize used for tricks
    174172                                        #endif // __ORDER_LITTLE_ENDIAN__
    175173
     
    189187
    190188        struct FreeHeader {
    191                 #if BUCKETLOCK == SPINLOCK
     189                #if BUCKLOCK == SPINLOCK
    192190                __spinlock_t lock;                                                              // must be first field for alignment
    193191                Storage * freeList;
     192                #elif BUCKLOCK == LOCKFREE
     193                // future code
     194                StackLF<Storage> freeList;
    194195                #else
    195                 StackLF(Storage) freeList;
    196                 #endif // BUCKETLOCK
     196                        #error undefined lock type for bucket lock
     197                #endif // SPINLOCK
    197198                size_t blockSize;                                                               // size of allocations on this list
    198199        }; // FreeHeader
     
    207208}; // HeapManager
    208209
    209 #if BUCKETLOCK == LOCKFREE
    210 static inline {
    211         Link(HeapManager.Storage) * ?`next( HeapManager.Storage * this ) { return &this->header.kind.real.next; }
    212         void ?{}( HeapManager.FreeHeader & ) {}
    213         void ^?{}( HeapManager.FreeHeader & ) {}
    214 } // distribution
    215 #endif // LOCKFREE
    216 
    217210static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; }
    218211
     
    221214#define __STATISTICS__
    222215
    223 // Size of array must harmonize with NoBucketSizes and individual bucket sizes must be multiple of 16.
    224 // Smaller multiples of 16 and powers of 2 are common allocation sizes, so make them generate the minimum required bucket size.
    225 // malloc(0) returns 0p, so no bucket is necessary for 0 bytes returning an address that can be freed.
     216// Bucket size must be multiple of 16.
     217// Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size.
    226218static const unsigned int bucketSizes[] @= {                    // different bucket sizes
    227         16 + sizeof(HeapManager.Storage), 32 + sizeof(HeapManager.Storage), 48 + sizeof(HeapManager.Storage), 64 + sizeof(HeapManager.Storage), // 4
    228         96 + sizeof(HeapManager.Storage), 112 + sizeof(HeapManager.Storage), 128 + sizeof(HeapManager.Storage), // 3
     219        16, 32, 48, 64 + sizeof(HeapManager.Storage), // 4
     220        96, 112, 128 + sizeof(HeapManager.Storage), // 3
    229221        160, 192, 224, 256 + sizeof(HeapManager.Storage), // 4
    230222        320, 384, 448, 512 + sizeof(HeapManager.Storage), // 4
     
    244236};
    245237
    246 static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0] ), "size of bucket array wrong" );
     238static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0]), "size of bucket array wrong" );
    247239
    248240#ifdef FASTLOOKUP
     
    251243#endif // FASTLOOKUP
    252244
    253 static const off_t mmapFd = -1;                                                 // fake or actual fd for anonymous file
     245static int mmapFd = -1;                                                                 // fake or actual fd for anonymous file
    254246#ifdef __CFA_DEBUG__
    255247static bool heapBoot = 0;                                                               // detect recursion during boot
    256248#endif // __CFA_DEBUG__
    257 
    258 // The constructor for heapManager is called explicitly in memory_startup.
    259249static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
    260250
     
    262252#ifdef __STATISTICS__
    263253// Heap statistics counters.
     254static unsigned long long int mmap_storage;
     255static unsigned int mmap_calls;
     256static unsigned long long int munmap_storage;
     257static unsigned int munmap_calls;
     258static unsigned long long int sbrk_storage;
     259static unsigned int sbrk_calls;
     260static unsigned long long int malloc_storage;
    264261static unsigned int malloc_calls;
    265 static unsigned long long int malloc_storage;
    266 static unsigned int aalloc_calls;
    267 static unsigned long long int aalloc_storage;
     262static unsigned long long int free_storage;
     263static unsigned int free_calls;
     264static unsigned long long int calloc_storage;
    268265static unsigned int calloc_calls;
    269 static unsigned long long int calloc_storage;
     266static unsigned long long int memalign_storage;
    270267static unsigned int memalign_calls;
    271 static unsigned long long int memalign_storage;
    272 static unsigned int amemalign_calls;
    273 static unsigned long long int amemalign_storage;
     268static unsigned long long int cmemalign_storage;
    274269static unsigned int cmemalign_calls;
    275 static unsigned long long int cmemalign_storage;
    276 static unsigned int resize_calls;
    277 static unsigned long long int resize_storage;
     270static unsigned long long int realloc_storage;
    278271static unsigned int realloc_calls;
    279 static unsigned long long int realloc_storage;
    280 static unsigned int free_calls;
    281 static unsigned long long int free_storage;
    282 static unsigned int mmap_calls;
    283 static unsigned long long int mmap_storage;
    284 static unsigned int munmap_calls;
    285 static unsigned long long int munmap_storage;
    286 static unsigned int sbrk_calls;
    287 static unsigned long long int sbrk_storage;
    288272// Statistics file descriptor (changed by malloc_stats_fd).
    289 static int stat_fd = STDERR_FILENO;                                             // default stderr
     273static int statfd = STDERR_FILENO;                                              // default stderr
    290274
    291275// Use "write" because streams may be shutdown when calls are made.
    292276static void printStats() {
    293         char helpText[1024];
     277        char helpText[512];
    294278        __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
    295279                                                                        "\nHeap statistics:\n"
    296280                                                                        "  malloc: calls %u / storage %llu\n"
    297                                                                         "  aalloc: calls %u / storage %llu\n"
    298281                                                                        "  calloc: calls %u / storage %llu\n"
    299282                                                                        "  memalign: calls %u / storage %llu\n"
    300                                                                         "  amemalign: calls %u / storage %llu\n"
    301283                                                                        "  cmemalign: calls %u / storage %llu\n"
    302                                                                         "  resize: calls %u / storage %llu\n"
    303284                                                                        "  realloc: calls %u / storage %llu\n"
    304285                                                                        "  free: calls %u / storage %llu\n"
     
    307288                                                                        "  sbrk: calls %u / storage %llu\n",
    308289                                                                        malloc_calls, malloc_storage,
    309                                                                         aalloc_calls, aalloc_storage,
    310290                                                                        calloc_calls, calloc_storage,
    311291                                                                        memalign_calls, memalign_storage,
    312                                                                         amemalign_calls, amemalign_storage,
    313292                                                                        cmemalign_calls, cmemalign_storage,
    314                                                                         resize_calls, resize_storage,
    315293                                                                        realloc_calls, realloc_storage,
    316294                                                                        free_calls, free_storage,
     
    322300
    323301static int printStatsXML( FILE * stream ) {                             // see malloc_info
    324         char helpText[1024];
     302        char helpText[512];
    325303        int len = snprintf( helpText, sizeof(helpText),
    326304                                                "<malloc version=\"1\">\n"
     
    329307                                                "</sizes>\n"
    330308                                                "<total type=\"malloc\" count=\"%u\" size=\"%llu\"/>\n"
    331                                                 "<total type=\"aalloc\" count=\"%u\" size=\"%llu\"/>\n"
    332309                                                "<total type=\"calloc\" count=\"%u\" size=\"%llu\"/>\n"
    333310                                                "<total type=\"memalign\" count=\"%u\" size=\"%llu\"/>\n"
    334                                                 "<total type=\"amemalign\" count=\"%u\" size=\"%llu\"/>\n"
    335311                                                "<total type=\"cmemalign\" count=\"%u\" size=\"%llu\"/>\n"
    336                                                 "<total type=\"resize\" count=\"%u\" size=\"%llu\"/>\n"
    337312                                                "<total type=\"realloc\" count=\"%u\" size=\"%llu\"/>\n"
    338313                                                "<total type=\"free\" count=\"%u\" size=\"%llu\"/>\n"
     
    342317                                                "</malloc>",
    343318                                                malloc_calls, malloc_storage,
    344                                                 aalloc_calls, aalloc_storage,
    345319                                                calloc_calls, calloc_storage,
    346320                                                memalign_calls, memalign_storage,
    347                                                 amemalign_calls, amemalign_storage,
    348321                                                cmemalign_calls, cmemalign_storage,
    349                                                 resize_calls, resize_storage,
    350322                                                realloc_calls, realloc_storage,
    351323                                                free_calls, free_storage,
     
    358330} // printStatsXML
    359331#endif // __STATISTICS__
     332
     333
     334// static inline void noMemory() {
     335//      abort( "Heap memory exhausted at %zu bytes.\n"
     336//                 "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
     337//                 ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
     338// } // noMemory
     339
     340
     341static inline void checkAlign( size_t alignment ) {
     342        if ( alignment < libAlign() || ! libPow2( alignment ) ) {
     343                abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );
     344        } // if
     345} // checkAlign
     346
     347
     348static inline bool setHeapExpand( size_t value ) {
     349  if ( heapExpand < pageSize ) return true;
     350        heapExpand = value;
     351        return false;
     352} // setHeapExpand
    360353
    361354
     
    376369
    377370static inline bool setMmapStart( size_t value ) {               // true => mmapped, false => sbrk
    378   if ( value < __page_size || bucketSizes[NoBucketSizes - 1] < value ) return false;
     371  if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
    379372        mmapStart = value;                                                                      // set global
    380373
     
    383376        assert( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    384377        assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
    385         return true;
     378        return false;
    386379} // setMmapStart
    387380
    388381
    389 // <-------+----------------------------------------------------> bsize (bucket size)
    390 // |header |addr
    391 //==================================================================================
    392 //                   align/offset |
    393 // <-----------------<------------+-----------------------------> bsize (bucket size)
    394 //                   |fake-header | addr
    395 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
    396 #define realHeader( header ) ((HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset))
    397 
    398 // <-------<<--------------------- dsize ---------------------->> bsize (bucket size)
    399 // |header |addr
    400 //==================================================================================
    401 //                   align/offset |
    402 // <------------------------------<<---------- dsize --------->>> bsize (bucket size)
    403 //                   |fake-header |addr
    404 #define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header ))
    405 
    406 
    407 static inline void checkAlign( size_t alignment ) {
    408         if ( alignment < libAlign() || ! is_pow2( alignment ) ) {
    409                 abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );
    410         } // if
    411 } // checkAlign
    412 
    413 
    414 static inline void checkHeader( bool check, const char name[], void * addr ) {
     382static inline void checkHeader( bool check, const char * name, void * addr ) {
    415383        if ( unlikely( check ) ) {                                                      // bad address ?
    416384                abort( "Attempt to %s storage %p with address outside the heap.\n"
     
    423391static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & alignment ) {
    424392        if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?
     393                size_t offset = header->kind.fake.offset;
    425394                alignment = header->kind.fake.alignment & -2;   // remove flag from value
    426395                #ifdef __CFA_DEBUG__
    427396                checkAlign( alignment );                                                // check alignment
    428397                #endif // __CFA_DEBUG__
    429                 header = realHeader( header );                                  // backup from fake to real header
    430         } else {
    431                 alignment = libAlign();                                                 // => no fake header
     398                header = (HeapManager.Storage.Header *)((char *)header - offset);
    432399        } // if
    433400} // fakeHeader
    434401
    435402
    436 static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem,
    437                                                         size_t & size, size_t & alignment ) with( heapManager ) {
     403// <-------+----------------------------------------------------> bsize (bucket size)
     404// |header |addr
     405//==================================================================================
     406//                                | alignment
     407// <-----------------<------------+-----------------------------> bsize (bucket size)
     408//                   |fake-header | addr
     409#define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
     410
     411// <-------<<--------------------- dsize ---------------------->> bsize (bucket size)
     412// |header |addr
     413//==================================================================================
     414//                                | alignment
     415// <------------------------------<<---------- dsize --------->>> bsize (bucket size)
     416//                   |fake-header |addr
     417#define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header ))
     418
     419
     420static inline bool headers( const char * name __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) {
    438421        header = headerAddr( addr );
    439422
    440   if ( unlikely( addr < heapBegin || heapEnd < addr ) ) { // mmapped ?
     423        if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
    441424                fakeHeader( header, alignment );
    442425                size = header->kind.real.blockSize & -3;                // mmap size
     
    445428
    446429        #ifdef __CFA_DEBUG__
    447         checkHeader( header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
     430        checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
    448431        #endif // __CFA_DEBUG__
    449432
     
    466449} // headers
    467450
    468 #ifdef __CFA_DEBUG__
    469 #if __SIZEOF_POINTER__ == 4
    470 #define MASK 0xdeadbeef
    471 #else
    472 #define MASK 0xdeadbeefdeadbeef
    473 #endif
    474 #define STRIDE size_t
    475 
    476 static void * Memset( void * addr, STRIDE size ) {              // debug only
    477         if ( size % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, size %zd not multiple of %zd.", size, sizeof(STRIDE) );
    478         if ( (STRIDE)addr % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, addr %p not multiple of %zd.", addr, sizeof(STRIDE) );
    479 
    480         STRIDE * end = (STRIDE *)addr + size / sizeof(STRIDE);
    481         for ( STRIDE * p = (STRIDE *)addr; p < end; p += 1 ) *p = MASK;
    482         return addr;
    483 } // Memset
    484 #endif // __CFA_DEBUG__
    485 
    486 
    487 #define NO_MEMORY_MSG "insufficient heap memory available for allocating %zd new bytes."
    488 
    489 static inline void * extend( size_t size ) with( heapManager ) {
     451
     452static inline void * extend( size_t size ) with ( heapManager ) {
    490453        lock( extlock __cfaabi_dbg_ctx2 );
    491454        ptrdiff_t rem = heapRemaining - size;
     
    493456                // If the size requested is bigger than the current remaining storage, increase the size of the heap.
    494457
    495                 size_t increase = ceiling2( size > heapExpand ? size : heapExpand, __page_size );
    496                 // Do not call abort or strerror( errno ) as they may call malloc.
    497                 if ( sbrk( increase ) == (void *)-1 ) {                 // failed, no memory ?
     458                size_t increase = libCeiling( size > heapExpand ? size : heapExpand, libAlign() );
     459                if ( sbrk( increase ) == (void *)-1 ) {
    498460                        unlock( extlock );
    499                         __cfaabi_bits_print_nolock( STDERR_FILENO, NO_MEMORY_MSG, size );
    500                         _exit( EXIT_FAILURE );
    501                 } // if
    502                 if ( mprotect( (char *)heapEnd + heapRemaining, increase, __map_prot ) ) {
    503                         unlock( extlock );
    504                         __cfaabi_bits_print_nolock( STDERR_FILENO, "extend() : internal error, mprotect failure, heapEnd:%p size:%zd, errno:%d.\n", heapEnd, increase, errno );
    505                         _exit( EXIT_FAILURE );
     461                        errno = ENOMEM;
     462                        return 0p;
    506463                } // if
    507464                #ifdef __STATISTICS__
     
    511468                #ifdef __CFA_DEBUG__
    512469                // Set new memory to garbage so subsequent uninitialized usages might fail.
    513                 memset( (char *)heapEnd + heapRemaining, '\xde', increase );
    514                 //Memset( (char *)heapEnd + heapRemaining, increase );
     470                memset( (char *)heapEnd + heapRemaining, '\377', increase );
    515471                #endif // __CFA_DEBUG__
    516472                rem = heapRemaining + increase - size;
     
    525481
    526482
    527 static inline void * doMalloc( size_t size ) with( heapManager ) {
     483static inline void * doMalloc( size_t size ) with ( heapManager ) {
    528484        HeapManager.Storage * block;                                            // pointer to new block of storage
    529485
     
    531487        // along with the block and is a multiple of the alignment size.
    532488
    533   if ( unlikely( size > ULONG_MAX - sizeof(HeapManager.Storage) ) ) return 0p;
     489  if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0p;
    534490        size_t tsize = size + sizeof(HeapManager.Storage);
    535491        if ( likely( tsize < mmapStart ) ) {                            // small size => sbrk
     
    541497                        posn = Bsearchl( (unsigned int)tsize, bucketSizes, (size_t)maxBucketsUsed );
    542498                HeapManager.FreeHeader * freeElem = &freeLists[posn];
    543                 verify( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ?
    544                 verify( tsize <= freeElem->blockSize );                 // search failure ?
     499                // #ifdef FASTLOOKUP
     500                // if ( tsize < LookupSizes )
     501                //      freeElem = &freeLists[lookup[tsize]];
     502                // else
     503                // #endif // FASTLOOKUP
     504                //      freeElem = bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search
     505                // HeapManager.FreeHeader * freeElem =
     506                //      #ifdef FASTLOOKUP
     507                //      tsize < LookupSizes ? &freeLists[lookup[tsize]] :
     508                //      #endif // FASTLOOKUP
     509                //      bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search
     510                assert( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ?
     511                assert( tsize <= freeElem->blockSize );                 // search failure ?
    545512                tsize = freeElem->blockSize;                                    // total space needed for request
    546513
    547514                // Spin until the lock is acquired for this particular size of block.
    548515
    549                 #if BUCKETLOCK == SPINLOCK
     516                #if defined( SPINLOCK )
    550517                lock( freeElem->lock __cfaabi_dbg_ctx2 );
    551518                block = freeElem->freeList;                                             // remove node from stack
    552519                #else
    553                 block = pop( freeElem->freeList );
    554                 #endif // BUCKETLOCK
     520                block = freeElem->freeList.pop();
     521                #endif // SPINLOCK
    555522                if ( unlikely( block == 0p ) ) {                                // no free block ?
    556                         #if BUCKETLOCK == SPINLOCK
     523                        #if defined( SPINLOCK )
    557524                        unlock( freeElem->lock );
    558                         #endif // BUCKETLOCK
     525                        #endif // SPINLOCK
    559526
    560527                        // Freelist for that size was empty, so carve it out of the heap if there's enough left, or get some more
     
    562529
    563530                        block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call
    564                 #if BUCKETLOCK == SPINLOCK
     531  if ( unlikely( block == 0p ) ) return 0p;
     532                #if defined( SPINLOCK )
    565533                } else {
    566534                        freeElem->freeList = block->header.kind.real.next;
    567535                        unlock( freeElem->lock );
    568                 #endif // BUCKETLOCK
     536                #endif // SPINLOCK
    569537                } // if
    570538
    571539                block->header.kind.real.home = freeElem;                // pointer back to free list of apropriate size
    572540        } else {                                                                                        // large size => mmap
    573   if ( unlikely( size > ULONG_MAX - __page_size ) ) return 0p;
    574                 tsize = ceiling2( tsize, __page_size );                 // must be multiple of page size
     541  if ( unlikely( size > ~0ul - pageSize ) ) return 0p;
     542                tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
    575543                #ifdef __STATISTICS__
    576544                __atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST );
    577545                __atomic_add_fetch( &mmap_storage, tsize, __ATOMIC_SEQ_CST );
    578546                #endif // __STATISTICS__
    579 
    580                 block = (HeapManager.Storage *)mmap( 0, tsize, __map_prot, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
    581                 if ( block == (HeapManager.Storage *)MAP_FAILED ) { // failed ?
    582                         if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory
     547                block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
     548                if ( block == (HeapManager.Storage *)MAP_FAILED ) {
    583549                        // Do not call strerror( errno ) as it may call malloc.
    584                         abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu errno:%d.", &heapManager, tsize, errno );
    585                 } //if
     550                        abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu error:%d.", &heapManager, tsize, errno );
     551                } // if
    586552                #ifdef __CFA_DEBUG__
    587553                // Set new memory to garbage so subsequent uninitialized usages might fail.
    588                 memset( block, '\xde', tsize );
    589                 //Memset( block, tsize );
     554                memset( block, '\377', tsize );
    590555                #endif // __CFA_DEBUG__
    591556                block->header.kind.real.blockSize = tsize;              // storage size for munmap
    592557        } // if
    593558
    594         block->header.kind.real.size = size;                            // store allocation size
    595559        void * addr = &(block->data);                                           // adjust off header to user bytes
    596         verify( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
    597560
    598561        #ifdef __CFA_DEBUG__
    599         __atomic_add_fetch( &allocUnfreed, tsize, __ATOMIC_SEQ_CST );
     562        assert( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
     563        __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST );
    600564        if ( traceHeap() ) {
    601565                enum { BufferSize = 64 };
    602566                char helpText[BufferSize];
    603567                int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize );
     568                // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", addr, size );
    604569                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    605570        } // if
     
    610575
    611576
    612 static inline void doFree( void * addr ) with( heapManager ) {
     577static inline void doFree( void * addr ) with ( heapManager ) {
    613578        #ifdef __CFA_DEBUG__
    614579        if ( unlikely( heapManager.heapBegin == 0p ) ) {
     
    627592                #endif // __STATISTICS__
    628593                if ( munmap( header, size ) == -1 ) {
     594                        #ifdef __CFA_DEBUG__
    629595                        abort( "Attempt to deallocate storage %p not allocated or with corrupt header.\n"
    630596                                   "Possible cause is invalid pointer.",
    631597                                   addr );
     598                        #endif // __CFA_DEBUG__
    632599                } // if
    633600        } else {
    634601                #ifdef __CFA_DEBUG__
    635602                // Set free memory to garbage so subsequent usages might fail.
    636                 memset( ((HeapManager.Storage *)header)->data, '\xde', freeElem->blockSize - sizeof( HeapManager.Storage ) );
    637                 //Memset( ((HeapManager.Storage *)header)->data, freeElem->blockSize - sizeof( HeapManager.Storage ) );
     603                memset( ((HeapManager.Storage *)header)->data, '\377', freeElem->blockSize - sizeof( HeapManager.Storage ) );
    638604                #endif // __CFA_DEBUG__
    639605
     
    641607                free_storage += size;
    642608                #endif // __STATISTICS__
    643                 #if BUCKETLOCK == SPINLOCK
     609                #if defined( SPINLOCK )
    644610                lock( freeElem->lock __cfaabi_dbg_ctx2 );               // acquire spin lock
    645611                header->kind.real.next = freeElem->freeList;    // push on stack
     
    647613                unlock( freeElem->lock );                                               // release spin lock
    648614                #else
    649                 push( freeElem->freeList, *(HeapManager.Storage *)header );
    650                 #endif // BUCKETLOCK
     615                freeElem->freeList.push( *(HeapManager.Storage *)header );
     616                #endif // SPINLOCK
    651617        } // if
    652618
    653619        #ifdef __CFA_DEBUG__
    654         __atomic_add_fetch( &allocUnfreed, -size, __ATOMIC_SEQ_CST );
     620        __atomic_add_fetch( &allocFree, -size, __ATOMIC_SEQ_CST );
    655621        if ( traceHeap() ) {
    656                 char helpText[64];
     622                enum { BufferSize = 64 };
     623                char helpText[BufferSize];
    657624                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    658625                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     
    662629
    663630
    664 size_t prtFree( HeapManager & manager ) with( manager ) {
     631size_t prtFree( HeapManager & manager ) with ( manager ) {
    665632        size_t total = 0;
    666633        #ifdef __STATISTICS__
     
    674641                #endif // __STATISTICS__
    675642
    676                 #if BUCKETLOCK == SPINLOCK
     643                #if defined( SPINLOCK )
    677644                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    678645                #else
    679                         for(;;) {
    680 //              for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
    681 //              for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
    682 //                      HeapManager.Storage * temp = p->header.kind.real.next.top; // FIX ME: direct assignent fails, initialization works`
    683 //                      typeof(p) temp = (( p )`next)->top;                     // FIX ME: direct assignent fails, initialization works`
    684 //                      p = temp;
    685                 #endif // BUCKETLOCK
     646                for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) {
     647                #endif // SPINLOCK
    686648                        total += size;
    687649                        #ifdef __STATISTICS__
     
    703665
    704666
    705 static void ?{}( HeapManager & manager ) with( manager ) {
    706         __page_size = sysconf( _SC_PAGESIZE );
    707         __map_prot = PROT_READ | PROT_WRITE | PROT_EXEC;
     667static void ?{}( HeapManager & manager ) with ( manager ) {
     668        pageSize = sysconf( _SC_PAGESIZE );
    708669
    709670        for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
     
    719680        #endif // FASTLOOKUP
    720681
    721         if ( ! setMmapStart( default_mmap_start() ) ) {
     682        if ( setMmapStart( default_mmap_start() ) ) {
    722683                abort( "HeapManager : internal error, mmap start initialization failure." );
    723684        } // if
     
    725686
    726687        char * end = (char *)sbrk( 0 );
    727         heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, __page_size ) - end ); // move start of heap to multiple of alignment
     688        sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
     689        heapBegin = heapEnd = sbrk( 0 );                                        // get new start point
    728690} // HeapManager
    729691
     
    733695        if ( traceHeapTerm() ) {
    734696                printStats();
    735                 // prtUnfreed() called in heapAppStop()
     697                // if ( prtfree() ) prtFree( heapManager, true );
    736698        } // if
    737699        #endif // __STATISTICS__
     
    742704void memory_startup( void ) {
    743705        #ifdef __CFA_DEBUG__
    744         if ( heapBoot ) {                                                                       // check for recursion during system boot
     706        if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
     707                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    745708                abort( "boot() : internal error, recursively invoked during system boot." );
    746709        } // if
     
    748711        #endif // __CFA_DEBUG__
    749712
    750         //verify( heapManager.heapBegin != 0 );
     713        //assert( heapManager.heapBegin != 0 );
    751714        //heapManager{};
    752         if ( heapManager.heapBegin == 0p ) heapManager{};       // sanity check
     715        if ( heapManager.heapBegin == 0p ) heapManager{};
    753716} // memory_startup
    754717
     
    760723
    761724static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    762         verify( heapManager.heapBegin != 0p );                          // called before memory_startup ?
    763   if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    764 
    765 #if __SIZEOF_POINTER__ == 8
    766         verify( size < ((typeof(size_t))1 << 48) );
    767 #endif // __SIZEOF_POINTER__ == 8
    768         return doMalloc( size );
     725        //assert( heapManager.heapBegin != 0 );
     726        if ( unlikely( heapManager.heapBegin == 0p ) ) heapManager{}; // called before memory_startup ?
     727        void * addr = doMalloc( size );
     728        if ( unlikely( addr == 0p ) ) errno = ENOMEM;           // POSIX
     729        return addr;
    769730} // mallocNoStats
    770731
    771732
    772 static inline void * callocNoStats( size_t dim, size_t elemSize ) {
    773         size_t size = dim * elemSize;
    774   if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
     733static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) {
     734        size_t size = noOfElems * elemSize;
    775735        char * addr = (char *)mallocNoStats( size );
     736  if ( unlikely( addr == 0p ) ) return 0p;
    776737
    777738        HeapManager.Storage.Header * header;
    778739        HeapManager.FreeHeader * freeElem;
    779740        size_t bsize, alignment;
     741        bool mapped __attribute__(( unused )) = headers( "calloc", addr, header, freeElem, bsize, alignment );
    780742        #ifndef __CFA_DEBUG__
    781         bool mapped =
    782         #endif // __CFA_DEBUG__
    783                 headers( "calloc", addr, header, freeElem, bsize, alignment );
    784         #ifndef __CFA_DEBUG__
    785 
    786743        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    787744        if ( ! mapped )
    788745        #endif // __CFA_DEBUG__
    789                 // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined
     746                // Zero entire data space even when > than size => realloc without a new allocation and zero fill works.
     747                // <-------00000000000000000000000000000000000000000000000000000> bsize (bucket size)
    790748                // `-header`-addr                      `-size
    791                 memset( addr, '\0', size );                                             // set to zeros
     749                memset( addr, '\0', bsize - sizeof(HeapManager.Storage) ); // set to zeros
    792750
    793751        header->kind.real.blockSize |= 2;                                       // mark as zero filled
     
    796754
    797755
    798 static inline void * memalignNoStats( size_t alignment, size_t size ) {
    799   if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    800 
     756static inline void * memalignNoStats( size_t alignment, size_t size ) { // necessary for malloc statistics
    801757        #ifdef __CFA_DEBUG__
    802758        checkAlign( alignment );                                                        // check alignment
     
    816772        // add sizeof(Storage) for fake header
    817773        char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
     774  if ( unlikely( addr == 0p ) ) return addr;
    818775
    819776        // address in the block of the "next" alignment address
    820         char * user = (char *)ceiling2( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
     777        char * user = (char *)libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
    821778
    822779        // address of header from malloc
    823780        HeapManager.Storage.Header * realHeader = headerAddr( addr );
    824         realHeader->kind.real.size = size;                                      // correct size to eliminate above alignment offset
    825781        // address of fake header * before* the alignment location
    826782        HeapManager.Storage.Header * fakeHeader = headerAddr( user );
     
    834790
    835791
    836 static inline void * cmemalignNoStats( size_t alignment, size_t dim, size_t elemSize ) {
    837         size_t size = dim * elemSize;
    838   if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
     792static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) {
     793        size_t size = noOfElems * elemSize;
    839794        char * addr = (char *)memalignNoStats( alignment, size );
    840 
     795  if ( unlikely( addr == 0p ) ) return 0p;
    841796        HeapManager.Storage.Header * header;
    842797        HeapManager.FreeHeader * freeElem;
    843798        size_t bsize;
     799        bool mapped __attribute__(( unused )) = headers( "cmemalign", addr, header, freeElem, bsize, alignment );
    844800        #ifndef __CFA_DEBUG__
    845         bool mapped =
    846         #endif // __CFA_DEBUG__
    847                 headers( "cmemalign", addr, header, freeElem, bsize, alignment );
    848 
    849801        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    850         #ifndef __CFA_DEBUG__
    851802        if ( ! mapped )
    852803        #endif // __CFA_DEBUG__
    853                 // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined
    854                 // `-header`-addr                      `-size
    855                 memset( addr, '\0', size );                                             // set to zeros
    856 
    857         header->kind.real.blockSize |= 2;                                       // mark as zero filled
     804                memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros
     805        header->kind.real.blockSize |= 2;                               // mark as zero filled
     806
    858807        return addr;
    859808} // cmemalignNoStats
    860809
    861810
     811// supported mallopt options
     812#ifndef M_MMAP_THRESHOLD
     813#define M_MMAP_THRESHOLD (-1)
     814#endif // M_TOP_PAD
     815#ifndef M_TOP_PAD
     816#define M_TOP_PAD (-2)
     817#endif // M_TOP_PAD
     818
     819
    862820extern "C" {
    863         // Allocates size bytes and returns a pointer to the allocated memory.  The contents are undefined. If size is 0,
    864         // then malloc() returns a unique pointer value that can later be successfully passed to free().
     821        // The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not
     822        // initialized. If size is 0, then malloc() returns either 0p, or a unique pointer value that can later be
     823        // successfully passed to free().
    865824        void * malloc( size_t size ) {
    866825                #ifdef __STATISTICS__
     
    872831        } // malloc
    873832
    874 
    875         // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes.
    876         void * aalloc( size_t dim, size_t elemSize ) {
    877                 size_t size = dim * elemSize;
    878                 #ifdef __STATISTICS__
    879                 __atomic_add_fetch( &aalloc_calls, 1, __ATOMIC_SEQ_CST );
    880                 __atomic_add_fetch( &aalloc_storage, size, __ATOMIC_SEQ_CST );
    881                 #endif // __STATISTICS__
    882 
    883                 return mallocNoStats( size );
    884         } // aalloc
    885 
    886 
    887         // Same as aalloc() with memory set to zero.
    888         void * calloc( size_t dim, size_t elemSize ) {
     833        // The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to
     834        // the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either 0p, or a
     835        // unique pointer value that can later be successfully passed to free().
     836        void * calloc( size_t noOfElems, size_t elemSize ) {
    889837                #ifdef __STATISTICS__
    890838                __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );
    891                 __atomic_add_fetch( &calloc_storage, dim * elemSize, __ATOMIC_SEQ_CST );
    892                 #endif // __STATISTICS__
    893 
    894                 return callocNoStats( dim, elemSize );
     839                __atomic_add_fetch( &calloc_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
     840                #endif // __STATISTICS__
     841
     842                return callocNoStats( noOfElems, elemSize );
    895843        } // calloc
    896844
    897 
    898         // Change the size of the memory block pointed to by oaddr to size bytes. The contents are undefined.  If oaddr is
    899         // 0p, then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and oaddr is
    900         // not 0p, then the call is equivalent to free(oaddr). Unless oaddr is 0p, it must have been returned by an earlier
    901         // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done.
    902         void * resize( void * oaddr, size_t size ) {
    903                 #ifdef __STATISTICS__
    904                 __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
     845        // The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be
     846        // unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size
     847        // is larger than the old size, the added memory will not be initialized.  If ptr is 0p, then the call is
     848        // equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not 0p, then the call
     849        // is equivalent to free(ptr). Unless ptr is 0p, it must have been returned by an earlier call to malloc(),
     850        // calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.
     851        void * realloc( void * oaddr, size_t size ) {
     852                #ifdef __STATISTICS__
     853                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    905854                #endif // __STATISTICS__
    906855
    907856                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    908           if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    909           if ( unlikely( oaddr == 0p ) ) {
    910                         #ifdef __STATISTICS__
    911                         __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    912                         #endif // __STATISTICS__
    913                         return mallocNoStats( size );
    914                 } // if
     857          if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
     858          if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    915859
    916860                HeapManager.Storage.Header * header;
    917861                HeapManager.FreeHeader * freeElem;
    918                 size_t bsize, oalign;
    919                 headers( "resize", oaddr, header, freeElem, bsize, oalign );
     862                size_t bsize, oalign = 0;
     863                headers( "realloc", oaddr, header, freeElem, bsize, oalign );
     864
    920865                size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    921 
    922                 // same size, DO NOT preserve STICKY PROPERTIES.
    923                 if ( oalign == libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
    924                         header->kind.real.blockSize &= -2;                      // no alignment and turn off 0 fill
    925                         header->kind.real.size = size;                          // reset allocation size
     866          if ( size <= odsize && odsize <= size * 2 ) { // allow up to 50% wasted storage in smaller size
     867                        // Do not know size of original allocation => cannot do 0 fill for any additional space because do not know
     868                        // where to start filling, i.e., do not overwrite existing values in space.
     869                        //
     870                        // This case does not result in a new profiler entry because the previous one still exists and it must match with
     871                        // the free for this memory.  Hence, this realloc does not appear in the profiler output.
    926872                        return oaddr;
    927873                } // if
    928874
    929875                #ifdef __STATISTICS__
    930                 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    931                 #endif // __STATISTICS__
    932 
    933                 // change size, DO NOT preserve STICKY PROPERTIES.
    934                 free( oaddr );
    935                 return mallocNoStats( size );                                   // create new area
    936         } // resize
    937 
    938 
    939         // Same as resize() but the contents are unchanged in the range from the start of the region up to the minimum of
    940         // the old and new sizes.
    941         void * realloc( void * oaddr, size_t size ) {
    942                 #ifdef __STATISTICS__
    943                 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    944                 #endif // __STATISTICS__
    945 
    946                 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    947           if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    948           if ( unlikely( oaddr == 0p ) ) {
    949                         #ifdef __STATISTICS__
    950                         __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    951                         #endif // __STATISTICS__
    952                         return mallocNoStats( size );
    953                 } // if
    954 
    955                 HeapManager.Storage.Header * header;
    956                 HeapManager.FreeHeader * freeElem;
    957                 size_t bsize, oalign;
    958                 headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    959 
    960                 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    961                 size_t osize = header->kind.real.size;                  // old allocation size
    962                 bool ozfill = (header->kind.real.blockSize & 2); // old allocation zero filled
    963           if ( unlikely( size <= odsize ) && odsize <= size * 2 ) { // allow up to 50% wasted storage
    964                         header->kind.real.size = size;                          // reset allocation size
    965                         if ( unlikely( ozfill ) && size > osize ) {     // previous request zero fill and larger ?
    966                                 memset( (char *)oaddr + osize, '\0', size - osize ); // initialize added storage
    967                         } // if
    968                         return oaddr;
    969                 } // if
    970 
    971                 #ifdef __STATISTICS__
    972                 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     876                __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    973877                #endif // __STATISTICS__
    974878
     
    976880
    977881                void * naddr;
    978                 if ( likely( oalign == libAlign() ) ) {                 // previous request not aligned ?
    979                         naddr = mallocNoStats( size );                          // create new area
     882                if ( unlikely( oalign != 0 ) ) {                                // previous request memalign?
     883                        if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
     884                                naddr = cmemalignNoStats( oalign, 1, size ); // create new aligned area
     885                        } else {
     886                                naddr = memalignNoStats( oalign, size ); // create new aligned area
     887                        } // if
    980888                } else {
    981                         naddr = memalignNoStats( oalign, size );        // create new aligned area
    982                 } // if
    983 
    984                 headers( "realloc", naddr, header, freeElem, bsize, oalign );
    985                 memcpy( naddr, oaddr, min( osize, size ) );             // copy bytes
    986                 free( oaddr );
    987 
    988                 if ( unlikely( ozfill ) ) {                                             // previous request zero fill ?
    989                         header->kind.real.blockSize |= 2;                       // mark new request as zero filled
    990                         if ( size > osize ) {                                           // previous request larger ?
    991                                 memset( (char *)naddr + osize, '\0', size - osize ); // initialize added storage
     889                        if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
     890                                naddr = callocNoStats( 1, size );               // create new area
     891                        } else {
     892                                naddr = mallocNoStats( size );                  // create new area
    992893                        } // if
    993894                } // if
     895          if ( unlikely( naddr == 0p ) ) return 0p;
     896
     897                headers( "realloc", naddr, header, freeElem, bsize, oalign );
     898                size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
     899                // To preserve prior fill, the entire bucket must be copied versus the size.
     900                memcpy( naddr, oaddr, MIN( odsize, ndsize ) );  // copy bytes
     901                free( oaddr );
    994902                return naddr;
    995903        } // realloc
    996904
    997 
    998         // Same as malloc() except the memory address is a multiple of alignment, which must be a power of two. (obsolete)
     905        // The obsolete function memalign() allocates size bytes and returns a pointer to the allocated memory. The memory
     906        // address will be a multiple of alignment, which must be a power of two.
    999907        void * memalign( size_t alignment, size_t size ) {
    1000908                #ifdef __STATISTICS__
     
    1007915
    1008916
    1009         // Same as aalloc() with memory alignment.
    1010         void * amemalign( size_t alignment, size_t dim, size_t elemSize ) {
    1011                 size_t size = dim * elemSize;
     917        // The cmemalign() function is the same as calloc() with memory alignment.
     918        void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
    1012919                #ifdef __STATISTICS__
    1013920                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    1014                 __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST );
    1015                 #endif // __STATISTICS__
    1016 
    1017                 return memalignNoStats( alignment, size );
    1018         } // amemalign
    1019 
    1020 
    1021         // Same as calloc() with memory alignment.
    1022         void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) {
    1023                 #ifdef __STATISTICS__
    1024                 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    1025                 __atomic_add_fetch( &cmemalign_storage, dim * elemSize, __ATOMIC_SEQ_CST );
    1026                 #endif // __STATISTICS__
    1027 
    1028                 return cmemalignNoStats( alignment, dim, elemSize );
     921                __atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
     922                #endif // __STATISTICS__
     923
     924                return cmemalignNoStats( alignment, noOfElems, elemSize );
    1029925        } // cmemalign
    1030926
    1031 
    1032         // Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple
    1033     // of alignment. This requirement is universally ignored.
     927        // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a
     928        // multiple of alignment.
    1034929        void * aligned_alloc( size_t alignment, size_t size ) {
    1035930                return memalign( alignment, size );
     
    1037932
    1038933
    1039         // Allocates size bytes and places the address of the allocated memory in *memptr. The address of the allocated
    1040         // memory shall be a multiple of alignment, which must be a power of two and a multiple of sizeof(void *). If size
    1041         // is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later be successfully passed to
    1042         // free(3).
     934        // The function posix_memalign() allocates size bytes and places the address of the allocated memory in *memptr. The
     935        // address of the allocated memory will be a multiple of alignment, which must be a power of two and a multiple of
     936        // sizeof(void *). If size is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later
     937        // be successfully passed to free(3).
    1043938        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    1044           if ( alignment < libAlign() || ! is_pow2( alignment ) ) return EINVAL; // check alignment
     939          if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
    1045940                * memptr = memalign( alignment, size );
     941          if ( unlikely( * memptr == 0p ) ) return ENOMEM;
    1046942                return 0;
    1047943        } // posix_memalign
    1048944
    1049 
    1050         // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the
    1051         // page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
     945        // The obsolete function valloc() allocates size bytes and returns a pointer to the allocated memory. The memory
     946        // address will be a multiple of the page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
    1052947        void * valloc( size_t size ) {
    1053                 return memalign( __page_size, size );
     948                return memalign( pageSize, size );
    1054949        } // valloc
    1055950
    1056951
    1057         // Same as valloc but rounds size to multiple of page size.
    1058         void * pvalloc( size_t size ) {
    1059                 return memalign( __page_size, ceiling2( size, __page_size ) );
    1060         } // pvalloc
    1061 
    1062 
    1063         // Frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc()
    1064         // or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behaviour occurs. If ptr is
    1065         // 0p, no operation is performed.
     952        // The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to
     953        // malloc(), calloc() or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behavior
     954        // occurs. If ptr is 0p, no operation is performed.
    1066955        void free( void * addr ) {
    1067956                #ifdef __STATISTICS__
     
    1084973
    1085974
    1086         // Returns the alignment of an allocation.
     975        // The malloc_alignment() function returns the alignment of the allocation.
    1087976        size_t malloc_alignment( void * addr ) {
    1088977          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
     
    1091980                        return header->kind.fake.alignment & -2;        // remove flag from value
    1092981                } else {
    1093                         return libAlign();                                                      // minimum alignment
     982                        return libAlign ();                                                     // minimum alignment
    1094983                } // if
    1095984        } // malloc_alignment
    1096985
    1097986
    1098         // Set the alignment for an the allocation and return previous alignment or 0 if no alignment.
    1099         size_t $malloc_alignment_set( void * addr, size_t alignment ) {
    1100           if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
    1101                 size_t ret;
    1102                 HeapManager.Storage.Header * header = headerAddr( addr );
    1103                 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1104                         ret = header->kind.fake.alignment & -2;         // remove flag from old value
    1105                         header->kind.fake.alignment = alignment | 1; // add flag to new value
    1106                 } else {
    1107                         ret = 0;                                                                        // => no alignment to change
    1108                 } // if
    1109                 return ret;
    1110         } // $malloc_alignment_set
    1111 
    1112 
    1113         // Returns true if the allocation is zero filled, e.g., allocated by calloc().
     987        // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
    1114988        bool malloc_zero_fill( void * addr ) {
    1115989          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    1116990                HeapManager.Storage.Header * header = headerAddr( addr );
    1117991                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1118                         header = realHeader( header );                          // backup from fake to real header
     992                        header = (HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset);
    1119993                } // if
    1120                 return (header->kind.real.blockSize & 2) != 0;  // zero filled ?
     994                return (header->kind.real.blockSize & 2) != 0;  // zero filled (calloc/cmemalign) ?
    1121995        } // malloc_zero_fill
    1122996
    1123         // Set allocation is zero filled and return previous zero filled.
    1124         bool $malloc_zero_fill_set( void * addr ) {
    1125           if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    1126                 HeapManager.Storage.Header * header = headerAddr( addr );
    1127                 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1128                         header = realHeader( header );                          // backup from fake to real header
    1129                 } // if
    1130                 bool ret = (header->kind.real.blockSize & 2) != 0; // zero filled ?
    1131                 header->kind.real.blockSize |= 2;                               // mark as zero filled
    1132                 return ret;
    1133         } // $malloc_zero_fill_set
    1134 
    1135 
    1136         // Returns original total allocation size (not bucket size) => array size is dimension * sizeif(T).
    1137         size_t malloc_size( void * addr ) {
    1138           if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has zero size
    1139                 HeapManager.Storage.Header * header = headerAddr( addr );
    1140                 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1141                         header = realHeader( header );                          // backup from fake to real header
    1142                 } // if
    1143                 return header->kind.real.size;
    1144         } // malloc_size
    1145 
    1146         // Set allocation size and return previous size.
    1147         size_t $malloc_size_set( void * addr, size_t size ) {
    1148           if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
    1149                 HeapManager.Storage.Header * header = headerAddr( addr );
    1150                 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1151                         header = realHeader( header );                          // backup from fake to real header
    1152                 } // if
    1153                 size_t ret = header->kind.real.size;
    1154                 header->kind.real.size = size;
    1155                 return ret;
    1156         } // $malloc_size_set
    1157 
    1158 
    1159         // Returns the number of usable bytes in the block pointed to by ptr, a pointer to a block of memory allocated by
    1160         // malloc or a related function.
     997
     998        // The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to
     999        // a block of memory allocated by malloc(3) or a related function.
    11611000        size_t malloc_usable_size( void * addr ) {
    11621001          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
     
    11661005
    11671006                headers( "malloc_usable_size", addr, header, freeElem, bsize, alignment );
    1168                 return dataStorage( bsize, addr, header );              // data storage in bucket
     1007                return dataStorage( bsize, addr, header );      // data storage in bucket
    11691008        } // malloc_usable_size
    11701009
    11711010
    1172         // Prints (on default standard error) statistics about memory allocated by malloc and related functions.
     1011        // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and
     1012        // related functions.
    11731013        void malloc_stats( void ) {
    11741014                #ifdef __STATISTICS__
     
    11781018        } // malloc_stats
    11791019
    1180 
    1181         // Changes the file descripter where malloc_stats() writes statistics.
     1020        // The malloc_stats_fd() function changes the file descripter where malloc_stats() writes the statistics.
    11821021        int malloc_stats_fd( int fd __attribute__(( unused )) ) {
    11831022                #ifdef __STATISTICS__
    1184                 int temp = stat_fd;
    1185                 stat_fd = fd;
     1023                int temp = statfd;
     1024                statfd = fd;
    11861025                return temp;
    11871026                #else
     
    11911030
    11921031
    1193         // Adjusts parameters that control the behaviour of the memory-allocation functions (see malloc). The param argument
    1194         // specifies the parameter to be modified, and value specifies the new value for that parameter.
     1032        // The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see
     1033        // malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that
     1034        // parameter.
    11951035        int mallopt( int option, int value ) {
    11961036                choose( option ) {
    11971037                  case M_TOP_PAD:
    1198                         heapExpand = ceiling2( value, __page_size ); return 1;
     1038                        if ( setHeapExpand( value ) ) return 1;
    11991039                  case M_MMAP_THRESHOLD:
    12001040                        if ( setMmapStart( value ) ) return 1;
    1201                         break;
    12021041                } // switch
    12031042                return 0;                                                                               // error, unsupported
    12041043        } // mallopt
    12051044
    1206 
    1207         // Attempt to release free memory at the top of the heap (by calling sbrk with a suitable argument).
     1045        // The malloc_trim() function attempts to release free memory at the top of the heap (by calling sbrk(2) with a
     1046        // suitable argument).
    12081047        int malloc_trim( size_t ) {
    12091048                return 0;                                                                               // => impossible to release memory
     
    12111050
    12121051
    1213         // Exports an XML string that describes the current state of the memory-allocation implementation in the caller.
    1214         // The string is printed on the file stream stream.  The exported string includes information about all arenas (see
    1215         // malloc).
     1052        // The malloc_info() function exports an XML string that describes the current state of the memory-allocation
     1053        // implementation in the caller.  The string is printed on the file stream stream.  The exported string includes
     1054        // information about all arenas (see malloc(3)).
    12161055        int malloc_info( int options, FILE * stream ) {
    1217           if ( options != 0 ) { errno = EINVAL; return -1; }
    1218                 #ifdef __STATISTICS__
     1056                if ( options != 0 ) { errno = EINVAL; return -1; }
    12191057                return printStatsXML( stream );
    1220                 #else
    1221                 return 0;                                                                               // unsupported
    1222                 #endif // __STATISTICS__
    12231058        } // malloc_info
    12241059
    12251060
    1226         // Records the current state of all malloc internal bookkeeping variables (but not the actual contents of the heap
    1227         // or the state of malloc_hook functions pointers).  The state is recorded in a system-dependent opaque data
    1228         // structure dynamically allocated via malloc, and a pointer to that data structure is returned as the function
    1229         // result.  (The caller must free this memory.)
     1061        // The malloc_get_state() function records the current state of all malloc(3) internal bookkeeping variables (but
     1062        // not the actual contents of the heap or the state of malloc_hook(3) functions pointers).  The state is recorded in
     1063        // a system-dependent opaque data structure dynamically allocated via malloc(3), and a pointer to that data
     1064        // structure is returned as the function result.  (It is the caller's responsibility to free(3) this memory.)
    12301065        void * malloc_get_state( void ) {
    12311066                return 0p;                                                                              // unsupported
     
    12331068
    12341069
    1235         // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
    1236         // structure pointed to by state.
    1237         int malloc_set_state( void * ) {
     1070        // The malloc_set_state() function restores the state of all malloc(3) internal bookkeeping variables to the values
     1071        // recorded in the opaque data structure pointed to by state.
     1072        int malloc_set_state( void * ptr ) {
    12381073                return 0;                                                                               // unsupported
    12391074        } // malloc_set_state
     
    12421077
    12431078// Must have CFA linkage to overload with C linkage realloc.
    1244 void * resize( void * oaddr, size_t nalign, size_t size ) {
     1079void * realloc( void * oaddr, size_t nalign, size_t size ) {
    12451080        #ifdef __STATISTICS__
    1246         __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
     1081        __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    12471082        #endif // __STATISTICS__
    12481083
    1249         if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum
     1084        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
     1085  if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
     1086  if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
     1087
     1088        if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
    12501089        #ifdef __CFA_DEBUG__
    12511090        else
     
    12531092        #endif // __CFA_DEBUG__
    12541093
    1255         // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1256   if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    1257   if ( unlikely( oaddr == 0p ) ) {
    1258                 #ifdef __STATISTICS__
    1259                 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    1260                 #endif // __STATISTICS__
    1261                 return memalignNoStats( nalign, size );
    1262         } // if
    1263 
    1264         // Attempt to reuse existing alignment.
    1265         HeapManager.Storage.Header * header = headerAddr( oaddr );
    1266         bool isFakeHeader = header->kind.fake.alignment & 1; // old fake header ?
    1267         size_t oalign;
    1268         if ( isFakeHeader ) {
    1269                 oalign = header->kind.fake.alignment & -2;              // old alignment
    1270                 if ( (uintptr_t)oaddr % nalign == 0                             // lucky match ?
    1271                          && ( oalign <= nalign                                          // going down
    1272                                   || (oalign >= nalign && oalign <= 256) ) // little alignment storage wasted ?
    1273                         ) {
    1274                         headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1275                         HeapManager.FreeHeader * freeElem;
    1276                         size_t bsize, oalign;
    1277                         headers( "resize", oaddr, header, freeElem, bsize, oalign );
    1278                         size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    1279 
    1280                         if ( size <= odsize && odsize <= size * 2 ) { // allow 50% wasted data storage
    1281                                 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1282 
    1283                                 header->kind.real.blockSize &= -2;              // turn off 0 fill
    1284                                 header->kind.real.size = size;                  // reset allocation size
    1285                                 return oaddr;
    1286                         } // if
    1287                 } // if
    1288         } else if ( ! isFakeHeader                                                      // old real header (aligned on libAlign) ?
    1289                                 && nalign == libAlign() ) {                             // new alignment also on libAlign => no fake header needed
    1290                 return resize( oaddr, size );                                   // duplicate special case checks
     1094        HeapManager.Storage.Header * header;
     1095        HeapManager.FreeHeader * freeElem;
     1096        size_t bsize, oalign = 0;
     1097        headers( "realloc", oaddr, header, freeElem, bsize, oalign );
     1098        size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
     1099
     1100  if ( oalign != 0 && (uintptr_t)oaddr % nalign == 0 ) { // has alignment and just happens to work out
     1101                headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
     1102                return realloc( oaddr, size );
    12911103        } // if
    12921104
    12931105        #ifdef __STATISTICS__
    1294         __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    1295         #endif // __STATISTICS__
    1296 
    1297         // change size, DO NOT preserve STICKY PROPERTIES.
    1298         free( oaddr );
    1299         return memalignNoStats( nalign, size );                         // create new aligned area
    1300 } // resize
    1301 
    1302 
    1303 void * realloc( void * oaddr, size_t nalign, size_t size ) {
    1304         if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum
    1305         #ifdef __CFA_DEBUG__
    1306         else
    1307                 checkAlign( nalign );                                                   // check alignment
    1308         #endif // __CFA_DEBUG__
    1309 
    1310         // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1311   if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    1312   if ( unlikely( oaddr == 0p ) ) {
    1313                 #ifdef __STATISTICS__
    1314                 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    1315                 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    1316                 #endif // __STATISTICS__
    1317                 return memalignNoStats( nalign, size );
    1318         } // if
    1319 
    1320         // Attempt to reuse existing alignment.
    1321         HeapManager.Storage.Header * header = headerAddr( oaddr );
    1322         bool isFakeHeader = header->kind.fake.alignment & 1; // old fake header ?
    1323         size_t oalign;
    1324         if ( isFakeHeader ) {
    1325                 oalign = header->kind.fake.alignment & -2;              // old alignment
    1326                 if ( (uintptr_t)oaddr % nalign == 0                             // lucky match ?
    1327                          && ( oalign <= nalign                                          // going down
    1328                                   || (oalign >= nalign && oalign <= 256) ) // little alignment storage wasted ?
    1329                         ) {
    1330                         headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1331                         return realloc( oaddr, size );                          // duplicate alignment and special case checks
    1332                 } // if
    1333         } else if ( ! isFakeHeader                                                      // old real header (aligned on libAlign) ?
    1334                                 && nalign == libAlign() )                               // new alignment also on libAlign => no fake header needed
    1335                 return realloc( oaddr, size );                                  // duplicate alignment and special case checks
    1336 
    1337         #ifdef __STATISTICS__
    1338         __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    13391106        __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    13401107        #endif // __STATISTICS__
    13411108
    1342         HeapManager.FreeHeader * freeElem;
    1343         size_t bsize;
    1344         headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    1345 
    13461109        // change size and copy old content to new storage
    13471110
    1348         size_t osize = header->kind.real.size;                          // old allocation size
    1349         bool ozfill = (header->kind.real.blockSize & 2);        // old allocation zero filled
    1350 
    1351         void * naddr = memalignNoStats( nalign, size );         // create new aligned area
     1111        void * naddr;
     1112        if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
     1113                naddr = cmemalignNoStats( nalign, 1, size );    // create new aligned area
     1114        } else {
     1115                naddr = memalignNoStats( nalign, size );                // create new aligned area
     1116        } // if
    13521117
    13531118        headers( "realloc", naddr, header, freeElem, bsize, oalign );
    1354         memcpy( naddr, oaddr, min( osize, size ) );                     // copy bytes
     1119        size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
     1120        // To preserve prior fill, the entire bucket must be copied versus the size.
     1121        memcpy( naddr, oaddr, MIN( odsize, ndsize ) );          // copy bytes
    13551122        free( oaddr );
    1356 
    1357         if ( unlikely( ozfill ) ) {                                                     // previous request zero fill ?
    1358                 header->kind.real.blockSize |= 2;                               // mark new request as zero filled
    1359                 if ( size > osize ) {                                                   // previous request larger ?
    1360                         memset( (char *)naddr + osize, '\0', size - osize ); // initialize added storage
    1361                 } // if
    1362         } // if
    13631123        return naddr;
    13641124} // realloc
  • libcfa/src/interpose.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed Mar 29 16:10:31 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 13 17:35:37 2020
    13 // Update Count     : 178
     12// Last Modified On : Thu Jan 30 17:47:32 2020
     13// Update Count     : 156
    1414//
    1515
    1616#include <stdarg.h>                                                                             // va_start, va_end
    17 #include <stdio.h>
    1817#include <string.h>                                                                             // strlen
    1918#include <unistd.h>                                                                             // _exit, getpid
     
    3029#include "bits/signal.hfa"                                                              // sigHandler_?
    3130#include "startup.hfa"                                                                  // STARTUP_PRIORITY_CORE
    32 #include <assert.h>
    3331
    3432//=============================================================================================
     
    4240
    4341typedef void (* generic_fptr_t)(void);
    44 generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
     42generic_fptr_t interpose_symbol( const char * symbol, const char * version ) {
    4543        const char * error;
    4644
     
    144142void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
    145143void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
    146 void __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ ));
    147144
    148145extern "C" {
    149146        void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
    150                 abort( false, "%s", "" );
     147                abort( false, NULL ); // FIX ME: 0p does not work
    151148        }
    152149
     
    154151                va_list argp;
    155152                va_start( argp, fmt );
    156                 __abort( false, fmt, argp );
     153                abort( false, fmt, argp );
    157154                va_end( argp );
    158155        }
     
    164161
    165162void * kernel_abort( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 0p; }
    166 void kernel_abort_msg( void * data, char buffer[], int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
     163void kernel_abort_msg( void * data, char * buffer, int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
    167164// See concurrency/kernel.cfa for strong definition used in multi-processor mode.
    168165int kernel_abort_lastframe( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 4; }
     
    172169
    173170static void __cfaabi_backtrace( int start ) {
    174         enum { Frames = 50, };                                                          // maximum number of stack frames
     171        enum {
     172                Frames = 50,                                                                    // maximum number of stack frames
     173        };
    175174        int last = kernel_abort_lastframe();                            // skip last N stack frames
    176175
    177176        void * array[Frames];
    178177        size_t size = backtrace( array, Frames );
    179         char ** messages = backtrace_symbols( array, size ); // does not demangle names
     178        char ** messages = backtrace_symbols( array, size );
    180179
    181180        *index( messages[0], '(' ) = '\0';                                      // find executable name
     
    185184                char * name = 0p, * offset_begin = 0p, * offset_end = 0p;
    186185
    187                 for ( char * p = messages[i]; *p; p += 1 ) {    // find parantheses and +offset
     186                for ( char * p = messages[i]; *p; ++p ) {               // find parantheses and +offset
    188187                        //__cfaabi_bits_print_nolock( "X %s\n", p);
    189188                        if ( *p == '(' ) {
     
    220219}
    221220
    222 static volatile int __abort_stage = 0;
    223 
    224 // Cannot forward va_list.
    225 void __abort( bool signalAbort, const char fmt[], va_list args ) {
    226         int stage = __atomic_add_fetch( &__abort_stage, 1, __ATOMIC_SEQ_CST );
    227 
    228         // First stage: stop the cforall kernel and print
    229         if(stage == 1) {
    230                 // increment stage
    231                 stage = __atomic_add_fetch( &__abort_stage, 1, __ATOMIC_SEQ_CST );
    232 
    233                 // must be done here to lock down kernel
    234                 void * kernel_data = kernel_abort();
    235                 int len;
    236 
    237                 signal( SIGABRT, SIG_DFL );                                                     // prevent final "real" abort from recursing to handler
    238 
    239                 len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid)
     221void abort( bool signalAbort, const char fmt[], ... ) {
     222        void * kernel_data = kernel_abort();                            // must be done here to lock down kernel
     223        int len;
     224
     225        signal( SIGABRT, SIG_DFL );                                                     // prevent final "real" abort from recursing to handler
     226
     227        len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid)
     228        __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
     229
     230        if ( fmt ) {
     231                va_list args;
     232                va_start( args, fmt );
     233
     234                len = vsnprintf( abort_text, abort_text_size, fmt, args );
     235                va_end( args );
    240236                __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
    241237
    242                 assert( fmt );
    243                 len = vsnprintf( abort_text, abort_text_size, fmt, args );
    244                 __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
    245 
    246                 // add optional newline if missing at the end of the format text
    247                 if ( fmt[strlen( fmt ) - 1] != '\n' ) {
    248                         __cfaabi_bits_write( STDERR_FILENO, "\n", 1 );
    249                 } // if
    250                 kernel_abort_msg( kernel_data, abort_text, abort_text_size );
    251         }
    252 
    253         // Second stage: print the backtrace
    254         if(stage == 2) {
    255                 // increment stage
    256                 stage = __atomic_add_fetch( &__abort_stage, 1, __ATOMIC_SEQ_CST );
    257 
    258                 // print stack trace in handler
    259                 __cfaabi_backtrace( signalAbort ? 4 : 2 );
    260         }
    261 
    262         do {
    263                 // Finally call abort
    264                 __cabi_libc.abort();
    265 
    266                 // Loop so that we never return
    267         } while(true);
     238                if ( fmt[strlen( fmt ) - 1] != '\n' ) {                 // add optional newline if missing at the end of the format text
     239                        __cfaabi_dbg_write( "\n", 1 );
     240                }
     241        }
     242
     243        kernel_abort_msg( kernel_data, abort_text, abort_text_size );
     244        __cfaabi_backtrace( signalAbort ? 4 : 3 );
     245
     246        __cabi_libc.abort();                                                            // print stack trace in handler
    268247}
    269248
     
    271250        va_list args;
    272251        va_start( args, fmt );
    273         __abort( false, fmt, args );
    274     // CONTROL NEVER REACHES HERE!
     252        abort( false, fmt, args );
    275253        va_end( args );
    276 }
    277 
    278 void abort( bool signalAbort, const char fmt[], ... ) {
    279     va_list args;
    280     va_start( args, fmt );
    281     __abort( signalAbort, fmt, args );
    282     // CONTROL NEVER REACHES HERE!
    283     va_end( args );
    284254}
    285255
  • libcfa/src/iostream.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Aug 24 08:31:35 2020
    13 // Update Count     : 1130
     12// Last Modified On : Sat Jul 13 08:07:59 2019
     13// Update Count     : 821
    1414//
    1515
    1616#include "iostream.hfa"
    1717
     18extern "C" {
    1819#include <stdio.h>
    1920#include <stdbool.h>                                                                    // true/false
    20 #include <stdint.h>                                                                             // UINT64_MAX
    21 #include <float.h>                                                                              // DBL_DIG, LDBL_DIG
    22 #include <complex.h>                                                                    // creal, cimag
    23 //#include <string.h>                                                                   // strlen, strcmp, memcpy
    24 extern "C" {
     21//#include <string.h>                                                                   // strlen, strcmp
    2522extern size_t strlen (const char *__s) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1)));
    2623extern int strcmp (const char *__s1, const char *__s2) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1, 2)));
    2724extern char *strcpy (char *__restrict __dest, const char *__restrict __src) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
    2825extern void *memcpy (void *__restrict __dest, const void *__restrict __src, size_t __n) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
     26#include <float.h>                                                                              // DBL_DIG, LDBL_DIG
     27#include <math.h>                                                                               // isfinite
     28#include <complex.h>                                                                    // creal, cimag
    2929} // extern "C"
    3030
    31 #include "math.hfa"                                                                             // isfinite, floor, ceiling_div
    32 #include "bitmanip.hfa"                                                                 // high1
    33 
    34 
    35 // *********************************** ostream ***********************************
     31
     32//*********************************** ostream ***********************************
    3633
    3734
    3835forall( dtype ostype | ostream( ostype ) ) {
     36        ostype & ?|?( ostype & os, zero_t ) {
     37                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     38                fmt( os, "%d", 0n );
     39                return os;
     40        } // ?|?
     41        void ?|?( ostype & os, zero_t z ) {
     42                (ostype &)(os | z); ends( os );
     43        } // ?|?
     44
     45        ostype & ?|?( ostype & os, one_t ) {
     46                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     47                fmt( os, "%d", 1n );
     48                return os;
     49        } // ?|?
     50        void ?|?( ostype & os, one_t o ) {
     51                (ostype &)(os | o); ends( os );
     52        } // ?|?
     53
    3954        ostype & ?|?( ostype & os, bool b ) {
    40                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     55                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    4156                fmt( os, "%s", b ? "true" : "false" );
    4257                return os;
     
    4863        ostype & ?|?( ostype & os, char c ) {
    4964                fmt( os, "%c", c );
    50                 if ( c == '\n' ) $setNL( os, true );
     65                if ( c == '\n' ) setNL( os, true );
    5166                return sepOff( os );
    5267        } // ?|?
     
    5671
    5772        ostype & ?|?( ostype & os, signed char sc ) {
    58                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     73                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    5974                fmt( os, "%hhd", sc );
    6075                return os;
     
    6580
    6681        ostype & ?|?( ostype & os, unsigned char usc ) {
    67                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     82                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    6883                fmt( os, "%hhu", usc );
    6984                return os;
     
    7489
    7590        ostype & ?|?( ostype & os, short int si ) {
    76                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     91                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    7792                fmt( os, "%hd", si );
    7893                return os;
     
    8398
    8499        ostype & ?|?( ostype & os, unsigned short int usi ) {
    85                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     100                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    86101                fmt( os, "%hu", usi );
    87102                return os;
     
    92107
    93108        ostype & ?|?( ostype & os, int i ) {
    94                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     109                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    95110                fmt( os, "%d", i );
    96111                return os;
     
    101116
    102117        ostype & ?|?( ostype & os, unsigned int ui ) {
    103                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     118                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    104119                fmt( os, "%u", ui );
    105120                return os;
     
    110125
    111126        ostype & ?|?( ostype & os, long int li ) {
    112                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     127                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    113128                fmt( os, "%ld", li );
    114129                return os;
     
    119134
    120135        ostype & ?|?( ostype & os, unsigned long int uli ) {
    121                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     136                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    122137                fmt( os, "%lu", uli );
    123138                return os;
     
    128143
    129144        ostype & ?|?( ostype & os, long long int lli ) {
    130                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     145                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    131146                fmt( os, "%lld", lli );
    132147                return os;
     
    137152
    138153        ostype & ?|?( ostype & os, unsigned long long int ulli ) {
    139                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     154                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    140155                fmt( os, "%llu", ulli );
    141156                return os;
     
    144159                (ostype &)(os | ulli); ends( os );
    145160        } // ?|?
    146 
    147 #if defined( __SIZEOF_INT128__ )
    148         //      UINT64_MAX 18_446_744_073_709_551_615_ULL
    149         #define P10_UINT64 10_000_000_000_000_000_000_ULL       // 19 zeroes
    150 
    151         static inline void base10_128( ostype & os, unsigned int128 val ) {
    152 #if defined(__GNUC__) && __GNUC_PREREQ(7,0)                             // gcc version >= 7
    153                 if ( val > P10_UINT64 ) {
    154 #else
    155                 if ( (uint64_t)(val >> 64) != 0 || (uint64_t)val > P10_UINT64 ) { // patch gcc 5 & 6 -O3 bug
    156 #endif // __GNUC_PREREQ(7,0)
    157                         base10_128( os, val / P10_UINT64 );                     // recursive
    158                         fmt( os, "%.19lu", (uint64_t)(val % P10_UINT64) );
    159                 } else {
    160                         fmt( os, "%lu", (uint64_t)val );
    161                 } // if
    162         } // base10_128
    163 
    164         static inline void base10_128( ostype & os, int128 val ) {
    165                 if ( val < 0 ) {
    166                         fmt( os, "-" );                                                         // leading negative sign
    167                         val = -val;
    168                 } // if
    169                 base10_128( os, (unsigned int128)val );                 // print zero/positive value
    170         } // base10_128
    171 
    172         ostype & ?|?( ostype & os, int128 llli ) {
    173                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    174                 base10_128( os, llli );
    175                 return os;
    176         } // ?|?
    177         void & ?|?( ostype & os, int128 llli ) {
    178                 (ostype &)(os | llli); ends( os );
    179         } // ?|?
    180 
    181         ostype & ?|?( ostype & os, unsigned int128 ullli ) {
    182                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    183                 base10_128( os, ullli );
    184                 return os;
    185         } // ?|?
    186         void & ?|?( ostype & os, unsigned int128 ullli ) {
    187                 (ostype &)(os | ullli); ends( os );
    188         } // ?|?
    189 #endif // __SIZEOF_INT128__
    190161
    191162        #define PrintWithDP( os, format, val, ... ) \
     
    204175
    205176        ostype & ?|?( ostype & os, float f ) {
    206                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     177                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    207178                PrintWithDP( os, "%g", f );
    208179                return os;
     
    213184
    214185        ostype & ?|?( ostype & os, double d ) {
    215                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     186                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    216187                PrintWithDP( os, "%.*lg", d, DBL_DIG );
    217188                return os;
     
    222193
    223194        ostype & ?|?( ostype & os, long double ld ) {
    224                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     195                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    225196                PrintWithDP( os, "%.*Lg", ld, LDBL_DIG );
    226197                return os;
     
    231202
    232203        ostype & ?|?( ostype & os, float _Complex fc ) {
    233                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     204                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    234205//              os | crealf( fc ) | nonl;
    235206                PrintWithDP( os, "%g", crealf( fc ) );
     
    243214
    244215        ostype & ?|?( ostype & os, double _Complex dc ) {
    245                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     216                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    246217//              os | creal( dc ) | nonl;
    247218                PrintWithDP( os, "%.*lg", creal( dc ), DBL_DIG );
     
    255226
    256227        ostype & ?|?( ostype & os, long double _Complex ldc ) {
    257                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     228                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    258229//              os | creall( ldc ) || nonl;
    259230                PrintWithDP( os, "%.*Lg", creall( ldc ), LDBL_DIG );
     
    266237        } // ?|?
    267238
    268         ostype & ?|?( ostype & os, const char str[] ) {
     239        ostype & ?|?( ostype & os, const char * str ) {
    269240                enum { Open = 1, Close, OpenClose };
    270241                static const unsigned char mask[256] @= {
     
    286257                // first character IS NOT spacing or closing punctuation => add left separator
    287258                unsigned char ch = str[0];                                              // must make unsigned
    288                 if ( $sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
    289                         fmt( os, "%s", $sepGetCur( os ) );
     259                if ( sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
     260                        fmt( os, "%s", sepGetCur( os ) );
    290261                } // if
    291262
    292263                // if string starts line, must reset to determine open state because separator is off
    293                 $sepReset( os );                                                                // reset separator
     264                sepReset( os );                                                                 // reset separator
    294265
    295266                // last character IS spacing or opening punctuation => turn off separator for next item
    296267                size_t len = strlen( str );
    297268                ch = str[len - 1];                                                              // must make unsigned
    298                 if ( $sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
     269                if ( sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
    299270                        sepOn( os );
    300271                } else {
    301272                        sepOff( os );
    302273                } // if
    303                 if ( ch == '\n' ) $setNL( os, true );                   // check *AFTER* $sepPrt call above as it resets NL flag
     274                if ( ch == '\n' ) setNL( os, true );                    // check *AFTER* sepPrt call above as it resets NL flag
    304275                return write( os, str, len );
    305276        } // ?|?
    306 
    307         void ?|?( ostype & os, const char str[] ) {
     277        void ?|?( ostype & os, const char * str ) {
    308278                (ostype &)(os | str); ends( os );
    309279        } // ?|?
    310280
    311281//      ostype & ?|?( ostype & os, const char16_t * str ) {
    312 //              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     282//              if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    313283//              fmt( os, "%ls", str );
    314284//              return os;
     
    317287// #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
    318288//      ostype & ?|?( ostype & os, const char32_t * str ) {
    319 //              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     289//              if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    320290//              fmt( os, "%ls", str );
    321291//              return os;
     
    324294
    325295//      ostype & ?|?( ostype & os, const wchar_t * str ) {
    326 //              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     296//              if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    327297//              fmt( os, "%ls", str );
    328298//              return os;
     
    330300
    331301        ostype & ?|?( ostype & os, const void * p ) {
    332                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     302                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    333303                fmt( os, "%p", p );
    334304                return os;
     
    345315        void ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {
    346316                (ostype &)(manip( os ));
    347                 if ( $getPrt( os ) ) ends( os );                                // something printed ?
    348                 $setPrt( os, false );                                                   // turn off
     317                if ( getPrt( os ) ) ends( os );                                 // something printed ?
     318                setPrt( os, false );                                                    // turn off
    349319        } // ?|?
    350320
     
    359329        ostype & nl( ostype & os ) {
    360330                (ostype &)(os | '\n');
    361                 $setPrt( os, false );                                                   // turn off
    362                 $setNL( os, true );
     331                setPrt( os, false );                                                    // turn off
     332                setNL( os, true );
    363333                flush( os );
    364334                return sepOff( os );                                                    // prepare for next line
     
    366336
    367337        ostype & nonl( ostype & os ) {
    368                 $setPrt( os, false );                                                   // turn off
     338                setPrt( os, false );                                                    // turn off
    369339                return os;
    370340        } // nonl
     
    405375        ostype & ?|?( ostype & os, T arg, Params rest ) {
    406376                (ostype &)(os | arg);                                                   // print first argument
    407                 $sepSetCur( os, sepGetTuple( os ) );                    // switch to tuple separator
     377                sepSetCur( os, sepGetTuple( os ) );                             // switch to tuple separator
    408378                (ostype &)(os | rest);                                                  // print remaining arguments
    409                 $sepSetCur( os, sepGet( os ) );                                 // switch to regular separator
     379                sepSetCur( os, sepGet( os ) );                                  // switch to regular separator
    410380                return os;
    411381        } // ?|?
     
    413383                // (ostype &)(?|?( os, arg, rest )); ends( os );
    414384                (ostype &)(os | arg);                                                   // print first argument
    415                 $sepSetCur( os, sepGetTuple( os ) );                    // switch to tuple separator
     385                sepSetCur( os, sepGetTuple( os ) );                             // switch to tuple separator
    416386                (ostype &)(os | rest);                                                  // print remaining arguments
    417                 $sepSetCur( os, sepGet( os ) );                                 // switch to regular separator
     387                sepSetCur( os, sepGet( os ) );                                  // switch to regular separator
    418388                ends( os );
    419389        } // ?|?
     
    433403} // distribution
    434404
    435 // *********************************** manipulators ***********************************
    436 
    437 // *********************************** integral ***********************************
     405//*********************************** manipulators ***********************************
     406
     407//*********************************** integral ***********************************
    438408
    439409static const char * shortbin[] = { "0", "1", "10", "11", "100", "101", "110", "111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" };
     
    441411
    442412// Default prefix for non-decimal prints is 0b, 0, 0x.
    443 #define IntegralFMTImpl( T, IFMTNP, IFMTP ) \
     413#define IntegralFMTImpl( T, CODE, IFMTNP, IFMTP ) \
    444414forall( dtype ostype | ostream( ostype ) ) { \
    445415        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    446                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
     416                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); \
    447417\
    448418                if ( f.base == 'b' || f.base == 'B' ) {                 /* bespoke binary format */ \
    449                         int bits = high1( f.val );                                      /* position of most significant bit */ \
    450                         if ( bits == 0 ) bits = 1;                                      /* 0 value => force one bit to print */ \
    451                         int spaces; \
     419                        int bits;                                                                                                       \
     420                        if ( f.val == (T){0} ) bits = 1;                        /* force at least one bit to print */ \
     421                        else bits = sizeof(long long int) * 8 - __builtin_clzll( f.val ); /* position of most significant bit */ \
     422                        bits = bits > sizeof(f.val) * 8 ? sizeof(f.val) * 8 : bits; \
     423                        int spaces = f.wd - bits;                                       /* can be negative */ \
     424                        if ( ! f.flags.nobsdp ) { spaces -= 2; }        /* base prefix takes space */ \
     425                        /* printf( "%d %d\n", bits, spaces ); */ \
    452426                        if ( ! f.flags.left ) {                                         /* right justified ? */ \
    453427                                /* Note, base prefix then zero padding or spacing then prefix. */ \
    454                                 if ( f.flags.pc ) { \
    455                                         spaces = f.wd - f.pc; \
    456                                         if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \
     428                                if ( f.flags.pad0 || f.flags.pc ) { \
     429                                        if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \
     430                                        if ( f.flags.pc ) spaces = f.pc - bits; \
     431                                        if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \
     432                                } else { \
    457433                                        if ( spaces > 0 ) fmt( os, "%*s", spaces, " " ); /* space pad */ \
    458434                                        if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \
    459                                         spaces = f.pc - bits; \
    460                                         if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \
    461                                 } else { \
    462                                         spaces = f.wd - bits; \
    463                                         if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \
    464                                         if ( f.flags.pad0 ) { \
    465                                                 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \
    466                                                 if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \
    467                                         } else { \
    468                                                 if ( spaces > 0 ) fmt( os, "%*s", spaces, " " ); /* space pad */ \
    469                                                 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \
    470                                         } /* if */ \
    471435                                } /* if */ \
    472                         } else { \
    473                                 if ( ! f.flags.nobsdp ) fmt( os, "0%c", f.base ); \
    474                                 if ( f.flags.pc ) { \
    475                                         spaces = f.pc - bits; \
    476                                         if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \
    477                                         spaces = f.wd - f.pc; \
    478                                 } else { /* pad0 flag ignored with left flag */ \
    479                                         spaces = f.wd - bits; \
    480                                 } /* if */ \
    481                                 if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \
     436                        } else if ( ! f.flags.nobsdp ) { \
     437                                fmt( os, "0%c", f.base ); \
    482438                        } /* if */ \
    483                         int shift = floor( bits - 1, 4 ); \
     439                        int shift = (bits - 1) / 4 * 4; /* floor( bits - 1, 4 ) */ \
    484440                        typeof( f.val ) temp = f.val; \
    485441                        fmt( os, "%s", shortbin[(temp >> shift) & 0xf] ); \
     
    492448                        if ( f.flags.left && spaces > 0 ) fmt( os, "%*s", spaces, " " ); \
    493449                        return os; \
    494                 } /* if */ \
     450                } /* if  */ \
    495451\
    496452                char fmtstr[sizeof(IFMTP)];                                             /* sizeof includes '\0' */ \
     
    502458                if ( ! f.flags.nobsdp ) { fmtstr[star] = '#'; star -= 1; } \
    503459                if ( f.flags.left ) { fmtstr[star] = '-'; star -= 1; } \
    504                 if ( f.flags.sign ) { fmtstr[star] = '+'; star -= 1; } \
     460                if ( f.flags.sign && f.base == CODE ) { fmtstr[star] = '+'; star -= 1; } \
    505461                if ( f.flags.pad0 && ! f.flags.pc ) { fmtstr[star] = '0'; star -= 1; } \
    506462                fmtstr[star] = '%'; \
    507463\
    508464                if ( ! f.flags.pc ) {                                                   /* no precision */ \
     465                        /* printf( "%s\n", &fmtstr[star] ); */ \
    509466                        fmtstr[sizeof(IFMTNP)-2] = f.base;                      /* sizeof includes '\0' */ \
    510                         /* printf( "%s %c\n", &fmtstr[star], f.base ); */ \
    511467                        fmt( os, &fmtstr[star], f.wd, f.val ); \
    512468                } else {                                                                                /* precision */ \
    513469                        fmtstr[sizeof(IFMTP)-2] = f.base;                       /* sizeof includes '\0' */ \
    514                         /* printf( "%s %c\n", &fmtstr[star], f.base ); */ \
     470                        /* printf( "%s\n", &fmtstr[star] ); */ \
    515471                        fmt( os, &fmtstr[star], f.wd, f.pc, f.val ); \
    516472                } /* if */ \
     
    520476} // distribution
    521477
    522 IntegralFMTImpl( signed char, "%    *hh ", "%    *.*hh " )
    523 IntegralFMTImpl( unsigned char, "%    *hh ", "%    *.*hh " )
    524 IntegralFMTImpl( signed short int, "%    *h ", "%    *.*h " )
    525 IntegralFMTImpl( unsigned short int, "%    *h ", "%    *.*h " )
    526 IntegralFMTImpl( signed int, "%    * ", "%    *.* " )
    527 IntegralFMTImpl( unsigned int, "%    * ", "%    *.* " )
    528 IntegralFMTImpl( signed long int, "%    *l ", "%    *.*l " )
    529 IntegralFMTImpl( unsigned long int, "%    *l ", "%    *.*l " )
    530 IntegralFMTImpl( signed long long int, "%    *ll ", "%    *.*ll " )
    531 IntegralFMTImpl( unsigned long long int, "%    *ll ", "%    *.*ll " )
    532 
    533 #if 0
    534 #if defined( __SIZEOF_INT128__ )
    535 // Default prefix for non-decimal prints is 0b, 0, 0x.
    536 #define IntegralFMTImpl128( T, SIGNED, CODE, IFMTNP, IFMTP ) \
    537 forall( dtype ostype | ostream( ostype ) ) \
    538 static void base10_128( ostype & os, _Ostream_Manip(T) f ) { \
    539         if ( f.val > UINT64_MAX ) { \
    540                 unsigned long long int lsig = f.val % P10_UINT64; \
    541                 f.val /= P10_UINT64; /* msig */ \
    542                 base10_128( os, f ); /* recursion */ \
    543                 _Ostream_Manip(unsigned long long int) fmt @= { lsig, 0, 19, 'u', { .all : 0 } }; \
    544                 fmt.flags.nobsdp = true; \
    545                 /* printf( "fmt1 %c %lld %d\n", fmt.base, fmt.val, fmt.all ); */ \
    546                 sepOff( os ); \
    547                 (ostype &)(os | fmt); \
    548         } else { \
    549                 /* printf( "fmt2 %c %lld %d\n", f.base, (unsigned long long int)f.val, f.all ); */ \
    550                 _Ostream_Manip(SIGNED long long int) fmt @= { (SIGNED long long int)f.val, f.wd, f.pc, f.base, { .all : f.all } }; \
    551                 (ostype &)(os | fmt); \
    552         } /* if */ \
    553 } /* base10_128 */ \
    554 forall( dtype ostype | ostream( ostype ) ) { \
    555         ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    556                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
    557 \
    558                 if ( f.base == 'b' | f.base == 'B' | f.base == 'o' | f.base == 'x' | f.base == 'X' ) { \
    559                         unsigned long long int msig = (unsigned long long int)(f.val >> 64); \
    560                         unsigned long long int lsig = (unsigned long long int)(f.val); \
    561                         _Ostream_Manip(SIGNED long long int) fmt @= { msig, f.wd, f.pc, f.base, { .all : f.all } }; \
    562                         _Ostream_Manip(unsigned long long int) fmt2 @= { lsig, 0, 0, f.base, { .all : 0 } }; \
    563                         if ( msig == 0 ) { \
    564                                 fmt.val = lsig; \
    565                                 (ostype &)(os | fmt); \
    566                         } else { \
    567                                 fmt2.flags.pad0 = fmt2.flags.nobsdp = true;     \
    568                                 if ( f.base == 'b' | f.base == 'B' ) { \
    569                                         if ( fmt.flags.pc && fmt.pc > 64 ) fmt.pc -= 64; else { fmt.flags.pc = false; fmt.pc = 0; } \
    570                                         if ( fmt.flags.left ) { \
    571                                                 fmt.flags.left = false; \
    572                                                 fmt.wd = 0; \
    573                                                 /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
    574                                                 fmt2.flags.left = true; \
    575                                                 int msigd = high1( msig ); \
    576                                                 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
    577                                                 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0b base specifier */ \
    578                                                 if ( (int)fmt2.wd < 64 ) fmt2.wd = 64; /* cast deals with negative value */ \
    579                                                 fmt2.flags.pc = true; fmt2.pc = 64; \
    580                                         } else { \
    581                                                 if ( fmt.wd > 64 ) fmt.wd -= 64; \
    582                                                 else fmt.wd = 1; \
    583                                                 /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
    584                                                 fmt2.wd = 64; \
    585                                         } /* if */ \
    586                                         /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
    587                                         (ostype &)(os | fmt | "" | fmt2); \
    588                                 } else if ( f.base == 'o' ) { \
    589                                         if ( fmt.flags.pc && fmt.pc > 22 ) fmt.pc -= 22; else { fmt.flags.pc = false; fmt.pc = 0; } \
    590                                         fmt.val = (unsigned long long int)fmt.val >> 2; \
    591                                         fmt2.val = ((msig & 0x3) << 1) + ((lsig & 0x8000000000000000U) != 0); \
    592                                         if ( fmt.flags.left ) { \
    593                                                 fmt.flags.left = false; \
    594                                                 fmt.wd = 0; \
    595                                                 /* printf( "L %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
    596                                                 (ostype &)(os | fmt | "" | fmt2); \
    597                                                 sepOff( os ); \
    598                                                 fmt2.flags.left = true; \
    599                                                 int msigd = ceiling_div( high1( fmt.val ), 3 ); \
    600                                                 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
    601                                                 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 1; /* compensate for 0 base specifier */ \
    602                                                 if ( (int)fmt2.wd < 21 ) fmt2.wd = 21; /* cast deals with negative value */ \
    603                                                 fmt2.flags.pc = true; fmt2.pc = 21; \
    604                                         } else { \
    605                                                 if ( fmt.wd > 22 ) fmt.wd -= 22; \
    606                                                 else fmt.wd = 1; \
    607                                                 /* printf( "R %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
    608                                                 (ostype &)(os | fmt | "" | fmt2); \
    609                                                 sepOff( os ); \
    610                                                 fmt2.wd = 21; \
    611                                         } /* if */ \
    612                                         fmt2.val = lsig & 0x7fffffffffffffffU; \
    613                                         /* printf( "\nC %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
    614                                         (ostype &)(os | fmt2); \
    615                                 } else { /* f.base == 'x'  | f.base == 'X' */ \
    616                                         if ( fmt.flags.pc && fmt.pc > 16 ) fmt.pc -= 16; else { fmt.flags.pc = false; fmt.pc = 0; } \
    617                                         if ( fmt.flags.left ) { \
    618                                                 fmt.flags.left = false; \
    619                                                 fmt.wd = 0; \
    620                                                 /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
    621                                                 fmt2.flags.left = true; \
    622                                                 int msigd = high1( msig ); \
    623                                                 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
    624                                                 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0x base specifier */ \
    625                                                 if ( (int)fmt2.wd < 16 ) fmt2.wd = 16; /* cast deals with negative value */ \
    626                                                 fmt2.flags.pc = true; fmt2.pc = 16; \
    627                                         } else { \
    628                                                 if ( fmt.wd > 16 ) fmt.wd -= 16; \
    629                                                 else fmt.wd = 1; \
    630                                                 /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
    631                                                 fmt2.wd = 16; \
    632                                         } /* if */ \
    633                                         /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
    634                                         (ostype &)(os | fmt | "" | fmt2); \
    635                                 } /* if */ \
    636                         } /* if */ \
    637                 } else { \
    638                         if ( CODE == 'd' ) { \
    639                                 if ( f.val < 0 )  { fmt( os, "-" ); sepOff( os ); f.val = -f.val; f.flags.sign = false; } \
    640                         } /* if */ \
    641                         base10_128( os, f ); \
    642                 } /* if */ \
    643                 return os; \
    644         } /* ?|? */ \
    645         void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
    646 } // distribution
    647 
    648 IntegralFMTImpl128( int128, signed, 'd', "%    *ll ", "%    *.*ll " )
    649 IntegralFMTImpl128( unsigned int128, unsigned, 'u', "%    *ll ", "%    *.*ll " )
    650 #endif // __SIZEOF_INT128__
    651 #endif // 0
    652 
    653 #if 1
    654 #if defined( __SIZEOF_INT128__ )
    655 // Default prefix for non-decimal prints is 0b, 0, 0x.
    656 forall( dtype ostype | ostream( ostype ) )
    657 static inline void base_128( ostype & os, unsigned int128 val, unsigned int128 power, _Ostream_Manip(uint64_t) & f, unsigned int maxdig, unsigned int bits, unsigned int cnt = 0 ) {
    658         int wd = 1;                                                                                     // f.wd is never 0 because 0 implies left-pad
    659         if ( val > power ) {                                                            // subdivide value into printable 64-bit values
    660                 base_128( os, val / power, power, f, maxdig, bits, cnt + 1 ); // recursive
    661                 f.val = val % power;
    662                 if ( cnt == 1 && f.flags.left ) { wd = f.wd; f.wd = maxdig; } // copy f.wd and reset for printing middle chunk
    663                 // printf( "R val:%#lx(%lu) wd:%u pc:%u base:%c neg:%d pc:%d left:%d nobsdp:%d sign:%d pad0:%d\n",
    664                 //              f.val, f.val, f.wd, f.pc, f.base, f.flags.neg, f.flags.pc, f.flags.left, f.flags.nobsdp, f.flags.sign, f.flags.pad0 );
    665                 (ostype &)(os | f);
    666                 if ( cnt == 1 ) {
    667                         if ( f.flags.left ) { wd -= maxdig; f.wd = wd < 0 ? 1 : wd; } // update and restore f.wd for printing end chunk
    668                         sepOff( os );                                                           // no seperator between chunks
    669                 } // if
    670         } else {                                                                                        // print start chunk
    671                 f.val = val;
    672                 // f.pc is unsigned => use wd
    673                 if ( f.flags.pc && f.pc > maxdig * cnt ) { wd = f.pc - maxdig * cnt; f.pc = wd < 0 ? 0 : wd; }
    674                 else { f.flags.pc = false; f.pc = 0; }
    675 
    676                 if ( ! f.flags.left ) {                                                 // right justify
    677                         wd = f.wd - maxdig * cnt;
    678                         f.wd = wd < 0 ? 1 : wd;
    679                         wd = maxdig;
    680                 } else {                                                                                // left justify
    681                         if ( cnt != 0 ) {                                                       // value >= 2^64 ?
    682                                 unsigned int dig, bs = 0;
    683                                 // compute size of prefix digits and base
    684                                 if ( f.base == 'd' || f.base == 'u' ) { // no base prefix
    685                                         dig = ceil( log10( f.val ) );           // use floating-point
    686                                         if ( f.base == 'd' && (f.flags.neg || f.flags.sign) ) bs = 1; // sign ?
    687                                 } else {
    688                                         dig = ceiling_div( high1( f.val ), bits );
    689                                         if ( ! f.flags.nobsdp ) {                       // base prefix ?
    690                                                 if ( f.base == 'o' ) {
    691                                                         // 0 prefix for octal is not added for precision with leading zero
    692                                                         if ( f.pc <= dig ) bs = 1;      // 1 character prefix
    693                                                 } else bs = 2;                                  // 2 character prefix
    694                                         } // if
    695                                 } // if
    696                                 wd = f.wd - (f.pc > dig ? f.pc : dig) - bs; // precision > leading digits ?
    697                                 if ( wd < 0 ) wd = 1;
    698                                 f.wd = 1;
    699                         } // if
    700                         // all manipulators handled implicitly for value < 2^64
    701                 } // if
    702                 // prior checks ensure wd not negative
    703 
    704                 if ( f.flags.neg ) f.val = -f.val;
    705                 // printf( "L val:%#lx(%lu) wd:%u pc:%u base:%c neg:%d pc:%d left:%d nobsdp:%d sign:%d pad0:%d\n",
    706                 //              f.val, f.val, f.wd, f.pc, f.base, f.flags.neg, f.flags.pc, f.flags.left, f.flags.nobsdp, f.flags.sign, f.flags.pad0 );
    707                 (ostype &)(os | f);
    708 
    709                 // remaining middle and end chunks are padded with 0s on the left
    710                 if ( ! f.flags.left ) { f.flags.pad0 = true; f.flags.pc = false; } // left pad with 0s
    711                 else { f.pc = maxdig; f.flags.pc = true; }              // left pad with precision
    712 
    713                 if ( cnt != 0 ) sepOff( os );                                   // no seperator between chunks
    714                 f.wd = wd;                                                                              // reset f.wd for next chunk
    715                 f.flags.sign = false;                                                   // no leading +/- sign
    716                 f.flags.nobsdp = true;                                                  // no leading base prefix
    717         } // if
    718 } // base_128
    719 
    720 #define IntegralFMTImpl128( T ) \
    721 forall( dtype ostype | ostream( ostype ) ) { \
    722         ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    723                 _Ostream_Manip(uint64_t) fmt; \
    724                 fmt.[wd, pc, base, all] = f.[wd, pc, base, all]; \
    725                 if ( f.base == 'b' | f.base == 'B' ) { \
    726                         base_128( os, f.val, (unsigned int128)1 << 64, fmt, 64, 1 ); \
    727                 } else if ( f.base == 'o' ) { \
    728                         base_128( os, f.val, (unsigned int128)1 << 63, fmt, 21, 3 ); \
    729                 } else if ( f.base == 'd' || f.base == 'u' ) { \
    730                         if ( f.base == 'd' && f.val < 0 ) { f.val = -f.val; fmt.flags.neg = true; } \
    731                         base_128( os, f.val, (unsigned int128)10_000_000_000_000_000_000UL, fmt, 19, 0 ); \
    732                 } else { \
    733                         base_128( os, f.val, (unsigned int128)1 << 64, fmt, 16, 4 ); \
    734                 } /* if */ \
    735                 return os; \
    736         } /* ?|? */ \
    737         void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
    738 } // distribution
    739 
    740 IntegralFMTImpl128( int128 )
    741 IntegralFMTImpl128( unsigned int128 )
    742 #endif // __SIZEOF_INT128__
    743 #endif // 0
    744 
    745 // *********************************** floating point ***********************************
     478IntegralFMTImpl( signed char, 'd', "%    *hh ", "%    *.*hh " )
     479IntegralFMTImpl( unsigned char, 'u', "%    *hh ", "%    *.*hh " )
     480IntegralFMTImpl( signed short int, 'd', "%    *h ", "%    *.*h " )
     481IntegralFMTImpl( unsigned short int, 'u', "%    *h ", "%    *.*h " )
     482IntegralFMTImpl( signed int, 'd', "%    * ", "%    *.* " )
     483IntegralFMTImpl( unsigned int, 'u', "%    * ", "%    *.* " )
     484IntegralFMTImpl( signed long int, 'd', "%    *l ", "%    *.*l " )
     485IntegralFMTImpl( unsigned long int, 'u', "%    *l ", "%    *.*l " )
     486IntegralFMTImpl( signed long long int, 'd', "%    *ll ", "%    *.*ll " )
     487IntegralFMTImpl( unsigned long long int, 'u', "%    *ll ", "%    *.*ll " )
     488
     489//*********************************** floating point ***********************************
    746490
    747491#define PrintWithDP2( os, format, val, ... ) \
     
    769513forall( dtype ostype | ostream( ostype ) ) { \
    770514        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    771                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
     515                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); \
    772516                char fmtstr[sizeof(DFMTP)];                                             /* sizeof includes '\0' */ \
    773517                if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \
     
    792536                return os; \
    793537        } /* ?|? */ \
    794 \
    795538        void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
    796539} // distribution
     
    799542FloatingPointFMTImpl( long double, "%    *L ", "%    *.*L " )
    800543
    801 // *********************************** character ***********************************
     544//*********************************** character ***********************************
    802545
    803546forall( dtype ostype | ostream( ostype ) ) {
     
    812555                } // if
    813556
    814                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     557                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    815558
    816559                #define CFMTNP "% * "
     
    828571                return os;
    829572        } // ?|?
    830 
    831573        void ?|?( ostype & os, _Ostream_Manip(char) f ) { (ostype &)(os | f); ends( os ); }
    832574} // distribution
    833575
    834 // *********************************** C string ***********************************
     576//*********************************** C string ***********************************
    835577
    836578forall( dtype ostype | ostream( ostype ) ) {
     
    850592                } // if
    851593
    852                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     594                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    853595
    854596                #define SFMTNP "% * "
     
    874616                return os;
    875617        } // ?|?
    876 
    877618        void ?|?( ostype & os, _Ostream_Manip(const char *) f ) { (ostype &)(os | f); ends( os ); }
    878619} // distribution
    879620
    880621
    881 // *********************************** istream ***********************************
     622//*********************************** istream ***********************************
    882623
    883624
     
    956697        } // ?|?
    957698
    958 #if defined( __SIZEOF_INT128__ )
    959         istype & ?|?( istype & is, int128 & i128 ) {
    960                 return (istype &)(is | (unsigned int128 &)i128);
    961         } // ?|?
    962 
    963         istype & ?|?( istype & is, unsigned int128 & ui128 ) {
    964                 char s[40];
    965                 bool sign = false;
    966 
    967                 if ( fmt( is, " %[-]", s ) == 1 ) sign = true;  // skip whitespace, negative sign ?
    968                 // If the input is too large, the value returned is undefined. If there is no input, no value is returned
    969                 if ( fmt( is, "%39[0-9]%*[0-9]", s ) == 1 ) {   // take first 39 characters, ignore remaining
    970                         ui128 = 0;
    971                         for ( unsigned int i = 0; s[i] != '\0'; i += 1 ) {
    972                                 ui128 = ui128 * 10 + s[i] - '0';
    973                         } // for
    974                         if ( sign ) ui128 = -ui128;
    975                 } else if ( sign ) ungetc( is, '-' );                   // return minus when no digits
    976                 return is;
    977         } // ?|?
    978 #endif // __SIZEOF_INT128__
    979699
    980700        istype & ?|?( istype & is, float & f ) {
     
    1015735        } // ?|?
    1016736
    1017         // istype & ?|?( istype & is, const char fmt[] ) {
     737        // istype & ?|?( istype & is, const char * fmt ) {
    1018738        //      fmt( is, fmt, "" );
    1019739        //      return is;
     
    1046766} // distribution
    1047767
    1048 // *********************************** manipulators ***********************************
     768//*********************************** manipulators ***********************************
    1049769
    1050770forall( dtype istype | istream( istype ) )
  • libcfa/src/iostream.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Aug 11 22:16:14 2020
    13 // Update Count     : 350
     12// Last Modified On : Fri Jul 12 12:08:38 2019
     13// Update Count     : 334
    1414//
    1515
     
    1919
    2020
    21 // *********************************** ostream ***********************************
     21//*********************************** ostream ***********************************
    2222
    2323
    2424trait ostream( dtype ostype ) {
    2525        // private
    26         bool $sepPrt( ostype & );                                                       // get separator state (on/off)
    27         void $sepReset( ostype & );                                                     // set separator state to default state
    28         void $sepReset( ostype &, bool );                                       // set separator and default state
    29         const char * $sepGetCur( ostype & );                            // get current separator string
    30         void $sepSetCur( ostype &, const char [] );                     // set current separator string
    31         bool $getNL( ostype & );                                                        // check newline
    32         void $setNL( ostype &, bool );                                          // saw newline
    33         bool $getANL( ostype & );                                                       // get auto newline (on/off)
    34         bool $getPrt( ostype & );                                                       // get fmt called in output cascade
    35         void $setPrt( ostype &, bool );                                         // set fmt called in output cascade
     26        bool sepPrt( ostype & );                                                        // get separator state (on/off)
     27        void sepReset( ostype & );                                                      // set separator state to default state
     28        void sepReset( ostype &, bool );                                        // set separator and default state
     29        const char * sepGetCur( ostype & );                                     // get current separator string
     30        void sepSetCur( ostype &, const char * );                       // set current separator string
     31        bool getNL( ostype & );                                                         // check newline
     32        void setNL( ostype &, bool );                                           // saw newline
     33        bool getANL( ostype & );                                                        // get auto newline (on/off)
     34        bool getPrt( ostype & );                                                        // get fmt called in output cascade
     35        void setPrt( ostype &, bool );                                          // set fmt called in output cascade
    3636        // public
    3737        void sepOn( ostype & );                                                         // turn separator state on
     
    4343
    4444        const char * sepGet( ostype & );                                        // get separator string
    45         void sepSet( ostype &, const char [] );                         // set separator to string (15 character maximum)
     45        void sepSet( ostype &, const char * );                          // set separator to string (15 character maximum)
    4646        const char * sepGetTuple( ostype & );                           // get tuple separator string
    47         void sepSetTuple( ostype &, const char [] );            // set tuple separator to string (15 character maximum)
     47        void sepSetTuple( ostype &, const char * );                     // set tuple separator to string (15 character maximum)
    4848
    4949        void ends( ostype & os );                                                       // end of output statement
    5050        int fail( ostype & );
    5151        int flush( ostype & );
    52         void open( ostype & os, const char name[], const char mode[] );
     52        void open( ostype & os, const char * name, const char * mode );
    5353        void close( ostype & os );
    54         ostype & write( ostype &, const char [], size_t );
     54        ostype & write( ostype &, const char *, size_t );
    5555        int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
    5656}; // ostream
     
    6767
    6868forall( dtype ostype | ostream( ostype ) ) {
     69        ostype & ?|?( ostype &, zero_t );
     70        void ?|?( ostype &, zero_t );
     71        ostype & ?|?( ostype &, one_t );
     72        void ?|?( ostype &, one_t );
     73
    6974        ostype & ?|?( ostype &, bool );
    7075        void ?|?( ostype &, bool );
     
    9398        ostype & ?|?( ostype &, unsigned long long int );
    9499        void ?|?( ostype &, unsigned long long int );
    95 #if defined( __SIZEOF_INT128__ )
    96         ostype & ?|?( ostype &, int128 );
    97         void ?|?( ostype &, int128 );
    98         ostype & ?|?( ostype &, unsigned int128 );
    99         void ?|?( ostype &, unsigned int128 );
    100 #endif // __SIZEOF_INT128__
    101100
    102101        ostype & ?|?( ostype &, float );
     
    114113        void ?|?( ostype &, long double _Complex );
    115114
    116         ostype & ?|?( ostype &, const char [] );
    117         void ?|?( ostype &, const char [] );
     115        ostype & ?|?( ostype &, const char * );
     116        void ?|?( ostype &, const char * );
    118117        // ostype & ?|?( ostype &, const char16_t * );
    119118#if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
     
    151150} // distribution
    152151
    153 // *********************************** manipulators ***********************************
     152//*********************************** manipulators ***********************************
    154153
    155154forall( otype T )
     
    161160                unsigned char all;
    162161                struct {
    163                         unsigned char neg:1;                                            // val is negative
    164162                        unsigned char pc:1;                                                     // precision specified
    165163                        unsigned char left:1;                                           // left justify
     
    171169}; // _Ostream_Manip
    172170
    173 // *********************************** integral ***********************************
     171//*********************************** integral ***********************************
    174172
    175173// See 6.7.9. 19) The initialization shall occur in initializer list order, each initializer provided for a particular
     
    208206IntegralFMTDecl( signed long long int, 'd' )
    209207IntegralFMTDecl( unsigned long long int, 'u' )
    210 #if defined( __SIZEOF_INT128__ )
    211 IntegralFMTDecl( int128, 'd' )
    212 IntegralFMTDecl( unsigned int128, 'u' )
    213 #endif // __SIZEOF_INT128__
    214 
    215 // *********************************** floating point ***********************************
     208
     209//*********************************** floating point ***********************************
    216210
    217211// Default suffix for values with no fraction is "."
     
    242236FloatingPointFMTDecl( long double )
    243237
    244 // *********************************** character ***********************************
     238//*********************************** character ***********************************
    245239
    246240static inline {
     
    259253} // ?|?
    260254
    261 // *********************************** C string ***********************************
     255//*********************************** C string ***********************************
    262256
    263257static inline {
    264         _Ostream_Manip(const char *) bin( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'b', { .all : 0 } }; }
    265         _Ostream_Manip(const char *) oct( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'o', { .all : 0 } }; }
    266         _Ostream_Manip(const char *) hex( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; }
    267         _Ostream_Manip(const char *) wd( unsigned int w, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; }
    268         _Ostream_Manip(const char *) wd( unsigned int w, unsigned char pc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }
     258        _Ostream_Manip(const char *) bin( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'b', { .all : 0 } }; }
     259        _Ostream_Manip(const char *) oct( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'o', { .all : 0 } }; }
     260        _Ostream_Manip(const char *) hex( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; }
     261        _Ostream_Manip(const char *) wd( unsigned int w, const char * s ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; }
     262        _Ostream_Manip(const char *) wd( unsigned int w, unsigned char pc, const char * s ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }
    269263        _Ostream_Manip(const char *) & wd( unsigned int w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; }
    270264        _Ostream_Manip(const char *) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }
     
    278272
    279273
    280 // *********************************** istream ***********************************
     274//*********************************** istream ***********************************
    281275
    282276
     
    287281        int fail( istype & );
    288282        int eof( istype & );
    289         void open( istype & is, const char name[] );
     283        void open( istype & is, const char * name );
    290284        void close( istype & is );
    291285        istype & read( istype &, char *, size_t );
     
    310304        istype & ?|?( istype &, unsigned int & );
    311305        istype & ?|?( istype &, long int & );
     306        istype & ?|?( istype &, long long int & );
    312307        istype & ?|?( istype &, unsigned long int & );
    313         istype & ?|?( istype &, long long int & );
    314308        istype & ?|?( istype &, unsigned long long int & );
    315 #if defined( __SIZEOF_INT128__ )
    316         istype & ?|?( istype &, int128 & );
    317         istype & ?|?( istype &, unsigned int128 & );
    318 #endif // __SIZEOF_INT128__
    319309
    320310        istype & ?|?( istype &, float & );
     
    326316        istype & ?|?( istype &, long double _Complex & );
    327317
    328 //      istype & ?|?( istype &, const char [] );
     318//      istype & ?|?( istype &, const char * );
    329319        istype & ?|?( istype &, char * );
    330320
     
    336326} // distribution
    337327
    338 // *********************************** manipulators ***********************************
     328//*********************************** manipulators ***********************************
    339329
    340330struct _Istream_Cstr {
     
    353343static inline {
    354344        _Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; }
    355         _Istream_Cstr skip( const char scanset[] ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
    356         _Istream_Cstr incl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
    357         _Istream_Cstr & incl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
    358         _Istream_Cstr excl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; }
    359         _Istream_Cstr & excl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
    360         _Istream_Cstr ignore( char s[] ) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; }
     345        _Istream_Cstr skip( const char * scanset ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
     346        _Istream_Cstr incl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
     347        _Istream_Cstr & incl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
     348        _Istream_Cstr excl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; }
     349        _Istream_Cstr & excl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
     350        _Istream_Cstr ignore( const char * s ) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; }
    361351        _Istream_Cstr & ignore( _Istream_Cstr & fmt ) { fmt.flags.ignore = true; return fmt; }
    362         _Istream_Cstr wdi( unsigned int w, char s[] ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
     352        _Istream_Cstr wdi( unsigned int w, char * s ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
    363353        _Istream_Cstr & wdi( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; }
    364354} // distribution
     
    370360
    371361static inline {
    372         _Istream_Char ignore( const char ) { return (_Istream_Char)@{ true }; }
     362        _Istream_Char ignore( const char c ) { return (_Istream_Char)@{ true }; }
    373363        _Istream_Char & ignore( _Istream_Char & fmt ) { fmt.ignore = true; return fmt; }
    374364} // distribution
    375365forall( dtype istype | istream( istype ) ) istype & ?|?( istype & is, _Istream_Char f );
    376366
    377 forall( dtype T | sized( T ) )
     367forall( otype T )
    378368struct _Istream_Manip {
    379369        T & val;                                                                                        // polymorphic base-type
     
    413403
    414404
    415 // *********************************** time ***********************************
     405//*********************************** time ***********************************
    416406
    417407
  • libcfa/src/math.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Mon Apr 18 23:37:04 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Aug 24 08:56:20 2020
    13 // Update Count     : 126
     12// Last Modified On : Fri Jul 13 11:02:15 2018
     13// Update Count     : 116
    1414//
    1515
     
    1919#include <complex.h>
    2020
     21//---------------------- General ----------------------
     22
     23static inline float ?%?( float x, float y ) { return fmodf( x, y ); }
     24static inline float fmod( float x, float y ) { return fmodf( x, y ); }
     25static inline double ?%?( double x, double y ) { return fmod( x, y ); }
     26// extern "C" { double fmod( double, double ); }
     27static inline long double ?%?( long double x, long double y ) { return fmodl( x, y ); }
     28static inline long double fmod( long double x, long double y ) { return fmodl( x, y ); }
     29
     30static inline float remainder( float x, float y ) { return remainderf( x, y ); }
     31// extern "C" { double remainder( double, double ); }
     32static inline long double remainder( long double x, long double y ) { return remainderl( x, y ); }
     33
     34static inline float remquo( float x, float y, int * quo ) { return remquof( x, y, quo ); }
     35// extern "C" { double remquo( double x, double y, int * quo ); }
     36static inline long double remquo( long double x, long double y, int * quo ) { return remquol( x, y, quo ); }
     37static inline [ int, float ] remquo( float x, float y ) { int quo; x = remquof( x, y, &quo ); return [ quo, x ]; }
     38static inline [ int, double ] remquo( double x, double y ) { int quo; x = remquo( x, y, &quo ); return [ quo, x ]; }
     39static inline [ int, long double ] remquo( long double x, long double y ) { int quo; x = remquol( x, y, &quo ); return [ quo, x ]; }
     40
     41static inline [ float, float ] div( float x, float y ) { y = modff( x / y, &x ); return [ x, y ]; }
     42static inline [ double, double ] div( double x, double y ) { y = modf( x / y, &x ); return [ x, y ]; }
     43static inline [ long double, long double ] div( long double x, long double y ) { y = modfl( x / y, &x ); return [ x, y ]; }
     44
     45static inline float fma( float x, float y, float z ) { return fmaf( x, y, z ); }
     46// extern "C" { double fma( double, double, double ); }
     47static inline long double fma( long double x, long double y, long double z ) { return fmal( x, y, z ); }
     48
     49static inline float fdim( float x, float y ) { return fdimf( x, y ); }
     50// extern "C" { double fdim( double, double ); }
     51static inline long double fdim( long double x, long double y ) { return fdiml( x, y ); }
     52
     53static inline float nan( const char * tag ) { return nanf( tag ); }
     54// extern "C" { double nan( const char * ); }
     55static inline long double nan( const char * tag ) { return nanl( tag ); }
     56
     57//---------------------- Exponential ----------------------
     58
     59static inline float exp( float x ) { return expf( x ); }
     60// extern "C" { double exp( double ); }
     61static inline long double exp( long double x ) { return expl( x ); }
     62static inline float _Complex exp( float _Complex x ) { return cexpf( x ); }
     63static inline double _Complex exp( double _Complex x ) { return cexp( x ); }
     64static inline long double _Complex exp( long double _Complex x ) { return cexpl( x ); }
     65
     66static inline float exp2( float x ) { return exp2f( x ); }
     67// extern "C" { double exp2( double ); }
     68static inline long double exp2( long double x ) { return exp2l( x ); }
     69//static inline float _Complex exp2( float _Complex x ) { return cexp2f( x ); }
     70//static inline double _Complex exp2( double _Complex x ) { return cexp2( x ); }
     71//static inline long double _Complex exp2( long double _Complex x ) { return cexp2l( x ); }
     72
     73static inline float expm1( float x ) { return expm1f( x ); }
     74// extern "C" { double expm1( double ); }
     75static inline long double expm1( long double x ) { return expm1l( x ); }
     76
     77static inline float pow( float x, float y ) { return powf( x, y ); }
     78// extern "C" { double pow( double, double ); }
     79static inline long double pow( long double x, long double y ) { return powl( x, y ); }
     80static inline float _Complex pow( float _Complex x, float _Complex y ) { return cpowf( x, y ); }
     81static inline double _Complex pow( double _Complex x, double _Complex y ) { return cpow( x, y ); }
     82static inline long double _Complex pow( long double _Complex x, long double _Complex y ) { return cpowl( x, y ); }
     83
     84//---------------------- Logarithm ----------------------
     85
     86static inline float log( float x ) { return logf( x ); }
     87// extern "C" { double log( double ); }
     88static inline long double log( long double x ) { return logl( x ); }
     89static inline float _Complex log( float _Complex x ) { return clogf( x ); }
     90static inline double _Complex log( double _Complex x ) { return clog( x ); }
     91static inline long double _Complex log( long double _Complex x ) { return clogl( x ); }
     92
     93static inline float log2( float x ) { return log2f( x ); }
     94// extern "C" { double log2( double ); }
     95static inline long double log2( long double x ) { return log2l( x ); }
     96// static inline float _Complex log2( float _Complex x ) { return clog2f( x ); }
     97// static inline double _Complex log2( double _Complex x ) { return clog2( x ); }
     98// static inline long double _Complex log2( long double _Complex x ) { return clog2l( x ); }
     99
     100static inline float log10( float x ) { return log10f( x ); }
     101// extern "C" { double log10( double ); }
     102static inline long double log10( long double x ) { return log10l( x ); }
     103// static inline float _Complex log10( float _Complex x ) { return clog10f( x ); }
     104// static inline double _Complex log10( double _Complex x ) { return clog10( x ); }
     105// static inline long double _Complex log10( long double _Complex x ) { return clog10l( x ); }
     106
     107static inline float log1p( float x ) { return log1pf( x ); }
     108// extern "C" { double log1p( double ); }
     109static inline long double log1p( long double x ) { return log1pl( x ); }
     110
     111static inline int ilogb( float x ) { return ilogbf( x ); }
     112// extern "C" { int ilogb( double ); }
     113static inline int ilogb( long double x ) { return ilogbl( x ); }
     114
     115static inline float logb( float x ) { return logbf( x ); }
     116// extern "C" { double logb( double ); }
     117static inline long double logb( long double x ) { return logbl( x ); }
     118
     119static inline float sqrt( float x ) { return sqrtf( x ); }
     120// extern "C" { double sqrt( double ); }
     121static inline long double sqrt( long double x ) { return sqrtl( x ); }
     122static inline float _Complex sqrt( float _Complex x ) { return csqrtf( x ); }
     123static inline double _Complex sqrt( double _Complex x ) { return csqrt( x ); }
     124static inline long double _Complex sqrt( long double _Complex x ) { return csqrtl( x ); }
     125
     126static inline float cbrt( float x ) { return cbrtf( x ); }
     127// extern "C" { double cbrt( double ); }
     128static inline long double cbrt( long double x ) { return cbrtl( x ); }
     129
     130static inline float hypot( float x, float y ) { return hypotf( x, y ); }
     131// extern "C" { double hypot( double, double ); }
     132static inline long double hypot( long double x, long double y ) { return hypotl( x, y ); }
     133
     134//---------------------- Trigonometric ----------------------
     135
     136static inline float sin( float x ) { return sinf( x ); }
     137// extern "C" { double sin( double ); }
     138static inline long double sin( long double x ) { return sinl( x ); }
     139static inline float _Complex sin( float _Complex x ) { return csinf( x ); }
     140static inline double _Complex sin( double _Complex x ) { return csin( x ); }
     141static inline long double _Complex sin( long double _Complex x ) { return csinl( x ); }
     142
     143static inline float cos( float x ) { return cosf( x ); }
     144// extern "C" { double cos( double ); }
     145static inline long double cos( long double x ) { return cosl( x ); }
     146static inline float _Complex cos( float _Complex x ) { return ccosf( x ); }
     147static inline double _Complex cos( double _Complex x ) { return ccos( x ); }
     148static inline long double _Complex cos( long double _Complex x ) { return ccosl( x ); }
     149
     150static inline float tan( float x ) { return tanf( x ); }
     151// extern "C" { double tan( double ); }
     152static inline long double tan( long double x ) { return tanl( x ); }
     153static inline float _Complex tan( float _Complex x ) { return ctanf( x ); }
     154static inline double _Complex tan( double _Complex x ) { return ctan( x ); }
     155static inline long double _Complex tan( long double _Complex x ) { return ctanl( x ); }
     156
     157static inline float asin( float x ) { return asinf( x ); }
     158// extern "C" { double asin( double ); }
     159static inline long double asin( long double x ) { return asinl( x ); }
     160static inline float _Complex asin( float _Complex x ) { return casinf( x ); }
     161static inline double _Complex asin( double _Complex x ) { return casin( x ); }
     162static inline long double _Complex asin( long double _Complex x ) { return casinl( x ); }
     163
     164static inline float acos( float x ) { return acosf( x ); }
     165// extern "C" { double acos( double ); }
     166static inline long double acos( long double x ) { return acosl( x ); }
     167static inline float _Complex acos( float _Complex x ) { return cacosf( x ); }
     168static inline double _Complex acos( double _Complex x ) { return cacos( x ); }
     169static inline long double _Complex acos( long double _Complex x ) { return cacosl( x ); }
     170
     171static inline float atan( float x ) { return atanf( x ); }
     172// extern "C" { double atan( double ); }
     173static inline long double atan( long double x ) { return atanl( x ); }
     174static inline float _Complex atan( float _Complex x ) { return catanf( x ); }
     175static inline double _Complex atan( double _Complex x ) { return catan( x ); }
     176static inline long double _Complex atan( long double _Complex x ) { return catanl( x ); }
     177
     178static inline float atan2( float x, float y ) { return atan2f( x, y ); }
     179// extern "C" { double atan2( double, double ); }
     180static inline long double atan2( long double x, long double y ) { return atan2l( x, y ); }
     181
     182// alternative name for atan2
     183static inline float atan( float x, float y ) { return atan2f( x, y ); }
     184static inline double atan( double x, double y ) { return atan2( x, y ); }
     185static inline long double atan( long double x, long double y ) { return atan2l( x, y ); }
     186
     187//---------------------- Hyperbolic ----------------------
     188
     189static inline float sinh( float x ) { return sinhf( x ); }
     190// extern "C" { double sinh( double ); }
     191static inline long double sinh( long double x ) { return sinhl( x ); }
     192static inline float _Complex sinh( float _Complex x ) { return csinhf( x ); }
     193static inline double _Complex sinh( double _Complex x ) { return csinh( x ); }
     194static inline long double _Complex sinh( long double _Complex x ) { return csinhl( x ); }
     195
     196static inline float cosh( float x ) { return coshf( x ); }
     197// extern "C" { double cosh( double ); }
     198static inline long double cosh( long double x ) { return coshl( x ); }
     199static inline float _Complex cosh( float _Complex x ) { return ccoshf( x ); }
     200static inline double _Complex cosh( double _Complex x ) { return ccosh( x ); }
     201static inline long double _Complex cosh( long double _Complex x ) { return ccoshl( x ); }
     202
     203static inline float tanh( float x ) { return tanhf( x ); }
     204// extern "C" { double tanh( double ); }
     205static inline long double tanh( long double x ) { return tanhl( x ); }
     206static inline float _Complex tanh( float _Complex x ) { return ctanhf( x ); }
     207static inline double _Complex tanh( double _Complex x ) { return ctanh( x ); }
     208static inline long double _Complex tanh( long double _Complex x ) { return ctanhl( x ); }
     209
     210static inline float asinh( float x ) { return asinhf( x ); }
     211// extern "C" { double asinh( double ); }
     212static inline long double asinh( long double x ) { return asinhl( x ); }
     213static inline float _Complex asinh( float _Complex x ) { return casinhf( x ); }
     214static inline double _Complex asinh( double _Complex x ) { return casinh( x ); }
     215static inline long double _Complex asinh( long double _Complex x ) { return casinhl( x ); }
     216
     217static inline float acosh( float x ) { return acoshf( x ); }
     218// extern "C" { double acosh( double ); }
     219static inline long double acosh( long double x ) { return acoshl( x ); }
     220static inline float _Complex acosh( float _Complex x ) { return cacoshf( x ); }
     221static inline double _Complex acosh( double _Complex x ) { return cacosh( x ); }
     222static inline long double _Complex acosh( long double _Complex x ) { return cacoshl( x ); }
     223
     224static inline float atanh( float x ) { return atanhf( x ); }
     225// extern "C" { double atanh( double ); }
     226static inline long double atanh( long double x ) { return atanhl( x ); }
     227static inline float _Complex atanh( float _Complex x ) { return catanhf( x ); }
     228static inline double _Complex atanh( double _Complex x ) { return catanh( x ); }
     229static inline long double _Complex atanh( long double _Complex x ) { return catanhl( x ); }
     230
     231//---------------------- Error / Gamma ----------------------
     232
     233static inline float erf( float x ) { return erff( x ); }
     234// extern "C" { double erf( double ); }
     235static inline long double erf( long double x ) { return erfl( x ); }
     236// float _Complex erf( float _Complex );
     237// double _Complex erf( double _Complex );
     238// long double _Complex erf( long double _Complex );
     239
     240static inline float erfc( float x ) { return erfcf( x ); }
     241// extern "C" { double erfc( double ); }
     242static inline long double erfc( long double x ) { return erfcl( x ); }
     243// float _Complex erfc( float _Complex );
     244// double _Complex erfc( double _Complex );
     245// long double _Complex erfc( long double _Complex );
     246
     247static inline float lgamma( float x ) { return lgammaf( x ); }
     248// extern "C" { double lgamma( double ); }
     249static inline long double lgamma( long double x ) { return lgammal( x ); }
     250static inline float lgamma( float x, int * sign ) { return lgammaf_r( x, sign ); }
     251static inline double lgamma( double x, int * sign ) { return lgamma_r( x, sign ); }
     252static inline long double lgamma( long double x, int * sign ) { return lgammal_r( x, sign ); }
     253
     254static inline float tgamma( float x ) { return tgammaf( x ); }
     255// extern "C" { double tgamma( double ); }
     256static inline long double tgamma( long double x ) { return tgammal( x ); }
     257
     258//---------------------- Nearest Integer ----------------------
     259
     260static inline float floor( float x ) { return floorf( x ); }
     261// extern "C" { double floor( double ); }
     262static inline long double floor( long double x ) { return floorl( x ); }
     263
     264static inline float ceil( float x ) { return ceilf( x ); }
     265// extern "C" { double ceil( double ); }
     266static inline long double ceil( long double x ) { return ceill( x ); }
     267
     268static inline float trunc( float x ) { return truncf( x ); }
     269// extern "C" { double trunc( double ); }
     270static inline long double trunc( long double x ) { return truncl( x ); }
     271
     272static inline float rint( float x ) { return rintf( x ); }
     273// extern "C" { double rint( double x ); }
     274static inline long double rint( long double x ) { return rintl( x ); }
     275static inline long int rint( float x ) { return lrintf( x ); }
     276static inline long int rint( double x ) { return lrint( x ); }
     277static inline long int rint( long double x ) { return lrintl( x ); }
     278static inline long long int rint( float x ) { return llrintf( x ); }
     279static inline long long int rint( double x ) { return llrint( x ); }
     280static inline long long int rint( long double x ) { return llrintl( x ); }
     281
     282static inline long int lrint( float x ) { return lrintf( x ); }
     283// extern "C" { long int lrint( double ); }
     284static inline long int lrint( long double x ) { return lrintl( x ); }
     285static inline long long int llrint( float x ) { return llrintf( x ); }
     286// extern "C" { long long int llrint( double ); }
     287static inline long long int llrint( long double x ) { return llrintl( x ); }
     288
     289static inline float nearbyint( float x ) { return nearbyintf( x ); }
     290// extern "C" { double nearbyint( double ); }
     291static inline long double nearbyint( long double x ) { return nearbyintl( x ); }
     292
     293static inline float round( float x ) { return roundf( x ); }
     294// extern "C" { double round( double x ); }
     295static inline long double round( long double x ) { return roundl( x ); }
     296static inline long int round( float x ) { return lroundf( x ); }
     297static inline long int round( double x ) { return lround( x ); }
     298static inline long int round( long double x ) { return lroundl( x ); }
     299static inline long long int round( float x ) { return llroundf( x ); }
     300static inline long long int round( double x ) { return llround( x ); }
     301static inline long long int round( long double x ) { return llroundl( x ); }
     302
     303static inline long int lround( float x ) { return lroundf( x ); }
     304// extern "C" { long int lround( double ); }
     305static inline long int lround( long double x ) { return lroundl( x ); }
     306static inline long long int llround( float x ) { return llroundf( x ); }
     307// extern "C" { long long int llround( double ); }
     308static inline long long int llround( long double x ) { return llroundl( x ); }
     309
     310//---------------------- Manipulation ----------------------
     311
     312static inline float copysign( float x, float y ) { return copysignf( x, y ); }
     313// extern "C" { double copysign( double, double ); }
     314static inline long double copysign( long double x, long double y ) { return copysignl( x, y ); }
     315
     316static inline float frexp( float x, int * ip ) { return frexpf( x, ip ); }
     317// extern "C" { double frexp( double, int * ); }
     318static inline long double frexp( long double x, int * ip ) { return frexpl( x, ip ); }
     319
     320static inline float ldexp( float x, int exp2 ) { return ldexpf( x, exp2 ); }
     321// extern "C" { double ldexp( double, int ); }
     322static inline long double ldexp( long double x, int exp2 ) { return ldexpl( x, exp2 ); }
     323
     324static inline [ float, float ] modf( float x ) { float i; x = modff( x, &i ); return [ i, x ]; }
     325static inline float modf( float x, float * i ) { return modff( x, i ); }
     326static inline [ double, double ] modf( double x ) { double i; x = modf( x, &i ); return [ i, x ]; }
     327// extern "C" { double modf( double, double * ); }
     328static inline [ long double, long double ] modf( long double x ) { long double i; x = modfl( x, &i ); return [ i, x ]; }
     329static inline long double modf( long double x, long double * i ) { return modfl( x, i ); }
     330
     331static inline float nextafter( float x, float y ) { return nextafterf( x, y ); }
     332// extern "C" { double nextafter( double, double ); }
     333static inline long double nextafter( long double x, long double y ) { return nextafterl( x, y ); }
     334
     335static inline float nexttoward( float x, long double y ) { return nexttowardf( x, y ); }
     336// extern "C" { double nexttoward( double, long double ); }
     337static inline long double nexttoward( long double x, long double y ) { return nexttowardl( x, y ); }
     338
     339static inline float scalbn( float x, int exp ) { return scalbnf( x, exp ); }
     340// extern "C" { double scalbn( double, int ); }
     341static inline long double scalbn( long double x, int exp ) { return scalbnl( x, exp ); }
     342static inline float scalbn( float x, long int exp ) { return scalblnf( x, exp ); }
     343static inline double scalbn( double x, long int exp ) { return scalbln( x, exp ); }
     344static inline long double scalbn( long double x, long int exp ) { return scalblnl( x, exp ); }
     345
     346static inline float scalbln( float x, long int exp ) { return scalblnf( x, exp ); }
     347// extern "C" { double scalbln( double, long int ); }
     348static inline long double scalbln( long double x, long int exp ) { return scalblnl( x, exp ); }
     349
    21350//---------------------------------------
    22351
    23352#include "common.hfa"
    24353
    25 //---------------------- General ----------------------
    26 
    27 static inline {
    28         float ?%?( float x, float y ) { return fmodf( x, y ); }
    29         float fmod( float x, float y ) { return fmodf( x, y ); }
    30         double ?%?( double x, double y ) { return fmod( x, y ); }
    31         // extern "C" { double fmod( double, double ); }
    32         long double ?%?( long double x, long double y ) { return fmodl( x, y ); }
    33         long double fmod( long double x, long double y ) { return fmodl( x, y ); }
    34 
    35         float remainder( float x, float y ) { return remainderf( x, y ); }
    36         // extern "C" { double remainder( double, double ); }
    37         long double remainder( long double x, long double y ) { return remainderl( x, y ); }
    38 
    39         float remquo( float x, float y, int * quo ) { return remquof( x, y, quo ); }
    40         // extern "C" { double remquo( double x, double y, int * quo ); }
    41         long double remquo( long double x, long double y, int * quo ) { return remquol( x, y, quo ); }
    42         [ int, float ] remquo( float x, float y ) { int quo; x = remquof( x, y, &quo ); return [ quo, x ]; }
    43         [ int, double ] remquo( double x, double y ) { int quo; x = remquo( x, y, &quo ); return [ quo, x ]; }
    44         [ int, long double ] remquo( long double x, long double y ) { int quo; x = remquol( x, y, &quo ); return [ quo, x ]; }
    45 
    46         [ float, float ] div( float x, float y ) { y = modff( x / y, &x ); return [ x, y ]; }
    47         [ double, double ] div( double x, double y ) { y = modf( x / y, &x ); return [ x, y ]; }
    48         [ long double, long double ] div( long double x, long double y ) { y = modfl( x / y, &x ); return [ x, y ]; }
    49 
    50         float fma( float x, float y, float z ) { return fmaf( x, y, z ); }
    51         // extern "C" { double fma( double, double, double ); }
    52         long double fma( long double x, long double y, long double z ) { return fmal( x, y, z ); }
    53 
    54         float fdim( float x, float y ) { return fdimf( x, y ); }
    55         // extern "C" { double fdim( double, double ); }
    56         long double fdim( long double x, long double y ) { return fdiml( x, y ); }
    57 
    58         float nan( const char tag[] ) { return nanf( tag ); }
    59         // extern "C" { double nan( const char [] ); }
    60         long double nan( const char tag[] ) { return nanl( tag ); }
    61 } // distribution
    62 
    63 //---------------------- Exponential ----------------------
    64 
    65 static inline {
    66         float exp( float x ) { return expf( x ); }
    67         // extern "C" { double exp( double ); }
    68         long double exp( long double x ) { return expl( x ); }
    69         float _Complex exp( float _Complex x ) { return cexpf( x ); }
    70         double _Complex exp( double _Complex x ) { return cexp( x ); }
    71         long double _Complex exp( long double _Complex x ) { return cexpl( x ); }
    72 
    73         float exp2( float x ) { return exp2f( x ); }
    74         // extern "C" { double exp2( double ); }
    75         long double exp2( long double x ) { return exp2l( x ); }
    76         //float _Complex exp2( float _Complex x ) { return cexp2f( x ); }
    77         //double _Complex exp2( double _Complex x ) { return cexp2( x ); }
    78         //long double _Complex exp2( long double _Complex x ) { return cexp2l( x ); }
    79 
    80         float expm1( float x ) { return expm1f( x ); }
    81         // extern "C" { double expm1( double ); }
    82         long double expm1( long double x ) { return expm1l( x ); }
    83 
    84         float pow( float x, float y ) { return powf( x, y ); }
    85         // extern "C" { double pow( double, double ); }
    86         long double pow( long double x, long double y ) { return powl( x, y ); }
    87         float _Complex pow( float _Complex x, float _Complex y ) { return cpowf( x, y ); }
    88         double _Complex pow( double _Complex x, double _Complex y ) { return cpow( x, y ); }
    89         long double _Complex pow( long double _Complex x, long double _Complex y ) { return cpowl( x, y ); }
    90 } // distribution
    91 
    92 //---------------------- Logarithm ----------------------
    93 
    94 static inline {
    95         float log( float x ) { return logf( x ); }
    96         // extern "C" { double log( double ); }
    97         long double log( long double x ) { return logl( x ); }
    98         float _Complex log( float _Complex x ) { return clogf( x ); }
    99         double _Complex log( double _Complex x ) { return clog( x ); }
    100         long double _Complex log( long double _Complex x ) { return clogl( x ); }
    101 
    102         float log2( float x ) { return log2f( x ); }
    103         // extern "C" { double log2( double ); }
    104         long double log2( long double x ) { return log2l( x ); }
    105         // float _Complex log2( float _Complex x ) { return clog2f( x ); }
    106         // double _Complex log2( double _Complex x ) { return clog2( x ); }
    107         // long double _Complex log2( long double _Complex x ) { return clog2l( x ); }
    108 
    109         float log10( float x ) { return log10f( x ); }
    110         // extern "C" { double log10( double ); }
    111         long double log10( long double x ) { return log10l( x ); }
    112         // float _Complex log10( float _Complex x ) { return clog10f( x ); }
    113         // double _Complex log10( double _Complex x ) { return clog10( x ); }
    114         // long double _Complex log10( long double _Complex x ) { return clog10l( x ); }
    115 
    116         float log1p( float x ) { return log1pf( x ); }
    117         // extern "C" { double log1p( double ); }
    118         long double log1p( long double x ) { return log1pl( x ); }
    119 
    120         int ilogb( float x ) { return ilogbf( x ); }
    121         // extern "C" { int ilogb( double ); }
    122         int ilogb( long double x ) { return ilogbl( x ); }
    123 
    124         float logb( float x ) { return logbf( x ); }
    125         // extern "C" { double logb( double ); }
    126         long double logb( long double x ) { return logbl( x ); }
    127 
    128         float sqrt( float x ) { return sqrtf( x ); }
    129         // extern "C" { double sqrt( double ); }
    130         long double sqrt( long double x ) { return sqrtl( x ); }
    131         float _Complex sqrt( float _Complex x ) { return csqrtf( x ); }
    132         double _Complex sqrt( double _Complex x ) { return csqrt( x ); }
    133         long double _Complex sqrt( long double _Complex x ) { return csqrtl( x ); }
    134 
    135         float cbrt( float x ) { return cbrtf( x ); }
    136         // extern "C" { double cbrt( double ); }
    137         long double cbrt( long double x ) { return cbrtl( x ); }
    138 
    139         float hypot( float x, float y ) { return hypotf( x, y ); }
    140         // extern "C" { double hypot( double, double ); }
    141         long double hypot( long double x, long double y ) { return hypotl( x, y ); }
    142 } // distribution
    143 
    144 //---------------------- Trigonometric ----------------------
    145 
    146 static inline {
    147         float sin( float x ) { return sinf( x ); }
    148         // extern "C" { double sin( double ); }
    149         long double sin( long double x ) { return sinl( x ); }
    150         float _Complex sin( float _Complex x ) { return csinf( x ); }
    151         double _Complex sin( double _Complex x ) { return csin( x ); }
    152         long double _Complex sin( long double _Complex x ) { return csinl( x ); }
    153 
    154         float cos( float x ) { return cosf( x ); }
    155         // extern "C" { double cos( double ); }
    156         long double cos( long double x ) { return cosl( x ); }
    157         float _Complex cos( float _Complex x ) { return ccosf( x ); }
    158         double _Complex cos( double _Complex x ) { return ccos( x ); }
    159         long double _Complex cos( long double _Complex x ) { return ccosl( x ); }
    160 
    161         float tan( float x ) { return tanf( x ); }
    162         // extern "C" { double tan( double ); }
    163         long double tan( long double x ) { return tanl( x ); }
    164         float _Complex tan( float _Complex x ) { return ctanf( x ); }
    165         double _Complex tan( double _Complex x ) { return ctan( x ); }
    166         long double _Complex tan( long double _Complex x ) { return ctanl( x ); }
    167 
    168         float asin( float x ) { return asinf( x ); }
    169         // extern "C" { double asin( double ); }
    170         long double asin( long double x ) { return asinl( x ); }
    171         float _Complex asin( float _Complex x ) { return casinf( x ); }
    172         double _Complex asin( double _Complex x ) { return casin( x ); }
    173         long double _Complex asin( long double _Complex x ) { return casinl( x ); }
    174 
    175         float acos( float x ) { return acosf( x ); }
    176         // extern "C" { double acos( double ); }
    177         long double acos( long double x ) { return acosl( x ); }
    178         float _Complex acos( float _Complex x ) { return cacosf( x ); }
    179         double _Complex acos( double _Complex x ) { return cacos( x ); }
    180         long double _Complex acos( long double _Complex x ) { return cacosl( x ); }
    181 
    182         float atan( float x ) { return atanf( x ); }
    183         // extern "C" { double atan( double ); }
    184         long double atan( long double x ) { return atanl( x ); }
    185         float _Complex atan( float _Complex x ) { return catanf( x ); }
    186         double _Complex atan( double _Complex x ) { return catan( x ); }
    187         long double _Complex atan( long double _Complex x ) { return catanl( x ); }
    188 
    189         float atan2( float x, float y ) { return atan2f( x, y ); }
    190         // extern "C" { double atan2( double, double ); }
    191         long double atan2( long double x, long double y ) { return atan2l( x, y ); }
    192 
    193         // alternative name for atan2
    194         float atan( float x, float y ) { return atan2f( x, y ); }
    195         double atan( double x, double y ) { return atan2( x, y ); }
    196         long double atan( long double x, long double y ) { return atan2l( x, y ); }
    197 } // distribution
    198 
    199 //---------------------- Hyperbolic ----------------------
    200 
    201 static inline {
    202         float sinh( float x ) { return sinhf( x ); }
    203         // extern "C" { double sinh( double ); }
    204         long double sinh( long double x ) { return sinhl( x ); }
    205         float _Complex sinh( float _Complex x ) { return csinhf( x ); }
    206         double _Complex sinh( double _Complex x ) { return csinh( x ); }
    207         long double _Complex sinh( long double _Complex x ) { return csinhl( x ); }
    208 
    209         float cosh( float x ) { return coshf( x ); }
    210         // extern "C" { double cosh( double ); }
    211         long double cosh( long double x ) { return coshl( x ); }
    212         float _Complex cosh( float _Complex x ) { return ccoshf( x ); }
    213         double _Complex cosh( double _Complex x ) { return ccosh( x ); }
    214         long double _Complex cosh( long double _Complex x ) { return ccoshl( x ); }
    215 
    216         float tanh( float x ) { return tanhf( x ); }
    217         // extern "C" { double tanh( double ); }
    218         long double tanh( long double x ) { return tanhl( x ); }
    219         float _Complex tanh( float _Complex x ) { return ctanhf( x ); }
    220         double _Complex tanh( double _Complex x ) { return ctanh( x ); }
    221         long double _Complex tanh( long double _Complex x ) { return ctanhl( x ); }
    222 
    223         float asinh( float x ) { return asinhf( x ); }
    224         // extern "C" { double asinh( double ); }
    225         long double asinh( long double x ) { return asinhl( x ); }
    226         float _Complex asinh( float _Complex x ) { return casinhf( x ); }
    227         double _Complex asinh( double _Complex x ) { return casinh( x ); }
    228         long double _Complex asinh( long double _Complex x ) { return casinhl( x ); }
    229 
    230         float acosh( float x ) { return acoshf( x ); }
    231         // extern "C" { double acosh( double ); }
    232         long double acosh( long double x ) { return acoshl( x ); }
    233         float _Complex acosh( float _Complex x ) { return cacoshf( x ); }
    234         double _Complex acosh( double _Complex x ) { return cacosh( x ); }
    235         long double _Complex acosh( long double _Complex x ) { return cacoshl( x ); }
    236 
    237         float atanh( float x ) { return atanhf( x ); }
    238         // extern "C" { double atanh( double ); }
    239         long double atanh( long double x ) { return atanhl( x ); }
    240         float _Complex atanh( float _Complex x ) { return catanhf( x ); }
    241         double _Complex atanh( double _Complex x ) { return catanh( x ); }
    242         long double _Complex atanh( long double _Complex x ) { return catanhl( x ); }
    243 } // distribution
    244 
    245 //---------------------- Error / Gamma ----------------------
    246 
    247 static inline {
    248         float erf( float x ) { return erff( x ); }
    249         // extern "C" { double erf( double ); }
    250         long double erf( long double x ) { return erfl( x ); }
    251         // float _Complex erf( float _Complex );
    252         // double _Complex erf( double _Complex );
    253         // long double _Complex erf( long double _Complex );
    254 
    255         float erfc( float x ) { return erfcf( x ); }
    256         // extern "C" { double erfc( double ); }
    257         long double erfc( long double x ) { return erfcl( x ); }
    258         // float _Complex erfc( float _Complex );
    259         // double _Complex erfc( double _Complex );
    260         // long double _Complex erfc( long double _Complex );
    261 
    262         float lgamma( float x ) { return lgammaf( x ); }
    263         // extern "C" { double lgamma( double ); }
    264         long double lgamma( long double x ) { return lgammal( x ); }
    265         float lgamma( float x, int * sign ) { return lgammaf_r( x, sign ); }
    266         double lgamma( double x, int * sign ) { return lgamma_r( x, sign ); }
    267         long double lgamma( long double x, int * sign ) { return lgammal_r( x, sign ); }
    268 
    269         float tgamma( float x ) { return tgammaf( x ); }
    270         // extern "C" { double tgamma( double ); }
    271         long double tgamma( long double x ) { return tgammal( x ); }
    272 } // distribution
    273 
    274 //---------------------- Nearest Integer ----------------------
    275 
    276 static inline {
    277         signed char floor( signed char n, signed char align ) { return n / align * align; }
    278         unsigned char floor( unsigned char n, unsigned char align ) { return n / align * align; }
    279         short int floor( short int n, short int align ) { return n / align * align; }
    280         unsigned short int floor( unsigned short int n, unsigned short int align ) { return n / align * align; }
    281         int floor( int n, int align ) { return n / align * align; }
    282         unsigned int floor( unsigned int n, unsigned int align ) { return n / align * align; }
    283         long int floor( long int n, long int align ) { return n / align * align; }
    284         unsigned long int floor( unsigned long int n, unsigned long int align ) { return n / align * align; }
    285         long long int floor( long long int n, long long int align ) { return n / align * align; }
    286         unsigned long long int floor( unsigned long long int n, unsigned long long int align ) { return n / align * align; }
    287 
    288         // forall( otype T | { T ?/?( T, T ); T ?*?( T, T ); } )
    289         // T floor( T n, T align ) { return n / align * align; }
    290 
    291         signed char ceiling_div( signed char n, char align ) { return (n + (align - 1)) / align; }
    292         unsigned char ceiling_div( unsigned char n, unsigned char align ) { return (n + (align - 1)) / align; }
    293         short int ceiling_div( short int n, short int align ) { return (n + (align - 1)) / align; }
    294         unsigned short int ceiling_div( unsigned short int n, unsigned short int align ) { return (n + (align - 1)) / align; }
    295         int ceiling_div( int n, int align ) { return (n + (align - 1)) / align; }
    296         unsigned int ceiling_div( unsigned int n, unsigned int align ) { return (n + (align - 1)) / align; }
    297         long int ceiling_div( long int n, long int align ) { return (n + (align - 1)) / align; }
    298         unsigned long int ceiling_div( unsigned long int n, unsigned long int align ) { return (n + (align - 1)) / align; }
    299         long long int ceiling_div( long long int n, long long int align ) { return (n + (align - 1)) / align; }
    300         unsigned long long int ceiling_div( unsigned long long int n, unsigned long long int align ) { return (n + (align - 1)) / align; }
    301 
    302         // forall( otype T | { T ?+?( T, T ); T ?-?( T, T ); T ?%?( T, T ); } )
    303         // T ceiling_div( T n, T align ) { verify( is_pow2( align ) );return (n + (align - 1)) / align; }
    304        
    305         // gcc notices the div/mod pair and saves both so only one div.
    306         signed char ceiling( signed char n, signed char align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
    307         unsigned char ceiling( unsigned char n, unsigned char align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
    308         short int ceiling( short int n, short int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
    309         unsigned short int ceiling( unsigned short int n, unsigned short int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
    310         int ceiling( int n, int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
    311         unsigned int ceiling( unsigned int n, unsigned int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
    312         long int ceiling( long int n, long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
    313         unsigned long int ceiling( unsigned long int n, unsigned long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0) , align); }
    314         long long int ceiling( long long int n, long long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
    315         unsigned long long int ceiling( unsigned long long int n, unsigned long long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); }
    316 
    317         // forall( otype T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T ); T ?/?( T, T ); } )
    318         // T ceiling( T n, T align ) { return return floor( n + (n % align != 0 ? align - 1 : 0), align ); *}
    319 
    320         float floor( float x ) { return floorf( x ); }
    321         // extern "C" { double floor( double ); }
    322         long double floor( long double x ) { return floorl( x ); }
    323 
    324         float ceil( float x ) { return ceilf( x ); }
    325         // extern "C" { double ceil( double ); }
    326         long double ceil( long double x ) { return ceill( x ); }
    327 
    328         float trunc( float x ) { return truncf( x ); }
    329         // extern "C" { double trunc( double ); }
    330         long double trunc( long double x ) { return truncl( x ); }
    331 
    332         float rint( float x ) { return rintf( x ); }
    333         // extern "C" { double rint( double x ); }
    334         long double rint( long double x ) { return rintl( x ); }
    335         long int rint( float x ) { return lrintf( x ); }
    336         long int rint( double x ) { return lrint( x ); }
    337         long int rint( long double x ) { return lrintl( x ); }
    338         long long int rint( float x ) { return llrintf( x ); }
    339         long long int rint( double x ) { return llrint( x ); }
    340         long long int rint( long double x ) { return llrintl( x ); }
    341 
    342         long int lrint( float x ) { return lrintf( x ); }
    343         // extern "C" { long int lrint( double ); }
    344         long int lrint( long double x ) { return lrintl( x ); }
    345         long long int llrint( float x ) { return llrintf( x ); }
    346         // extern "C" { long long int llrint( double ); }
    347         long long int llrint( long double x ) { return llrintl( x ); }
    348 
    349         float nearbyint( float x ) { return nearbyintf( x ); }
    350         // extern "C" { double nearbyint( double ); }
    351         long double nearbyint( long double x ) { return nearbyintl( x ); }
    352 
    353         float round( float x ) { return roundf( x ); }
    354         // extern "C" { double round( double x ); }
    355         long double round( long double x ) { return roundl( x ); }
    356         long int round( float x ) { return lroundf( x ); }
    357         long int round( double x ) { return lround( x ); }
    358         long int round( long double x ) { return lroundl( x ); }
    359         long long int round( float x ) { return llroundf( x ); }
    360         long long int round( double x ) { return llround( x ); }
    361         long long int round( long double x ) { return llroundl( x ); }
    362 
    363         long int lround( float x ) { return lroundf( x ); }
    364         // extern "C" { long int lround( double ); }
    365         long int lround( long double x ) { return lroundl( x ); }
    366         long long int llround( float x ) { return llroundf( x ); }
    367         // extern "C" { long long int llround( double ); }
    368         long long int llround( long double x ) { return llroundl( x ); }
    369 } // distribution
    370 
    371 //---------------------- Manipulation ----------------------
    372 
    373 static inline {
    374         float copysign( float x, float y ) { return copysignf( x, y ); }
    375         // extern "C" { double copysign( double, double ); }
    376         long double copysign( long double x, long double y ) { return copysignl( x, y ); }
    377 
    378         float frexp( float x, int * ip ) { return frexpf( x, ip ); }
    379         // extern "C" { double frexp( double, int * ); }
    380         long double frexp( long double x, int * ip ) { return frexpl( x, ip ); }
    381 
    382         float ldexp( float x, int exp2 ) { return ldexpf( x, exp2 ); }
    383         // extern "C" { double ldexp( double, int ); }
    384         long double ldexp( long double x, int exp2 ) { return ldexpl( x, exp2 ); }
    385 
    386         [ float, float ] modf( float x ) { float i; x = modff( x, &i ); return [ i, x ]; }
    387         float modf( float x, float * i ) { return modff( x, i ); }
    388         [ double, double ] modf( double x ) { double i; x = modf( x, &i ); return [ i, x ]; }
    389         // extern "C" { double modf( double, double * ); }
    390         [ long double, long double ] modf( long double x ) { long double i; x = modfl( x, &i ); return [ i, x ]; }
    391         long double modf( long double x, long double * i ) { return modfl( x, i ); }
    392 
    393         float nextafter( float x, float y ) { return nextafterf( x, y ); }
    394         // extern "C" { double nextafter( double, double ); }
    395         long double nextafter( long double x, long double y ) { return nextafterl( x, y ); }
    396 
    397         float nexttoward( float x, long double y ) { return nexttowardf( x, y ); }
    398         // extern "C" { double nexttoward( double, long double ); }
    399         long double nexttoward( long double x, long double y ) { return nexttowardl( x, y ); }
    400 
    401         float scalbn( float x, int exp ) { return scalbnf( x, exp ); }
    402         // extern "C" { double scalbn( double, int ); }
    403         long double scalbn( long double x, int exp ) { return scalbnl( x, exp ); }
    404         float scalbn( float x, long int exp ) { return scalblnf( x, exp ); }
    405         double scalbn( double x, long int exp ) { return scalbln( x, exp ); }
    406         long double scalbn( long double x, long int exp ) { return scalblnl( x, exp ); }
    407 
    408         float scalbln( float x, long int exp ) { return scalblnf( x, exp ); }
    409         // extern "C" { double scalbln( double, long int ); }
    410         long double scalbln( long double x, long int exp ) { return scalblnl( x, exp ); }
    411 } // distribution
    412 
    413354//---------------------------------------
    414355
    415 static inline {
    416         forall( otype T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T );T ?*?( T, T ); } )
    417         T lerp( T x, T y, T a ) { return x * ((T){1} - a) + y * a; }
    418 
    419         forall( otype T | { void ?{}( T &, zero_t ); void ?{}( T &, one_t ); int ?<?( T, T ); } )
    420         T step( T edge, T x ) { return x < edge ? (T){0} : (T){1}; }
    421 
    422         forall( otype T | { void ?{}( T &, int ); T clamp( T, T, T ); T ?-?( T, T ); T ?*?( T, T ); T ?/?( T, T ); } )
    423         T smoothstep( T edge0, T edge1, T x ) { T t = clamp( (x - edge0) / (edge1 - edge0), (T){0}, (T){1} ); return t * t * ((T){3} - (T){2} * t); }
    424 } // distribution
     356forall( otype T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T );T ?*?( T, T ); } )
     357T lerp( T x, T y, T a ) { return x * ((T){1} - a) + y * a; }
     358
     359forall( otype T | { void ?{}( T &, zero_t ); void ?{}( T &, one_t ); int ?<?( T, T ); } )
     360T step( T edge, T x ) { return x < edge ? (T){0} : (T){1}; }
     361
     362forall( otype T | { void ?{}( T &, int ); T clamp( T, T, T ); T ?-?( T, T ); T ?*?( T, T ); T ?/?( T, T ); } )
     363T smoothstep( T edge0, T edge1, T x ) { T t = clamp( (x - edge0) / (edge1 - edge0), (T){0}, (T){1} ); return t * t * ((T){3} - (T){2} * t); }
    425364
    426365// Local Variables: //
  • libcfa/src/rational.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed Apr  6 17:54:28 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb  8 17:56:36 2020
    13 // Update Count     : 187
     12// Last Modified On : Fri Jul 12 18:12:08 2019
     13// Update Count     : 184
    1414//
    1515
     
    5656        } // rational
    5757
    58         void ?{}( Rational(RationalImpl) & r, zero_t ) {
    59                 r{ (RationalImpl){0}, (RationalImpl){1} };
    60         } // rational
    61 
    62         void ?{}( Rational(RationalImpl) & r, one_t ) {
    63                 r{ (RationalImpl){1}, (RationalImpl){1} };
    64         } // rational
    6558
    6659        // getter for numerator/denominator
  • libcfa/src/startup.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Jul 24 16:21:57 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 13:03:18 2020
    13 // Update Count     : 30
     12// Last Modified On : Fri Dec 13 13:16:45 2019
     13// Update Count     : 29
    1414//
    1515
    16 #include <time.h>                // tzset
    17 #include <locale.h>        // setlocale
     16#include <time.h>                                                                               // tzset
    1817#include "startup.hfa"
    1918
     
    2221    void __cfaabi_appready_startup( void ) {
    2322                tzset();                                                                                // initialize time global variables
    24                 setlocale(LC_NUMERIC, "");
    2523                #ifdef __CFA_DEBUG__
    2624                extern void heapAppStart();
     
    4341struct __spinlock_t;
    4442extern "C" {
    45         void __cfaabi_dbg_record_lock(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) {}
     43        void __cfaabi_dbg_record(struct __spinlock_t & this, const char * prev_name) __attribute__(( weak )) {}
    4644}
    4745
  • libcfa/src/stdhdr/assert.h

    reef8dfb rbdfc032  
    1010// Created On       : Mon Jul  4 23:25:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 12:58:49 2020
    13 // Update Count     : 15
     12// Last Modified On : Mon Jul 31 23:09:32 2017
     13// Update Count     : 13
    1414//
    1515
     
    2727        #define assertf( expr, fmt, ... ) ((expr) ? ((void)0) : __assert_fail_f(__VSTRINGIFY__(expr), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ## __VA_ARGS__ ))
    2828
    29         void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) __attribute__((noreturn, format( printf, 5, 6) ));
     29        void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) __attribute__((noreturn, format( printf, 5, 6) ));
    3030#endif
    3131
     
    3333        #define verify(x) assert(x)
    3434        #define verifyf(x, ...) assertf(x, __VA_ARGS__)
    35         #define verifyfail(...)
    3635        #define __CFA_WITH_VERIFY__
    3736#else
    3837        #define verify(x)
    3938        #define verifyf(x, ...)
    40         #define verifyfail(...)
    4139#endif
    4240
  • libcfa/src/stdhdr/bfdlink.h

    reef8dfb rbdfc032  
    1010// Created On       : Tue Jul 18 07:26:04 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:05:08 2020
    13 // Update Count     : 6
     12// Last Modified On : Sat Feb  1 07:15:29 2020
     13// Update Count     : 5
    1414//
    1515
    1616// include file uses the CFA keyword "with".
    1717#if ! defined( with )                                                                   // nesting ?
    18 #define with ``with                                                                             // make keyword an identifier
     18#define with ``with``                                                                   // make keyword an identifier
    1919#define __CFA_BFDLINK_H__
    2020#endif
  • libcfa/src/stdhdr/hwloc.h

    reef8dfb rbdfc032  
    1010// Created On       : Tue Jul 18 07:45:00 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:05:18 2020
    13 // Update Count     : 6
     12// Last Modified On : Sat Feb  1 07:15:39 2020
     13// Update Count     : 5
    1414//
    1515
    1616// include file uses the CFA keyword "thread".
    1717#if ! defined( thread )                                                                 // nesting ?
    18 #define thread ``thread                                                                 // make keyword an identifier
     18#define thread ``thread``                                                               // make keyword an identifier
    1919#define __CFA_HWLOC_H__
    2020#endif
  • libcfa/src/stdhdr/krb5.h

    reef8dfb rbdfc032  
    1010// Created On       : Tue Jul 18 07:55:44 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:05:35 2020
    13 // Update Count     : 6
     12// Last Modified On : Sat Feb  1 07:15:47 2020
     13// Update Count     : 5
    1414//
    1515
    1616// include file uses the CFA keyword "enable".
    1717#if ! defined( enable )                                                                 // nesting ?
    18 #define enable ``enable                                                                 // make keyword an identifier
     18#define enable ``enable``                                                               // make keyword an identifier
    1919#define __CFA_KRB5_H__
    2020#endif
  • libcfa/src/stdhdr/malloc.h

    reef8dfb rbdfc032  
    1010// Created On       : Thu Jul 20 15:58:16 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May 27 14:13:14 2020
    13 // Update Count     : 18
     12// Last Modified On : Sat Aug 11 09:06:31 2018
     13// Update Count     : 10
    1414//
     15
     16
     17size_t default_mmap_start();                                                    // CFA extras
     18size_t default_heap_expansion();
     19
     20bool traceHeap();
     21bool traceHeapOn();
     22bool traceHeapOff();
     23
     24bool traceHeapTerm();
     25bool traceHeapTermOn();
     26bool traceHeapTermOff();
     27
     28bool checkFree();
     29bool checkFreeOn();
     30bool checkFreeOff();
     31
     32extern "C" {
     33size_t malloc_alignment( void * );
     34bool malloc_zero_fill( void * );
     35int malloc_stats_fd( int fd );
     36void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize );
     37} // extern "C"
    1538
    1639extern "C" {
    1740#include_next <malloc.h>                                                                // has internal check for multiple expansion
    1841} // extern "C"
    19 
    20 #include <heap.hfa>
    2142
    2243// Local Variables: //
  • libcfa/src/stdhdr/math.h

    reef8dfb rbdfc032  
    1010// Created On       : Mon Jul  4 23:25:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:05:27 2020
    13 // Update Count     : 15
     12// Last Modified On : Sat Feb  1 07:15:58 2020
     13// Update Count     : 14
    1414//
    1515
    1616extern "C" {
    1717#if ! defined( exception )                                                              // nesting ?
    18 #define exception ``exception                                                   // make keyword an identifier
     18#define exception ``exception``                                                 // make keyword an identifier
    1919#define __CFA_MATH_H__
    2020#endif
  • libcfa/src/stdlib.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Thu Jan 28 17:10:29 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Nov 12 07:46:09 2020
    13 // Update Count     : 503
     12// Last Modified On : Wed Nov 20 17:22:47 2019
     13// Update Count     : 485
    1414//
    1515
     
    2020#define _XOPEN_SOURCE 600                                                               // posix_memalign, *rand48
    2121#include <string.h>                                                                             // memcpy, memset
     22#include <malloc.h>                                                                             // malloc_usable_size
    2223//#include <math.h>                                                                             // fabsf, fabs, fabsl
    2324#include <complex.h>                                                                    // _Complex_I
     
    2627//---------------------------------------
    2728
    28 // Cforall allocation/deallocation and constructor/destructor, array types
    29 
    30 forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } )
    31 T * anew( size_t dim, TT p ) {
     29forall( dtype T | sized(T) ) {
     30        T * alloc_set( T ptr[], size_t dim, char fill ) {       // realloc array with fill
     31                size_t olen = malloc_usable_size( ptr );                // current allocation
     32                void * nptr = (void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc
     33                size_t nlen = malloc_usable_size( nptr );               // new allocation
     34                if ( nlen > olen ) {                                                    // larger ?
     35                        memset( (char *)nptr + olen, (int)fill, nlen - olen ); // initialize added storage
     36                } // if
     37                return (T *)nptr;
     38        } // alloc_set
     39
     40        T * alloc_align_set( T ptr[], size_t align, char fill ) { // aligned realloc with fill
     41                size_t olen = malloc_usable_size( ptr );                // current allocation
     42                void * nptr = (void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc
     43                // char * nptr = alloc_align( ptr, align );
     44                size_t nlen = malloc_usable_size( nptr );               // new allocation
     45                if ( nlen > olen ) {                                                    // larger ?
     46                        memset( (char *)nptr + olen, (int)fill, nlen - olen ); // initialize added storage
     47                } // if
     48                return (T *)nptr;
     49        } // alloc_align_set
     50} // distribution
     51
     52// allocation/deallocation and constructor/destructor, non-array types
     53forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } )
     54T * new( Params p ) {
     55        return &(*malloc()){ p };                                                       // run constructor
     56} // new
     57
     58forall( dtype T | sized(T) | { void ^?{}( T & ); } )
     59void delete( T * ptr ) {
     60        if ( ptr ) {                                                                            // ignore null
     61                ^(*ptr){};                                                                              // run destructor
     62                free( ptr );
     63        } // if
     64} // delete
     65
     66forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } )
     67void delete( T * ptr, Params rest ) {
     68        if ( ptr ) {                                                                            // ignore null
     69                ^(*ptr){};                                                                              // run destructor
     70                free( ptr );
     71        } // if
     72        delete( rest );
     73} // delete
     74
     75
     76// allocation/deallocation and constructor/destructor, array types
     77forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } )
     78T * anew( size_t dim, Params p ) {
    3279        T * arr = alloc( dim );
    3380        for ( unsigned int i = 0; i < dim; i += 1 ) {
     
    3885
    3986forall( dtype T | sized(T) | { void ^?{}( T & ); } )
    40 void adelete( T arr[] ) {
     87void adelete( size_t dim, T arr[] ) {
    4188        if ( arr ) {                                                                            // ignore null
    42                 size_t dim = malloc_size( arr ) / sizeof( T );
    4389                for ( int i = dim - 1; i >= 0; i -= 1 ) {               // reverse allocation order, must be unsigned
    4490                        ^(arr[i]){};                                                            // run destructor
     
    4894} // adelete
    4995
    50 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype TT | { void adelete( TT ); } )
    51 void adelete( T arr[], TT rest ) {
     96forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } )
     97void adelete( size_t dim, T arr[], Params rest ) {
    5298        if ( arr ) {                                                                            // ignore null
    53                 size_t dim = malloc_size( arr ) / sizeof( T );
    5499                for ( int i = dim - 1; i >= 0; i -= 1 ) {               // reverse allocation order, must be unsigned
    55100                        ^(arr[i]){};                                                            // run destructor
     
    62107//---------------------------------------
    63108
    64 float _Complex strto( const char sptr[], char ** eptr ) {
     109float _Complex strto( const char * sptr, char ** eptr ) {
    65110        float re, im;
    66111        char * eeptr;
     
    73118} // strto
    74119
    75 double _Complex strto( const char sptr[], char ** eptr ) {
     120double _Complex strto( const char * sptr, char ** eptr ) {
    76121        double re, im;
    77122        char * eeptr;
     
    84129} // strto
    85130
    86 long double _Complex strto( const char sptr[], char ** eptr ) {
     131long double _Complex strto( const char * sptr, char ** eptr ) {
    87132        long double re, im;
    88133        char * eeptr;
     
    210255extern "C" {                                                                                    // override C version
    211256        void srandom( unsigned int seed ) { srand48( (long int)seed ); }
    212         long int random( void ) { return mrand48(); }           // GENERATES POSITIVE AND NEGATIVE VALUES
     257        long int random( void ) { return mrand48(); }
    213258} // extern "C"
    214259
  • libcfa/src/stdlib.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Dec 12 13:52:34 2020
    13 // Update Count     : 536
     12// Last Modified On : Fri Nov 29 23:08:02 2019
     13// Update Count     : 400
    1414//
    1515
    1616#pragma once
    1717
    18 #include "bits/defs.hfa"                                                                // OPTIONAL_THREAD
    19 #include "bits/align.hfa"                                                               // libAlign
     18#include "bits/defs.hfa"
     19#include "bits/align.hfa"
    2020
    2121#include <stdlib.h>                                                                             // *alloc, strto*, ato*
    22 #include <heap.hfa>
    23 
    24 // Reduce includes by explicitly defining these routines.
     22
    2523extern "C" {
    26         void * memalign( size_t alignment, size_t size );       // malloc.h
    27         void * pvalloc( size_t size );                                          // malloc.h
     24        void * memalign( size_t align, size_t size );           // malloc.h
    2825        void * memset( void * dest, int fill, size_t size ); // string.h
    2926        void * memcpy( void * dest, const void * src, size_t size ); // string.h
     27    void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ); // CFA heap
    3028} // extern "C"
     29
     30void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap
    3131
    3232//---------------------------------------
     
    3939//---------------------------------------
    4040
    41 #include "common.hfa"
    42 
    43 //---------------------------------------
    44 
    45 // Macro because of returns
    46 #define $ARRAY_ALLOC( allocation, alignment, dim ) \
    47         if ( _Alignof(T) <= libAlign() ) return (T *)(void *)allocation( dim, (size_t)sizeof(T) ); /* C allocation */ \
    48         else return (T *)alignment( _Alignof(T), dim, sizeof(T) )
    49 
    50 static inline forall( dtype T | sized(T) ) {
    51         // CFA safe equivalents, i.e., implicit size specification
     41static inline forall( dtype T | sized(T) ) {
     42        // C dynamic allocation
    5243
    5344        T * malloc( void ) {
    54                 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)malloc( (size_t)sizeof(T) ); // C allocation
     45                if ( _Alignof(T) <= libAlign() ) return (T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc
    5546                else return (T *)memalign( _Alignof(T), sizeof(T) );
    5647        } // malloc
    5748
    58         T * aalloc( size_t dim ) {
    59                 $ARRAY_ALLOC( aalloc, amemalign, dim );
    60         } // aalloc
    61 
    6249        T * calloc( size_t dim ) {
    63                 $ARRAY_ALLOC( calloc, cmemalign, dim );
     50                if ( _Alignof(T) <= libAlign() )return (T *)(void *)calloc( dim, sizeof(T) ); // C calloc
     51                else return (T *)cmemalign( _Alignof(T), dim, sizeof(T) );
    6452        } // calloc
    6553
    66         T * resize( T * ptr, size_t size ) {                            // CFA resize, eliminate return-type cast
    67                 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)resize( (void *)ptr, size ); // CFA resize
    68                 else return (T *)(void *)resize( (void *)ptr, _Alignof(T), size ); // CFA resize
    69         } // resize
    70 
    7154        T * realloc( T * ptr, size_t size ) {                           // CFA realloc, eliminate return-type cast
    72                 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)realloc( (void *)ptr, size ); // C realloc
    73                 else return (T *)(void *)realloc( (void *)ptr, _Alignof(T), size ); // CFA realloc
     55                return (T *)(void *)realloc( (void *)ptr, size ); // C realloc
    7456        } // realloc
    7557
     
    7860        } // memalign
    7961
    80         T * amemalign( size_t align, size_t dim ) {
    81                 return (T *)amemalign( align, dim, sizeof(T) ); // CFA amemalign
    82         } // amemalign
    83 
    8462        T * cmemalign( size_t align, size_t dim  ) {
    8563                return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign
     
    9472        } // posix_memalign
    9573
    96         T * valloc( void ) {
    97                 return (T *)valloc( sizeof(T) );                                // C valloc
    98         } // valloc
    99 
    100         T * pvalloc( void ) {
    101                 return (T *)pvalloc( sizeof(T) );                               // C pvalloc
    102         } // pvalloc
    103 } // distribution
    104 
    105 /*
    106         FIX ME : fix alloc interface after Ticker Number 214 is resolved, define and add union to S_fill. Then, modify postfix-fill functions to support T * with nmemb, char, and T object of any size. Finally, change alloc_internal.
    107         Or, just follow the instructions below for that.
    108 
    109         1. Replace the current forall-block that contains defintions of S_fill and S_realloc with following:
    110                 forall( dtype T | sized(T) ) {
    111                         union  U_fill           { char c; T * a; T t; };
    112                         struct S_fill           { char tag; U_fill(T) fill; };
    113                         struct S_realloc        { inline T *; };
    114                 }
    115 
    116         2. Replace all current postfix-fill functions with following for updated S_fill:
    117                 S_fill(T) ?`fill( char a )                                      { S_fill(T) ret = {'c'}; ret.fill.c = a; return ret; }
    118                 S_fill(T) ?`fill( T    a )                                      { S_fill(T) ret = {'t'}; memcpy(&ret.fill.t, &a, sizeof(T)); return ret; }
    119                 S_fill(T) ?`fill( T    a[], size_t nmemb )      { S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; }
    120 
    121         3. Replace the $alloc_internal function which is outside ttype forall-block with following function:
    122                 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) {
    123                         T * ptr = NULL;
    124                         size_t size = sizeof(T);
    125                         size_t copy_end = 0;
    126 
    127                         if(Resize) {
    128                                 ptr = (T*) (void *) resize( (int *)Resize, Align, Dim * size );
    129                         } else if (Realloc) {
    130                                 if (Fill.tag != '0') copy_end = min(malloc_size( Realloc ), Dim * size);
    131                                 ptr = (T*) (void *) realloc( (int *)Realloc, Align, Dim * size );
    132                         } else {
    133                                 ptr = (T*) (void *) memalign( Align, Dim * size );
    134                         }
    135 
    136                         if(Fill.tag == 'c') {
    137                                 memset( (char *)ptr + copy_end, (int)Fill.fill.c, Dim * size - copy_end );
    138                         } else if(Fill.tag == 't') {
    139                                 for ( int i = copy_end; i <= Dim * size - size ; i += size ) {
    140                                         memcpy( (char *)ptr + i, &Fill.fill.t, size );
    141                                 }
    142                         } else if(Fill.tag == 'a') {
    143                                 memcpy( (char *)ptr + copy_end, Fill.fill.a, min(Dim * size - copy_end, size * Fill.nmemb) );
    144                         }
    145 
    146                         return ptr;
    147                 } // $alloc_internal
    148 */
    149 
    150 typedef struct S_align                  { inline size_t;  } T_align;
    151 typedef struct S_resize                 { inline void *;  }     T_resize;
    152 
    153 forall( dtype T ) {
    154         struct S_fill           { char tag; char c; size_t size; T * at; char t[50]; };
    155         struct S_realloc        { inline T *; };
    156 }
    157 
    158 static inline T_align   ?`align   ( size_t a )  { return (T_align){a}; }
    159 static inline T_resize  ?`resize  ( void * a )  { return (T_resize){a}; }
    160 
    161 static inline forall( dtype T | sized(T) ) {
    162         S_fill(T) ?`fill ( T t ) {
    163                 S_fill(T) ret = { 't' };
    164                 size_t size = sizeof(T);
    165                 if(size > sizeof(ret.t)) { printf("ERROR: const object of size greater than 50 bytes given for dynamic memory fill\n"); exit(1); }
    166                 memcpy( &ret.t, &t, size );
    167                 return ret;
    168         }
    169         S_fill(T)               ?`fill ( char c )                               { return (S_fill(T)){ 'c', c }; }
    170         S_fill(T)               ?`fill ( T * a )                                { return (S_fill(T)){ 'T', '0', 0, a }; }
    171         S_fill(T)               ?`fill ( T a[], size_t nmemb )  { return (S_fill(T)){ 'a', '0', nmemb * sizeof(T), a }; }
    172 
    173         S_realloc(T)    ?`realloc ( T * a )                             { return (S_realloc(T)){a}; }
    174 
    175         T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) {
    176                 T * ptr = NULL;
    177                 size_t size = sizeof(T);
    178                 size_t copy_end = 0;
    179 
    180                 if ( Resize ) {
    181                         ptr = (T*) (void *) resize( (void *)Resize, Align, Dim * size );
    182                 } else if ( Realloc ) {
    183                         if (Fill.tag != '0') copy_end = min(malloc_size( Realloc ), Dim * size);
    184                         ptr = (T*) (void *) realloc( (void *)Realloc, Align, Dim * size );
    185                 } else {
    186                         ptr = (T*) (void *) memalign( Align, Dim * size );
    187                 }
    188 
    189                 if(Fill.tag == 'c') {
    190                         memset( (char *)ptr + copy_end, (int)Fill.c, Dim * size - copy_end );
    191                 } else if(Fill.tag == 't') {
    192                         for ( int i = copy_end; i < Dim * size; i += size ) {
    193                                 memcpy( (char *)ptr + i, &Fill.t, size );
    194                         }
    195                 } else if(Fill.tag == 'a') {
    196                         memcpy( (char *)ptr + copy_end, Fill.at, min(Dim * size - copy_end, Fill.size) );
    197                 } else if(Fill.tag == 'T') {
    198                         for ( int i = copy_end; i < Dim * size; i += size ) {
    199                                 memcpy( (char *)ptr + i, Fill.at, size );
    200                         }
    201                 }
    202 
    203                 return ptr;
    204         } // $alloc_internal
    205 
    206         forall( ttype TT | { T * $alloc_internal( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {
    207 
    208                 T * $alloc_internal( void *       , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) {
    209                 return $alloc_internal( Resize, (T*)0p, Align, Dim, Fill, rest);
    210                 }
    211 
    212                 T * $alloc_internal( void * Resize, T *        , size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest) {
    213                 return $alloc_internal( (void*)0p, Realloc, Align, Dim, Fill, rest);
    214                 }
    215 
    216                 T * $alloc_internal( void * Resize, T * Realloc, size_t      , size_t Dim, S_fill(T) Fill, T_align Align, TT rest) {
    217                 return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest);
    218                 }
    219 
    220                 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T)     , S_fill(T) Fill, TT rest) {
    221                 return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest);
    222                 }
    223 
    224             T * alloc( TT all ) {
    225                 return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all);
    226             }
    227 
    228             T * alloc( size_t dim, TT all ) {
    229                 return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all);
    230             }
    231 
    232         } // distribution TT
    233 } // distribution T
    234 
    235 static inline forall( dtype T | sized(T) ) {
    236         // CFA safe initialization/copy, i.e., implicit size specification, non-array types
     74        // Cforall dynamic allocation
     75
     76        T * alloc( void ) {
     77                return malloc();
     78        } // alloc
     79
     80        T * alloc( size_t dim ) {
     81                if ( _Alignof(T) <= libAlign() ) return (T *)(void *)malloc( dim * (size_t)sizeof(T) );
     82                else return (T *)memalign( _Alignof(T), dim * sizeof(T) );
     83        } // alloc
     84
     85        T * alloc( T ptr[], size_t dim ) {                                      // realloc
     86                return (T *)(void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc
     87        } // alloc
     88
     89        T * alloc_set( char fill ) {
     90                return (T *)memset( (T *)alloc(), (int)fill, sizeof(T) ); // initialize with fill value
     91        } // alloc
     92
     93        T * alloc_set( T fill ) {
     94                return (T *)memcpy( (T *)alloc(), &fill, sizeof(T) ); // initialize with fill value
     95        } // alloc
     96
     97        T * alloc_set( size_t dim, char fill ) {
     98                return (T *)memset( (T *)alloc( dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value
     99        } // alloc
     100
     101        T * alloc_set( size_t dim, T fill ) {
     102                T * r = (T *)alloc( dim );
     103                for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value
     104                return r;
     105        } // alloc
     106
     107        T * alloc_set( size_t dim, const T fill[] ) {
     108                return (T *)memcpy( (T *)alloc( dim ), fill, dim * sizeof(T) ); // initialize with fill value
     109        } // alloc
     110} // distribution
     111
     112forall( dtype T | sized(T) ) {
     113        T * alloc_set( T ptr[], size_t dim, char fill );        // realloc array with fill
     114} // distribution
     115
     116static inline forall( dtype T | sized(T) ) {
     117        T * alloc_align( size_t align ) {
     118                return (T *)memalign( align, sizeof(T) );
     119        } // alloc_align
     120
     121        T * alloc_align( size_t align, size_t dim ) {
     122                return (T *)memalign( align, dim * sizeof(T) );
     123        } // alloc_align
     124
     125        T * alloc_align( T ptr[], size_t align ) {                      // aligned realloc array
     126                return (T *)(void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc
     127        } // alloc_align
     128
     129        T * alloc_align( T ptr[], size_t align, size_t dim ) { // aligned realloc array
     130                return (T *)(void *)realloc( (void *)ptr, align, dim * sizeof(T) ); // CFA realloc
     131        } // alloc_align
     132
     133        T * alloc_align_set( size_t align, char fill ) {
     134                return (T *)memset( (T *)alloc_align( align ), (int)fill, sizeof(T) ); // initialize with fill value
     135        } // alloc_align
     136
     137        T * alloc_align_set( size_t align, T fill ) {
     138                return (T *)memcpy( (T *)alloc_align( align ), &fill, sizeof(T) ); // initialize with fill value
     139        } // alloc_align
     140
     141        T * alloc_align_set( size_t align, size_t dim, char fill ) {
     142                return (T *)memset( (T *)alloc_align( align, dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value
     143        } // alloc_align
     144
     145        T * alloc_align_set( size_t align, size_t dim, T fill ) {
     146                T * r = (T *)alloc_align( align, dim );
     147                for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value
     148                return r;
     149        } // alloc_align
     150
     151        T * alloc_align_set( size_t align, size_t dim, const T fill[] ) {
     152                return (T *)memcpy( (T *)alloc_align( align, dim ), fill, dim * sizeof(T) );
     153        } // alloc_align
     154} // distribution
     155
     156forall( dtype T | sized(T) ) {
     157        T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); // aligned realloc array with fill
     158} // distribution
     159
     160static inline forall( dtype T | sized(T) ) {
     161        // data, non-array types
    237162        T * memset( T * dest, char fill ) {
    238163                return (T *)memset( dest, fill, sizeof(T) );
     
    242167                return (T *)memcpy( dest, src, sizeof(T) );
    243168        } // memcpy
    244 
    245         // CFA safe initialization/copy, i.e., implicit size specification, array types
     169} // distribution
     170
     171static inline forall( dtype T | sized(T) ) {
     172        // data, array types
    246173        T * amemset( T dest[], char fill, size_t dim ) {
    247174                return (T *)(void *)memset( dest, fill, dim * sizeof(T) ); // C memset
     
    253180} // distribution
    254181
    255 // CFA deallocation for multiple objects
    256 static inline forall( dtype T )                                                 // FIX ME, problems with 0p in list
    257 void free( T * ptr ) {
    258         free( (void *)ptr );                                                            // C free
    259 } // free
    260 static inline forall( dtype T, ttype TT | { void free( TT ); } )
    261 void free( T * ptr, TT rest ) {
    262         free( ptr );
    263         free( rest );
    264 } // free
    265 
    266 // CFA allocation/deallocation and constructor/destructor, non-array types
    267 static inline forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } )
    268 T * new( TT p ) {
    269         return &(*(T *)malloc()){ p };                                                  // run constructor
    270 } // new
    271 
    272 static inline forall( dtype T | { void ^?{}( T & ); } )
    273 void delete( T * ptr ) {
    274         // special case for 0-sized object => always call destructor
    275         if ( ptr || sizeof(ptr) == 0 ) {                                        // ignore null but not 0-sized objects
    276                 ^(*ptr){};                                                                              // run destructor
    277         } // if
    278         free( ptr );                                                                            // always call free
    279 } // delete
    280 static inline forall( dtype T, ttype TT | { void ^?{}( T & ); void delete( TT ); } )
    281 void delete( T * ptr, TT rest ) {
    282         delete( ptr );
    283         delete( rest );
    284 } // delete
    285 
    286 // CFA allocation/deallocation and constructor/destructor, array types
    287 forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } ) T * anew( size_t dim, TT p );
    288 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] );
    289 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype TT | { void adelete( TT ); } ) void adelete( T arr[], TT rest );
     182// allocation/deallocation and constructor/destructor, non-array types
     183forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p );
     184forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void delete( T * ptr );
     185forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } ) void delete( T * ptr, Params rest );
     186
     187// allocation/deallocation and constructor/destructor, array types
     188forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p );
     189forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );
     190forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } ) void adelete( size_t dim, T arr[], Params rest );
    290191
    291192//---------------------------------------
    292193
    293194static inline {
    294         int strto( const char sptr[], char ** eptr, int base ) { return (int)strtol( sptr, eptr, base ); }
    295         unsigned int strto( const char sptr[], char ** eptr, int base ) { return (unsigned int)strtoul( sptr, eptr, base ); }
    296         long int strto( const char sptr[], char ** eptr, int base ) { return strtol( sptr, eptr, base ); }
    297         unsigned long int strto( const char sptr[], char ** eptr, int base ) { return strtoul( sptr, eptr, base ); }
    298         long long int strto( const char sptr[], char ** eptr, int base ) { return strtoll( sptr, eptr, base ); }
    299         unsigned long long int strto( const char sptr[], char ** eptr, int base ) { return strtoull( sptr, eptr, base ); }
    300 
    301         float strto( const char sptr[], char ** eptr ) { return strtof( sptr, eptr ); }
    302         double strto( const char sptr[], char ** eptr ) { return strtod( sptr, eptr ); }
    303         long double strto( const char sptr[], char ** eptr ) { return strtold( sptr, eptr ); }
    304 } // distribution
    305 
    306 float _Complex strto( const char sptr[], char ** eptr );
    307 double _Complex strto( const char sptr[], char ** eptr );
    308 long double _Complex strto( const char sptr[], char ** eptr );
     195        int strto( const char * sptr, char ** eptr, int base ) { return (int)strtol( sptr, eptr, base ); }
     196        unsigned int strto( const char * sptr, char ** eptr, int base ) { return (unsigned int)strtoul( sptr, eptr, base ); }
     197        long int strto( const char * sptr, char ** eptr, int base ) { return strtol( sptr, eptr, base ); }
     198        unsigned long int strto( const char * sptr, char ** eptr, int base ) { return strtoul( sptr, eptr, base ); }
     199        long long int strto( const char * sptr, char ** eptr, int base ) { return strtoll( sptr, eptr, base ); }
     200        unsigned long long int strto( const char * sptr, char ** eptr, int base ) { return strtoull( sptr, eptr, base ); }
     201
     202        float strto( const char * sptr, char ** eptr ) { return strtof( sptr, eptr ); }
     203        double strto( const char * sptr, char ** eptr ) { return strtod( sptr, eptr ); }
     204        long double strto( const char * sptr, char ** eptr ) { return strtold( sptr, eptr ); }
     205} // distribution
     206
     207float _Complex strto( const char * sptr, char ** eptr );
     208double _Complex strto( const char * sptr, char ** eptr );
     209long double _Complex strto( const char * sptr, char ** eptr );
    309210
    310211static inline {
    311         int ato( const char sptr[] ) { return (int)strtol( sptr, 0p, 10 ); }
    312         unsigned int ato( const char sptr[] ) { return (unsigned int)strtoul( sptr, 0p, 10 ); }
    313         long int ato( const char sptr[] ) { return strtol( sptr, 0p, 10 ); }
    314         unsigned long int ato( const char sptr[] ) { return strtoul( sptr, 0p, 10 ); }
    315         long long int ato( const char sptr[] ) { return strtoll( sptr, 0p, 10 ); }
    316         unsigned long long int ato( const char sptr[] ) { return strtoull( sptr, 0p, 10 ); }
    317 
    318         float ato( const char sptr[] ) { return strtof( sptr, 0p ); }
    319         double ato( const char sptr[] ) { return strtod( sptr, 0p ); }
    320         long double ato( const char sptr[] ) { return strtold( sptr, 0p ); }
    321 
    322         float _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); }
    323         double _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); }
    324         long double _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); }
     212        int ato( const char * sptr ) { return (int)strtol( sptr, 0p, 10 ); }
     213        unsigned int ato( const char * sptr ) { return (unsigned int)strtoul( sptr, 0p, 10 ); }
     214        long int ato( const char * sptr ) { return strtol( sptr, 0p, 10 ); }
     215        unsigned long int ato( const char * sptr ) { return strtoul( sptr, 0p, 10 ); }
     216        long long int ato( const char * sptr ) { return strtoll( sptr, 0p, 10 ); }
     217        unsigned long long int ato( const char * sptr ) { return strtoull( sptr, 0p, 10 ); }
     218
     219        float ato( const char * sptr ) { return strtof( sptr, 0p ); }
     220        double ato( const char * sptr ) { return strtod( sptr, 0p ); }
     221        long double ato( const char * sptr ) { return strtold( sptr, 0p ); }
     222
     223        float _Complex ato( const char * sptr ) { return strto( sptr, 0p ); }
     224        double _Complex ato( const char * sptr ) { return strto( sptr, 0p ); }
     225        long double _Complex ato( const char * sptr ) { return strto( sptr, 0p ); }
    325226} // distribution
    326227
     
    353254extern "C" {                                                                                    // override C version
    354255        void srandom( unsigned int seed );
    355         long int random( void );                                                        // GENERATES POSITIVE AND NEGATIVE VALUES
    356         // For positive values, use unsigned int, e.g., unsigned int r = random() % 100U;
     256        long int random( void );
    357257} // extern "C"
    358258
     
    361261        long int random( long int u ) { if ( u < 0 ) return random( u, 0 ); else return random( 0, u ); } // [0,u)
    362262        unsigned long int random( void ) { return lrand48(); }
     263        unsigned long int random( unsigned long int l, unsigned long int u ) { if ( u < l ) [u, l] = [l, u]; return lrand48() % (u - l) + l; } // [l,u)
    363264        unsigned long int random( unsigned long int u ) { return lrand48() % u; } // [0,u)
    364         unsigned long int random( unsigned long int l, unsigned long int u ) { if ( u < l ) [u, l] = [l, u]; return lrand48() % (u - l) + l; } // [l,u)
    365265
    366266        char random( void ) { return (unsigned long int)random(); }
     
    383283//---------------------------------------
    384284
    385 extern bool threading_enabled( void ) OPTIONAL_THREAD;
     285#include "common.hfa"
     286
     287//---------------------------------------
     288
     289extern bool threading_enabled(void) OPTIONAL_THREAD;
    386290
    387291// Local Variables: //
  • libcfa/src/time.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Mar 27 13:33:14 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 08:24:18 2020
    13 // Update Count     : 70
     12// Last Modified On : Sun Jan  5 17:27:40 2020
     13// Update Count     : 69
    1414//
    1515
     
    129129} // dd_mm_yy
    130130
    131 size_t strftime( char buf[], size_t size, const char fmt[], Time time ) with( time ) {
     131size_t strftime( char * buf, size_t size, const char * fmt, Time time ) with( time ) {
    132132        time_t s = tn / TIMEGRAN;
    133133        tm tm;
  • libcfa/src/time.hfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed Mar 14 23:18:57 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 17 16:13:00 2020
    13 // Update Count     : 663
     12// Last Modified On : Mon Jan  6 12:50:16 2020
     13// Update Count     : 653
    1414//
    1515
     
    2020
    2121#include <time.h>                                                                               // timespec
     22extern "C" {
    2223#include <sys/time.h>                                                                   // timeval
     24}
    2325#include <time_t.hfa>                                                                   // Duration/Time types
    2426
     
    8991        int64_t ?`w( Duration dur ) { return dur.tn / (7LL * 24LL * 60LL * 60LL * TIMEGRAN); }
    9092
    91         double ?`dns( Duration dur ) { return dur.tn; }
    92         double ?`dus( Duration dur ) { return dur.tn / ((double)TIMEGRAN / 1_000_000.); }
    93         double ?`dms( Duration dur ) { return dur.tn / ((double)TIMEGRAN / 1_000.); }
    94         double ?`ds( Duration dur ) { return dur.tn / (double)TIMEGRAN; }
    95         double ?`dm( Duration dur ) { return dur.tn / (60. * TIMEGRAN); }
    96         double ?`dh( Duration dur ) { return dur.tn / (60. * 60. * (double)TIMEGRAN); }
    97         double ?`dd( Duration dur ) { return dur.tn / (24. * 60. * 60. * (double)TIMEGRAN); }
    98         double ?`dw( Duration dur ) { return dur.tn / (7. * 24. * 60. * 60. * (double)TIMEGRAN); }
    99 
    10093        Duration max( Duration lhs, Duration rhs ) { return  (lhs.tn < rhs.tn) ? rhs : lhs;}
    10194        Duration min( Duration lhs, Duration rhs ) { return !(rhs.tn < lhs.tn) ? lhs : rhs;}
     
    198191} // dmy
    199192
    200 size_t strftime( char buf[], size_t size, const char fmt[], Time time );
     193size_t strftime( char * buf, size_t size, const char * fmt, Time time );
    201194
    202195//------------------------- timeval (cont) -------------------------
  • libcfa/src/vec/vec.hfa

    reef8dfb rbdfc032  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
    3 //
    4 // The contents of this file are covered under the licence agreement in the
    5 // file "LICENCE" distributed with Cforall.
    6 //
    7 // io/types.hfa --
    8 //
    9 // Author           : Dimitry Kobets
    10 // Created On       :
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
    14 //
    15 
    161#pragma once
    172
  • libcfa/src/vec/vec2.hfa

    reef8dfb rbdfc032  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
    3 //
    4 // The contents of this file are covered under the licence agreement in the
    5 // file "LICENCE" distributed with Cforall.
    6 //
    7 // io/types.hfa --
    8 //
    9 // Author           : Dimitry Kobets
    10 // Created On       :
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
    14 //
    15 
    161#pragma once
    172
  • libcfa/src/vec/vec3.hfa

    reef8dfb rbdfc032  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
    3 //
    4 // The contents of this file are covered under the licence agreement in the
    5 // file "LICENCE" distributed with Cforall.
    6 //
    7 // io/types.hfa --
    8 //
    9 // Author           : Dimitry Kobets
    10 // Created On       :
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
    14 //
    15 
    161#pragma once
    172
  • libcfa/src/vec/vec4.hfa

    reef8dfb rbdfc032  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
    3 //
    4 // The contents of this file are covered under the licence agreement in the
    5 // file "LICENCE" distributed with Cforall.
    6 //
    7 // io/types.hfa --
    8 //
    9 // Author           : Dimitry Kobets
    10 // Created On       :
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
    14 //
    15 
    161#pragma once
    172
  • longrun_tests/Makefile.am

    reef8dfb rbdfc032  
    1818ACLOCAL_AMFLAGS  = -I automake
    1919
    20 include $(top_srcdir)/tools/build/cfa.make
     20include $(top_srcdir)/src/cfa.make
    2121
    2222repeats=10
     
    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/Attribute.hpp

    reef8dfb rbdfc032  
    5151        template<typename node_t>
    5252        friend node_t * mutate(const node_t * node);
    53         template<typename node_t>
    54     friend node_t * shallowCopy(const node_t * node);
    5553};
    5654
  • src/AST/CVQualifiers.hpp

    reef8dfb rbdfc032  
    2727                Restrict = 1 << 1,
    2828                Volatile = 1 << 2,
    29                 Mutex    = 1 << 3,
    30                 Atomic   = 1 << 4,
    31                 NumQualifiers = 5
     29                Lvalue   = 1 << 3,
     30                Mutex    = 1 << 4,
     31                Atomic   = 1 << 5,
     32                NumQualifiers = 6
    3233        };
    3334
    3435        /// Mask for equivalence-preserving qualfiers
    35         enum { EquivQualifiers = ~Restrict };
     36        enum { EquivQualifiers = ~(Restrict | Lvalue) };
    3637
    3738        /// Underlying data for qualifiers
     
    4344                                bool is_restrict : 1;
    4445                                bool is_volatile : 1;
     46                                bool is_lvalue   : 1;
    4547                                bool is_mutex    : 1;
    4648                                bool is_atomic   : 1;
  • src/AST/Convert.cpp

    reef8dfb rbdfc032  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 09 15::37::05 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Nov 12 10:07:00 2020
    13 // Update Count     : 34
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Dec 11 21:39:32 2019
     13// Update Count     : 33
    1414//
    1515
     
    2020
    2121#include "AST/Attribute.hpp"
    22 #include "AST/Copy.hpp"
    2322#include "AST/Decl.hpp"
    2423#include "AST/Expr.hpp"
    2524#include "AST/Init.hpp"
    2625#include "AST/Stmt.hpp"
    27 #include "AST/TranslationUnit.hpp"
    2826#include "AST/TypeSubstitution.hpp"
    2927
     
    4846
    4947//================================================================================================
    50 namespace ast {
     48namespace {
    5149
    5250// This is to preserve the FindSpecialDecls hack. It does not (and perhaps should not)
    5351// allow us to use the same stratagy in the new ast.
    54 // xxx - since convert back pass works, this concern seems to be unnecessary.
    55 
    56 // these need to be accessed in new FixInit now
    57 ast::ptr<ast::Type> sizeType = nullptr;
    58 const ast::FunctionDecl * dereferenceOperator = nullptr;
    59 const ast::StructDecl   * dtorStruct = nullptr;
    60 const ast::FunctionDecl * dtorStructDestroy = nullptr;
     52ast::Type * sizeType = nullptr;
     53ast::FunctionDecl * dereferenceOperator = nullptr;
     54ast::StructDecl   * dtorStruct = nullptr;
     55ast::FunctionDecl * dtorStructDestroy = nullptr;
    6156
    6257}
     
    6762        using Cache = std::unordered_map< const ast::Node *, BaseSyntaxNode * >;
    6863        Cache cache;
    69 
    70         // Statements can no longer be shared.
    71         // however, since StmtExprResult is now implemented, need to still maintain
    72         // readonly references.
    73         Cache readonlyCache;
    7464
    7565        template<typename T>
     
    163153        }
    164154
    165         const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final {       
     155        const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final {
     156                auto&& bfwd = get<Expression>().accept1( node->bitfieldWidth );
     157                auto&& type = get<Type>().accept1( node->type );
     158                auto&& init = get<Initializer>().accept1( node->init );
     159                auto&& attr = get<Attribute>().acceptL( node->attributes );
    166160                if ( inCache( node ) ) {
    167161                        return nullptr;
    168162                }
    169                 auto bfwd = get<Expression>().accept1( node->bitfieldWidth );
    170                 auto type = get<Type>().accept1( node->type );
    171                 auto attr = get<Attribute>().acceptL( node->attributes );
    172 
    173163                auto decl = new ObjectDecl(
    174164                        node->name,
     
    176166                        LinkageSpec::Spec( node->linkage.val ),
    177167                        bfwd,
    178                         type->clone(),
    179                         nullptr, // prevent infinite loop
     168                        type,
     169                        init,
    180170                        attr,
    181171                        Type::FuncSpecifiers( node->funcSpec.val )
    182172                );
    183 
    184                 // handles the case where node->init references itself
    185                 // xxx - does it really happen?
    186                 declWithTypePostamble(decl, node);
    187                 auto init = get<Initializer>().accept1( node->init );
    188                 decl->init = init;
    189 
    190                 this->node = decl;
    191                 return nullptr;
     173                return declWithTypePostamble( decl, node );
    192174        }
    193175
    194176        const ast::DeclWithType * visit( const ast::FunctionDecl * node ) override final {
    195177                if ( inCache( node ) ) return nullptr;
    196 
    197                 // function decl contains real variables that the type must use.
    198                 // the structural change means function type in and out of decl
    199                 // must be handled **differently** on convert back to old.
    200                 auto ftype = new FunctionType(
    201                         cv(node->type),
    202                         (bool)node->type->isVarArgs
    203                 );
    204                 ftype->returnVals = get<DeclarationWithType>().acceptL(node->returns);
    205                 ftype->parameters = get<DeclarationWithType>().acceptL(node->params);
    206 
    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                 }
    213 
    214                 visitType(node->type, ftype);
    215 
    216178                auto decl = new FunctionDecl(
    217179                        node->name,
    218180                        Type::StorageClasses( node->storage.val ),
    219181                        LinkageSpec::Spec( node->linkage.val ),
    220                         ftype,
    221                         //get<FunctionType>().accept1( node->type ),
     182                        get<FunctionType>().accept1( node->type ),
    222183                        {},
    223184                        get<Attribute>().acceptL( node->attributes ),
     
    227188                decl->statements = get<CompoundStmt>().accept1( node->stmts );
    228189                decl->withExprs = get<Expression>().acceptL( node->withExprs );
    229                 if ( ast::dereferenceOperator == node ) {
     190                if ( dereferenceOperator == node ) {
    230191                        Validate::dereferenceOperator = decl;
    231192                }
    232                 if ( ast::dtorStructDestroy == node ) {
     193                if ( dtorStructDestroy == node ) {
    233194                        Validate::dtorStructDestroy = decl;
    234195                }
     
    238199        const ast::Decl * namedTypePostamble( NamedTypeDecl * decl, const ast::NamedTypeDecl * node ) {
    239200                // base comes from constructor
     201                decl->parameters = get<TypeDecl>().acceptL( node->params );
    240202                decl->assertions = get<DeclarationWithType>().acceptL( node->assertions );
    241203                declPostamble( decl, node );
     
    288250                );
    289251
    290                 if ( ast::dtorStruct == node ) {
     252                if ( dtorStruct == node ) {
    291253                        Validate::dtorStruct = decl;
    292254                }
     
    341303
    342304        const ast::Stmt * stmtPostamble( Statement * stmt, const ast::Stmt * node ) {
    343                 // force statements in old tree to be unique.
    344                 // cache.emplace( node, stmt );
    345                 readonlyCache.emplace( node, stmt );
     305                cache.emplace( node, stmt );
    346306                stmt->location = node->location;
    347307                stmt->labels = makeLabelL( stmt, node->labels );
     
    360320                if ( inCache( node ) ) return nullptr;
    361321                auto stmt = new ExprStmt( nullptr );
     322                cache.emplace( node, stmt );
    362323                stmt->expr = get<Expression>().accept1( node->expr );
    363324                return stmtPostamble( stmt, node );
     
    532493        }
    533494
    534         const ast::Stmt * visit(const ast::SuspendStmt * node ) override final {
    535                 if ( inCache( node ) ) return nullptr;
    536                 auto stmt = new SuspendStmt();
    537                 stmt->then   = get<CompoundStmt>().accept1( node->then   );
    538                 switch(node->type) {
    539                         case ast::SuspendStmt::None     : stmt->type = SuspendStmt::None     ; break;
    540                         case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break;
    541                         case ast::SuspendStmt::Generator: stmt->type = SuspendStmt::Generator; break;
    542                 }
    543                 return stmtPostamble( stmt, node );
    544         }
    545 
    546495        const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
    547496                if ( inCache( node ) ) return nullptr;
     
    607556
    608557                for (decltype(src->begin()) src_i = src->begin(); src_i != src->end(); src_i++) {
    609                         rslt->add( src_i->first.typeString(),
     558                        rslt->add( src_i->first,
    610559                                   get<Type>().accept1(src_i->second) );
     560                }
     561
     562                for (decltype(src->beginVar()) src_i = src->beginVar(); src_i != src->endVar(); src_i++) {
     563                        rslt->addVar( src_i->first,
     564                                      get<Expression>().accept1(src_i->second) );
    611565                }
    612566
     
    621575                assert( tgtResnSlots.empty() );
    622576
    623                 if ( srcInferred.data.inferParams ) {
     577                if ( srcInferred.mode == ast::Expr::InferUnion::Params ) {
    624578                        const ast::InferredParams &srcParams = srcInferred.inferParams();
    625579                        for (auto & srcParam : srcParams) {
     
    627581                                        srcParam.second.decl,
    628582                                        get<Declaration>().accept1(srcParam.second.declptr),
    629                                         get<Type>().accept1(srcParam.second.actualType)->clone(),
    630                                         get<Type>().accept1(srcParam.second.formalType)->clone(),
    631                                         get<Expression>().accept1(srcParam.second.expr)->clone()
     583                                        get<Type>().accept1(srcParam.second.actualType),
     584                                        get<Type>().accept1(srcParam.second.formalType),
     585                                        get<Expression>().accept1(srcParam.second.expr)
    632586                                ));
    633587                                assert(res.second);
    634588                        }
    635                 }
    636                 if ( srcInferred.data.resnSlots ) {
     589                } else if ( srcInferred.mode == ast::Expr::InferUnion::Slots  ) {
    637590                        const ast::ResnSlots &srcSlots = srcInferred.resnSlots();
    638591                        for (auto srcSlot : srcSlots) {
     
    655608
    656609                tgt->result = get<Type>().accept1(src->result);
    657                 // Unconditionally use a clone of the result type.
    658                 // We know this will leak some objects: much of the immediate conversion result.
    659                 // In some cases, using the conversion result directly gives unintended object sharing.
    660                 // A parameter (ObjectDecl, a child of a FunctionType) is shared by the weak-ref cache.
    661                 // But tgt->result must be fully owned privately by tgt.
    662                 // Applying these conservative copies here means
    663                 // - weak references point at the declaration's copy, not these expr.result copies (good)
    664                 // - we copy more objects than really needed (bad, tolerated)
    665                 if (tgt->result) {
    666                         tgt->result = tgt->result->clone();
    667                 }
    668610                return visitBaseExpr_skipResultType(src, tgt);
    669611        }
     
    738680                        new KeywordCastExpr(
    739681                                get<Expression>().accept1(node->arg),
    740                                 castTarget,
    741                                 {node->concrete_target.field, node->concrete_target.getter}
     682                                castTarget
    742683                        )
    743684                );
     
    1026967
    1027968        const ast::Expr * visit( const ast::StmtExpr * node ) override final {
    1028                 auto stmts = node->stmts;
    1029                 // disable sharing between multiple StmtExprs explicitly.
    1030                 // this should no longer be true.
    1031 
    1032969                auto rslt = new StmtExpr(
    1033                         get<CompoundStmt>().accept1(stmts)
     970                        get<CompoundStmt>().accept1(node->stmts)
    1034971                );
    1035972
    1036973                rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls);
    1037974                rslt->dtors       = get<Expression>().acceptL(node->dtors);
    1038                 if (node->resultExpr) {
    1039                         // this MUST be found by children visit
    1040                         rslt->resultExpr  = strict_dynamic_cast<ExprStmt *>(readonlyCache.at(node->resultExpr));
    1041                 }
    1042975
    1043976                auto expr = visitBaseExpr( node, rslt );
     
    1056989
    1057990                auto expr = visitBaseExpr( node, rslt );
    1058                 this->node = expr->clone();
     991                this->node = expr;
    1059992                return nullptr;
    1060993        }
     
    11461079                auto type = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind };
    11471080                // I believe this should always be a BasicType.
    1148                 if ( ast::sizeType == node ) {
     1081                if ( sizeType == node ) {
    11491082                        Validate::SizeType = type;
    11501083                }
     
    11881121
    11891122        const ast::Type * visit( const ast::FunctionType * node ) override final {
    1190                 static std::string dummy_paramvar_prefix = "__param_";
    1191                 static std::string dummy_returnvar_prefix = "__retval_";
    1192 
    11931123                auto ty = new FunctionType {
    11941124                        cv( node ),
    11951125                        (bool)node->isVarArgs
    11961126                };
    1197                 auto returns = get<Type>().acceptL(node->returns);
    1198                 auto params = get<Type>().acceptL(node->params);
    1199 
    1200                 int ret_index = 0;
    1201                 for (auto t: returns) {
    1202                         // xxx - LinkageSpec shouldn't matter but needs to be something
    1203                         ObjectDecl * dummy = new ObjectDecl(dummy_returnvar_prefix + std::to_string(ret_index++), {}, LinkageSpec::C, nullptr, t, nullptr);
    1204                         ty->returnVals.push_back(dummy);
    1205                 }
    1206                 int param_index = 0;
    1207                 for (auto t: params) {
    1208                         ObjectDecl * dummy = new ObjectDecl(dummy_paramvar_prefix + std::to_string(param_index++), {}, LinkageSpec::C, nullptr, t, nullptr);
    1209                         ty->parameters.push_back(dummy);
    1210                 }
    1211 
    1212                 // ty->returnVals = get<DeclarationWithType>().acceptL( node->returns );
    1213                 // 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 
     1127                ty->returnVals = get<DeclarationWithType>().acceptL( node->returns );
     1128                ty->parameters = get<DeclarationWithType>().acceptL( node->params );
     1129                ty->forall = get<TypeDecl>().acceptL( node->forall );
    12351130                return visitType( node, ty );
    12361131        }
    12371132
    1238         const ast::Type * postvisit( const ast::BaseInstType * old, ReferenceToType * ty ) {
     1133        const ast::Type * postvisit( const ast::ReferenceToType * old, ReferenceToType * ty ) {
     1134                ty->forall = get<TypeDecl>().acceptL( old->forall );
    12391135                ty->parameters = get<Expression>().acceptL( old->params );
    12401136                ty->hoistType = old->hoistType;
     
    13191215                        ty = new TypeInstType{
    13201216                                cv( node ),
    1321                                 node->typeString(),
     1217                                node->name,
    13221218                                get<TypeDecl>().accept1( node->base ),
    13231219                                get<Attribute>().acceptL( node->attributes )
     
    13261222                        ty = new TypeInstType{
    13271223                                cv( node ),
    1328                                 node->typeString(),
     1224                                node->name,
    13291225                                node->kind == ast::TypeDecl::Ftype,
    13301226                                get<Attribute>().acceptL( node->attributes )
     
    14231319};
    14241320
    1425 std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit ) {
     1321std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > > && translationUnit ) {
    14261322        ConverterNewToOld c;
    14271323        std::list< Declaration * > decls;
    1428         for(auto d : translationUnit.decls) {
     1324        for(auto d : translationUnit) {
    14291325                decls.emplace_back( c.decl( d ) );
    14301326        }
     
    14471343        ast::Node * node = nullptr;
    14481344        /// cache of nodes that might be referenced by readonly<> for de-duplication
    1449         /// in case that some nodes are dropped by conversion (due to possible structural change)
    1450         /// use smart pointers in cache value to prevent accidental invalidation.
    1451         /// at conversion stage, all created nodes are guaranteed to be unique, therefore
    1452         /// const_casting out of smart pointers is permitted.
    1453         std::unordered_map< const BaseSyntaxNode *, ast::readonly<ast::Node> > cache = {};
     1345        std::unordered_map< const BaseSyntaxNode *, ast::Node * > cache = {};
    14541346
    14551347        // Local Utilities:
     
    15241416                auto it = cache.find( old );
    15251417                if ( it == cache.end() ) return false;
    1526                 node = const_cast<ast::Node *>(it->second.get());
     1418                node = it->second;
    15271419                return true;
    15281420        }
     
    15631455        virtual void visit( const FunctionDecl * old ) override final {
    15641456                if ( inCache( old ) ) return;
    1565                 auto paramVars = GET_ACCEPT_V(type->parameters, DeclWithType);
    1566                 auto returnVars = GET_ACCEPT_V(type->returnVals, DeclWithType);
    1567                 auto forall = GET_ACCEPT_V(type->forall, TypeDecl);
    1568 
    1569                 // function type is now derived from parameter decls instead of storing them
    1570 
    1571                 /*
    1572                 auto ftype = new ast::FunctionType((ast::ArgumentFlag)old->type->isVarArgs, cv(old->type));
    1573                 ftype->params.reserve(paramVars.size());
    1574                 ftype->returns.reserve(returnVars.size());
    1575 
    1576                 for (auto & v: paramVars) {
    1577                         ftype->params.emplace_back(v->get_type());
    1578                 }
    1579                 for (auto & v: returnVars) {
    1580                         ftype->returns.emplace_back(v->get_type());
    1581                 }
    1582                 ftype->forall = std::move(forall);
    1583                 */
    1584 
    1585                 // can function type have attributes? seems not to be the case.
    1586                 // 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                 }
    1599 
    16001457                auto decl = new ast::FunctionDecl{
    16011458                        old->location,
    16021459                        old->name,
    1603                         // GET_ACCEPT_1(type, FunctionType),
    1604                         std::move(forall),
    1605                         std::move(paramVars),
    1606                         std::move(returnVars),
     1460                        GET_ACCEPT_1(type, FunctionType),
    16071461                        {},
    16081462                        { old->storageClasses.val },
    16091463                        { old->linkage.val },
    16101464                        GET_ACCEPT_V(attributes, Attribute),
    1611                         { old->get_funcSpec().val },
    1612                         old->type->isVarArgs
     1465                        { old->get_funcSpec().val }
    16131466                };
    1614 
    1615                 // decl->type = ftype;
    16161467                cache.emplace( old, decl );
    1617 
    1618                 decl->assertions = std::move(assertions);
    16191468                decl->withExprs = GET_ACCEPT_V(withExprs, Expr);
    16201469                decl->stmts = GET_ACCEPT_1(statements, CompoundStmt);
     
    16291478
    16301479                if ( Validate::dereferenceOperator == old ) {
    1631                         ast::dereferenceOperator = decl;
     1480                        dereferenceOperator = decl;
    16321481                }
    16331482
    16341483                if ( Validate::dtorStructDestroy == old ) {
    1635                         ast::dtorStructDestroy = decl;
     1484                        dtorStructDestroy = decl;
    16361485                }
    16371486        }
     
    16581507
    16591508                if ( Validate::dtorStruct == old ) {
    1660                         ast::dtorStruct = decl;
     1509                        dtorStruct = decl;
    16611510                }
    16621511        }
     
    17351584                cache.emplace( old, decl );
    17361585                decl->assertions = GET_ACCEPT_V(assertions, DeclWithType);
     1586                decl->params     = GET_ACCEPT_V(parameters, TypeDecl);
    17371587                decl->extension  = old->extension;
    17381588                decl->uniqueId   = old->uniqueId;
     
    17501600                );
    17511601                decl->assertions = GET_ACCEPT_V(assertions, DeclWithType);
     1602                decl->params     = GET_ACCEPT_V(parameters, TypeDecl);
    17521603                decl->extension  = old->extension;
    17531604                decl->uniqueId   = old->uniqueId;
     
    20081859        }
    20091860
    2010         virtual void visit( const SuspendStmt * old ) override final {
    2011                 if ( inCache( old ) ) return;
    2012                 ast::SuspendStmt::Type type;
    2013                 switch (old->type) {
    2014                         case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break;
    2015                         case SuspendStmt::Generator: type = ast::SuspendStmt::Generator; break;
    2016                         case SuspendStmt::None     : type = ast::SuspendStmt::None     ; break;
    2017                         default: abort();
    2018                 }
    2019                 this->node = new ast::SuspendStmt(
    2020                         old->location,
    2021                         GET_ACCEPT_1(then  , CompoundStmt),
    2022                         type,
    2023                         GET_LABELS_V(old->labels)
    2024                 );
    2025                 cache.emplace( old, this->node );
    2026         }
    2027 
    20281861        virtual void visit( const WaitForStmt * old ) override final {
    20291862                if ( inCache( old ) ) return;
     
    20991932        }
    21001933
    2101         // TypeSubstitution shouldn't exist yet in old.
    21021934        ast::TypeSubstitution * convertTypeSubstitution(const TypeSubstitution * old) {
    2103                
     1935
    21041936                if (!old) return nullptr;
    2105                 if (old->empty()) return nullptr;
    2106                 assert(false);
    2107 
    2108                 /*
     1937
    21091938                ast::TypeSubstitution *rslt = new ast::TypeSubstitution();
    21101939
     
    21141943                }
    21151944
     1945                for (decltype(old->beginVar()) old_i = old->beginVar(); old_i != old->endVar(); old_i++) {
     1946                        rslt->addVar( old_i->first,
     1947                                      getAccept1<ast::Expr>(old_i->second) );
     1948                }
     1949
    21161950                return rslt;
    2117                 */
    21181951        }
    21191952
     
    21231956
    21241957                assert( oldInferParams.empty() || oldResnSlots.empty() );
    2125                 // assert( newInferred.mode == ast::Expr::InferUnion::Empty );
     1958                assert( newInferred.mode == ast::Expr::InferUnion::Empty );
    21261959
    21271960                if ( !oldInferParams.empty() ) {
     
    22062039                                old->location,
    22072040                                GET_ACCEPT_1(arg, Expr),
    2208                                 castTarget,
    2209                                 {old->concrete_target.field, old->concrete_target.getter}
     2041                                castTarget
    22102042                        )
    22112043                );
     
    22552087                                old->location,
    22562088                                GET_ACCEPT_1(member, DeclWithType),
    2257                                 GET_ACCEPT_1(aggregate, Expr),
    2258                                 ast::MemberExpr::NoOpConstructionChosen
     2089                                GET_ACCEPT_1(aggregate, Expr)
    22592090                        )
    22602091                );
     
    25882419                // I believe this should always be a BasicType.
    25892420                if ( Validate::SizeType == old ) {
    2590                         ast::sizeType = type;
     2421                        sizeType = type;
    25912422                }
    25922423                visitType( old, type );
     
    26332464                        cv( old )
    26342465                };
    2635                 auto returnVars = GET_ACCEPT_V(returnVals, DeclWithType);
    2636                 auto paramVars = GET_ACCEPT_V(parameters, DeclWithType);
    2637                 // ty->returns = GET_ACCEPT_V( returnVals, DeclWithType );
    2638                 // ty->params = GET_ACCEPT_V( parameters, DeclWithType );
    2639                 for (auto & v: returnVars) {
    2640                         ty->returns.emplace_back(v->get_type());
    2641                 }
    2642                 for (auto & v: paramVars) {
    2643                         ty->params.emplace_back(v->get_type());
    2644                 }
    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                 }
     2466                ty->returns = GET_ACCEPT_V( returnVals, DeclWithType );
     2467                ty->params = GET_ACCEPT_V( parameters, DeclWithType );
     2468                ty->forall = GET_ACCEPT_V( forall, TypeDecl );
    26552469                visitType( old, ty );
    26562470        }
    26572471
    2658         void postvisit( const ReferenceToType * old, ast::BaseInstType * ty ) {
     2472        void postvisit( const ReferenceToType * old, ast::ReferenceToType * ty ) {
     2473                ty->forall = GET_ACCEPT_V( forall, TypeDecl );
    26592474                ty->params = GET_ACCEPT_V( parameters, Expr );
    26602475                ty->hoistType = old->hoistType;
     
    28012616                        old->location,
    28022617                        GET_ACCEPT_1(value, Expr),
    2803                         (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::NoConstruct
     2618                        (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::DoConstruct
    28042619                );
    28052620        }
     
    28102625                        GET_ACCEPT_V(initializers, Init),
    28112626                        GET_ACCEPT_V(designations, Designation),
    2812                         (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::NoConstruct
     2627                        (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::DoConstruct
    28132628                );
    28142629        }
     
    28412656#undef GET_ACCEPT_1
    28422657
    2843 ast::TranslationUnit convert( const std::list< Declaration * > && translationUnit ) {
     2658std::list< ast::ptr< ast::Decl > > convert( const std::list< Declaration * > && translationUnit ) {
    28442659        ConverterOldToNew c;
    2845         ast::TranslationUnit unit;
    2846         if (Validate::SizeType) {
    2847                 // this should be a BasicType.
    2848                 auto old = strict_dynamic_cast<BasicType *>(Validate::SizeType);
    2849                 ast::sizeType = new ast::BasicType{ (ast::BasicType::Kind)(unsigned)old->kind };
    2850         }
    2851 
     2660        std::list< ast::ptr< ast::Decl > > decls;
    28522661        for(auto d : translationUnit) {
    28532662                d->accept( c );
    2854                 unit.decls.emplace_back( c.decl() );
     2663                decls.emplace_back( c.decl() );
    28552664        }
    28562665        deleteAll(translationUnit);
    2857 
    2858         // Load the local static varables into the global store.
    2859         unit.global.sizeType = ast::sizeType;
    2860         unit.global.dereference = ast::dereferenceOperator;
    2861         unit.global.dtorStruct = ast::dtorStruct;
    2862         unit.global.dtorDestroy = ast::dtorStructDestroy;
    2863 
    2864         return unit;
     2666        return decls;
    28652667}
  • src/AST/Convert.hpp

    reef8dfb rbdfc032  
    1818#include <list>
    1919
     20#include "AST/Node.hpp"
     21
    2022class Declaration;
    2123namespace ast {
    22         struct TranslationUnit;
     24        class Decl;
    2325};
    2426
    25 std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit );
    26 ast::TranslationUnit convert( const std::list< Declaration * > && translationUnit );
     27std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > > && translationUnit );
     28std::list< ast::ptr< ast::Decl > > convert( const std::list< Declaration * > && translationUnit );
  • src/AST/Decl.cpp

    reef8dfb rbdfc032  
    4949// --- FunctionDecl
    5050
    51 FunctionDecl::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 }
    70 
    71 
    7251const Type * FunctionDecl::get_type() const { return type.get(); }
    73 void FunctionDecl::set_type( const Type * t ) {
    74         type = strict_dynamic_cast< const FunctionType * >( t );
    75 }
     52void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); }
    7653
    7754// --- TypeDecl
  • src/AST/Decl.hpp

    reef8dfb rbdfc032  
    3333
    3434// Must be included in *all* AST classes; should be #undef'd at the end of the file
    35 #define MUTATE_FRIEND \
    36     template<typename node_t> friend node_t * mutate(const node_t * node); \
    37         template<typename node_t> friend node_t * shallowCopy(const node_t * node);
     35#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
    3836
    3937namespace ast {
     
    7977        ptr<Expr> asmName;
    8078        bool isDeleted = false;
    81         bool isTypeFixed = false;
    8279
    8380        DeclWithType( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
     
    9188        virtual const Type * get_type() const = 0;
    9289        /// Set type of this declaration. May be verified by subclass
    93         virtual void set_type( const Type * ) = 0;
     90        virtual void set_type(Type *) = 0;
    9491
    9592        const DeclWithType * accept( Visitor & v ) const override = 0;
     
    114111
    115112        const Type* get_type() const override { return type; }
    116         void set_type( const Type * ty ) override { type = ty; }
     113        void set_type( Type * ty ) override { type = ty; }
    117114
    118115        const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
     
    125122class FunctionDecl : public DeclWithType {
    126123public:
    127         std::vector<ptr<DeclWithType>> params;
    128         std::vector<ptr<DeclWithType>> returns;
    129         std::vector<ptr<TypeDecl>> type_params;
    130         std::vector<ptr<DeclWithType>> assertions;
    131         // declared type, derived from parameter declarations
    132124        ptr<FunctionType> type;
    133125        ptr<CompoundStmt> stmts;
    134126        std::vector< ptr<Expr> > withExprs;
    135127
    136 
    137         FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
    138                 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
     128        FunctionDecl( const CodeLocation & loc, const std::string & name, FunctionType * type,
    139129                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
    140                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
    141         // : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
    142         //  stmts( stmts ) {}
     130                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {})
     131        : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), type( type ),
     132          stmts( stmts ) {}
    143133
    144134        const Type * get_type() const override;
    145         void set_type( const Type * t ) override;
     135        void set_type(Type * t) override;
    146136
    147137        bool has_body() const { return stmts; }
     
    157147public:
    158148        ptr<Type> base;
     149        std::vector<ptr<TypeDecl>> params;
    159150        std::vector<ptr<DeclWithType>> assertions;
    160151
    161         NamedTypeDecl(
    162                 const CodeLocation & loc, const std::string & name, Storage::Classes storage,
    163                 const Type * b, Linkage::Spec spec = Linkage::Cforall )
    164         : Decl( loc, name, storage, spec ), base( b ), assertions() {}
     152        NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
     153                Type* b, Linkage::Spec spec = Linkage::Cforall )
     154        : Decl( loc, name, storage, spec ), base( b ), params(), assertions() {}
    165155
    166156        /// Produces a name for the kind of alias
     
    196186        };
    197187
    198         TypeDecl(
    199                 const CodeLocation & loc, const std::string & name, Storage::Classes storage,
    200                 const Type * b, TypeDecl::Kind k, bool s, const Type * i = nullptr )
    201         : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeDecl::Ttype || s ),
    202           init( i ) {}
     188        TypeDecl( const CodeLocation & loc, const std::string & name, Storage::Classes storage, Type * b,
     189                          Kind k, bool s, Type * i = nullptr )
     190                : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == Ttype || s ),
     191                init( i ) {}
    203192
    204193        const char * typeString() const override;
     
    270259
    271260        bool is_coroutine() { return kind == Coroutine; }
    272         bool is_generator() { return kind == Generator; }
    273         bool is_monitor  () { return kind == Monitor  ; }
    274         bool is_thread   () { return kind == Thread   ; }
     261        bool is_monitor() { return kind == Monitor; }
     262        bool is_thread() { return kind == Thread; }
    275263
    276264        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/DeclReplacer.cpp

    reef8dfb rbdfc032  
    3838                        const ast::TypeInstType * previsit( const ast::TypeInstType * );
    3939                };
    40 
    41                 struct VarExprReplacer {
    42                 private:
    43                         const ExprMap & exprMap;
    44                        
    45                 public:
    46                         VarExprReplacer(const ExprMap & exprMap): exprMap (exprMap) {}
    47 
    48                         const Expr * postvisit (const VariableExpr *);
    49                 };
    5040        }
    5141
     
    6454                DeclMap declMap;
    6555                return replace( node, declMap, typeMap, debug );
    66         }
    67 
    68         const ast::Node * replace( const ast::Node * node, const ExprMap & exprMap) {
    69                 Pass<VarExprReplacer> replacer = {exprMap};
    70                 return node->accept( replacer );
    7156        }
    7257
     
    10388                        return ninst;
    10489                }
    105 
    106                 const Expr * VarExprReplacer::postvisit( const VariableExpr * expr ) {
    107                         if (!exprMap.count(expr->var)) return expr;
    108 
    109                         return exprMap.at(expr->var);
    110                 }
    111 
    11290        }
    11391}
  • src/AST/DeclReplacer.hpp

    reef8dfb rbdfc032  
    2323        class DeclWithType;
    2424        class TypeDecl;
    25         class Expr;
    2625
    2726        namespace DeclReplacer {
    2827                using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >;
    2928                using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >;
    30                 using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >;
    3129
    3230                const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false );
    3331                const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false );
    3432                const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false );
    35                 const Node * replace( const Node * node, const ExprMap & exprMap);
    3633        }
    3734}
  • src/AST/Expr.cpp

    reef8dfb rbdfc032  
    2020#include <vector>
    2121
    22 #include "Copy.hpp"                // for shallowCopy
    23 #include "Eval.hpp"                // for call
    2422#include "GenericSubstitution.hpp"
    25 #include "LinkageSpec.hpp"
    2623#include "Stmt.hpp"
    2724#include "Type.hpp"
     
    3027#include "Common/SemanticError.h"
    3128#include "GenPoly/Lvalue.h"        // for referencesPermissable
    32 #include "InitTweak/InitTweak.h"   // for getFunction, getPointerBase
     29#include "InitTweak/InitTweak.h"   // for getPointerBase
    3330#include "ResolvExpr/typeops.h"    // for extractResultType
    3431#include "Tuples/Tuples.h"         // for makeTupleType
    3532
    3633namespace ast {
    37 
    38 namespace {
    39         std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"};
    40 }
    41 
    42 // --- Expr
    43 bool Expr::get_lvalue() const {
    44         return false;
    45 }
    4634
    4735// --- ApplicationExpr
     
    5846}
    5947
    60 bool ApplicationExpr::get_lvalue() const {
    61         if ( const DeclWithType * func = InitTweak::getFunction( this ) ) {
    62                 return func->linkage == Linkage::Intrinsic && lvalueFunctionNames.count( func->name );
    63         }
    64         return false;
    65 }
    66 
    6748// --- UntypedExpr
    6849
    69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) {
     50UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, Expr * arg ) {
    7051        assert( arg );
    7152
    72         UntypedExpr * ret = call( loc, "*?", arg );
     53        UntypedExpr * ret = new UntypedExpr{
     54                loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } }
     55        };
    7356        if ( const Type * ty = arg->result ) {
    7457                const Type * base = InitTweak::getPointerBase( ty );
     
    8265                        // base type
    8366                        ret->result = base;
     67                        add_qualifiers( ret->result, CV::Lvalue );
    8468                }
    8569        }
     
    8771}
    8872
    89 bool UntypedExpr::get_lvalue() const {
    90         std::string fname = InitTweak::getFunctionName( this );
    91         return lvalueFunctionNames.count( fname );
    92 }
    93 
    94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) {
     73UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs ) {
    9574        assert( lhs && rhs );
    9675
    97         UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
     76        UntypedExpr * ret = new UntypedExpr{
     77                loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } }
     78        };
    9879        if ( lhs->result && rhs->result ) {
    9980                // if both expressions are typed, assumes that this assignment is a C bitwise assignment,
     
    10283        }
    10384        return ret;
    104 }
    105 
    106 // --- VariableExpr
    107 
    108 VariableExpr::VariableExpr( const CodeLocation & loc )
    109 : Expr( loc ), var( nullptr ) {}
    110 
    111 VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v )
    112 : Expr( loc ), var( v ) {
    113         assert( var );
    114         assert( var->get_type() );
    115         result = shallowCopy( var->get_type() );
    116 }
    117 
    118 bool VariableExpr::get_lvalue() const {
    119         // It isn't always an lvalue, but it is never an rvalue.
    120         return true;
    121 }
    122 
    123 VariableExpr * VariableExpr::functionPointer(
    124                 const CodeLocation & loc, const FunctionDecl * decl ) {
    125         // wrap usually-determined result type in a pointer
    126         VariableExpr * funcExpr = new VariableExpr{ loc, decl };
    127         funcExpr->result = new PointerType{ funcExpr->result };
    128         return funcExpr;
    12985}
    13086
     
    152108AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) : Expr( loc ), arg( a ) {
    153109        if ( arg->result ) {
    154                 if ( arg->get_lvalue() ) {
     110                if ( arg->result->is_lvalue() ) {
    155111                        // lvalue, retains all levels of reference, and gains a pointer inside the references
    156112                        Type * res = addrType( arg->result );
     113                        res->set_lvalue( false ); // result of & is never an lvalue
    157114                        result = res;
    158115                } else {
     
    161118                                        dynamic_cast< const ReferenceType * >( arg->result.get() ) ) {
    162119                                Type * res = addrType( refType->base );
     120                                res->set_lvalue( false ); // result of & is never an lvalue
    163121                                result = res;
    164122                        } else {
     
    181139: Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {}
    182140
    183 bool CastExpr::get_lvalue() const {
    184         // This is actually wrong by C, but it works with our current set-up.
    185         return arg->get_lvalue();
    186 }
    187 
    188141// --- KeywordCastExpr
    189142
    190143const char * KeywordCastExpr::targetString() const {
    191144        return AggregateDecl::aggrString( target );
    192 }
    193 
    194 // --- UntypedMemberExpr
    195 
    196 bool UntypedMemberExpr::get_lvalue() const {
    197         return aggregate->get_lvalue();
    198145}
    199146
     
    206153        assert( aggregate->result );
    207154
     155        // take ownership of member type
    208156        result = mem->get_type();
    209 
    210157        // substitute aggregate generic parameters into member type
    211158        genericSubstitution( aggregate->result ).apply( result );
    212         // ensure appropriate restrictions from aggregate type
    213         add_qualifiers( result, aggregate->result->qualifiers );
    214 }
    215 
    216 MemberExpr::MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
    217     MemberExpr::NoOpConstruction overloadSelector )
    218 : Expr( loc ), member( mem ), aggregate( agg ) {
    219         assert( member );
    220         assert( aggregate );
    221         assert( aggregate->result );
    222         (void) overloadSelector;
    223 }
    224 
    225 bool MemberExpr::get_lvalue() const {
    226         // This is actually wrong by C, but it works with our current set-up.
    227         return true;
     159        // ensure lvalue and appropriate restrictions from aggregate type
     160        add_qualifiers( result, aggregate->result->qualifiers | CV::Lvalue );
     161}
     162
     163// --- VariableExpr
     164
     165VariableExpr::VariableExpr( const CodeLocation & loc )
     166: Expr( loc ), var( nullptr ) {}
     167
     168VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v )
     169: Expr( loc ), var( v ) {
     170        assert( var );
     171        assert( var->get_type() );
     172        result = var->get_type();
     173        add_qualifiers( result, CV::Lvalue );
     174}
     175
     176VariableExpr * VariableExpr::functionPointer(
     177                const CodeLocation & loc, const FunctionDecl * decl ) {
     178        // wrap usually-determined result type in a pointer
     179        VariableExpr * funcExpr = new VariableExpr{ loc, decl };
     180        funcExpr->result = new PointerType{ funcExpr->result };
     181        return funcExpr;
    228182}
    229183
     
    303257        const CodeLocation & loc, const Expr * a1, const Expr * a2, LogicalFlag ia )
    304258: Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {}
    305 
    306 // --- CommaExpr
    307 bool CommaExpr::get_lvalue() const {
    308         // This is wrong by C, but the current implementation uses it.
    309         // (ex: Specialize, Lvalue and Box)
    310         return arg2->get_lvalue();
    311 }
    312259
    313260// --- ConstructorExpr
     
    329276        assert( t && i );
    330277        result = t;
    331 }
    332 
    333 bool CompoundLiteralExpr::get_lvalue() const {
    334         return true;
     278        add_qualifiers( result, CV::Lvalue );
    335279}
    336280
     
    349293        // like MemberExpr, TupleIndexExpr is always an lvalue
    350294        result = type->types[ index ];
    351 }
    352 
    353 bool TupleIndexExpr::get_lvalue() const {
    354         return tuple->get_lvalue();
     295        add_qualifiers( result, CV::Lvalue );
    355296}
    356297
  • src/AST/Expr.hpp

    reef8dfb rbdfc032  
    3131
    3232// Must be included in *all* AST classes; should be #undef'd at the end of the file
    33 #define MUTATE_FRIEND \
    34     template<typename node_t> friend node_t * mutate(const node_t * node); \
    35         template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    36 
     33#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
    3734
    3835class ConverterOldToNew;
     
    4542struct ParamEntry {
    4643        UniqueId decl;
    47         readonly<Decl> declptr;
     44        ptr<Decl> declptr;
    4845        ptr<Type> actualType;
    4946        ptr<Type> formalType;
     
    6562class Expr : public ParseNode {
    6663public:
    67         /*
    68          * NOTE: the union approach is incorrect until the case of
    69          * partial resolution in InferMatcher is eliminated.
    70          * it is reverted to allow unresolved and resolved parameters
    71          * to coexist in an expression node.
    72          */
     64        /// Saves space (~16 bytes) by combining ResnSlots and InferredParams
    7365        struct InferUnion {
    74                 // mode is now unused
    7566                enum { Empty, Slots, Params } mode;
    76                 struct data_t {
    77                         // char def;
    78                         ResnSlots * resnSlots;
    79                         InferredParams * inferParams;
    80 
    81                         data_t(): resnSlots(nullptr), inferParams(nullptr) {}
    82                         data_t(const data_t &other) = delete;
    83                         ~data_t() {
    84                                 delete resnSlots;
    85                                 delete inferParams;
    86                         }
     67                union data_t {
     68                        char def;
     69                        ResnSlots resnSlots;
     70                        InferredParams inferParams;
     71
     72                        data_t() : def('\0') {}
     73                        ~data_t() {}
    8774                } data;
    8875
    8976                /// initializes from other InferUnion
    9077                void init_from( const InferUnion& o ) {
    91                         if (o.data.resnSlots) {
    92                                 data.resnSlots = new ResnSlots(*o.data.resnSlots);
    93                         }
    94                         if (o.data.inferParams) {
    95                                 data.inferParams = new InferredParams(*o.data.inferParams);
     78                        switch ( o.mode ) {
     79                        case Empty:  return;
     80                        case Slots:  new(&data.resnSlots) ResnSlots{ o.data.resnSlots }; return;
     81                        case Params: new(&data.inferParams) InferredParams{ o.data.inferParams }; return;
    9682                        }
    9783                }
     
    9985                /// initializes from other InferUnion (move semantics)
    10086                void init_from( InferUnion&& o ) {
    101                         data.resnSlots = o.data.resnSlots;
    102                         data.inferParams = o.data.inferParams;
    103                         o.data.resnSlots = nullptr;
    104                         o.data.inferParams = nullptr;
     87                        switch ( o.mode ) {
     88                        case Empty:  return;
     89                        case Slots:  new(&data.resnSlots) ResnSlots{ std::move(o.data.resnSlots) }; return;
     90                        case Params:
     91                                new(&data.inferParams) InferredParams{ std::move(o.data.inferParams) }; return;
     92                        }
     93                }
     94
     95                /// clears variant fields
     96                void reset() {
     97                        switch( mode ) {
     98                        case Empty:  return;
     99                        case Slots:  data.resnSlots.~ResnSlots(); return;
     100                        case Params: data.inferParams.~InferredParams(); return;
     101                        }
    105102                }
    106103
     
    110107                InferUnion& operator= ( const InferUnion& ) = delete;
    111108                InferUnion& operator= ( InferUnion&& ) = delete;
    112 
    113                 bool hasSlots() const { return data.resnSlots; }
    114                 bool hasParams() const { return data.inferParams; }
     109                ~InferUnion() { reset(); }
    115110
    116111                ResnSlots& resnSlots() {
    117                         if (!data.resnSlots) {
    118                                 data.resnSlots = new ResnSlots();
     112                        switch (mode) {
     113                        case Empty: new(&data.resnSlots) ResnSlots{}; mode = Slots; // fallthrough
     114                        case Slots: return data.resnSlots;
     115                        case Params: assertf(false, "Cannot return to resnSlots from Params"); abort();
    119116                        }
    120                         return *data.resnSlots;
     117                        assertf(false, "unreachable");
    121118                }
    122119
    123120                const ResnSlots& resnSlots() const {
    124                         if (data.resnSlots) {
    125                                 return *data.resnSlots;
     121                        if (mode == Slots) {
     122                                return data.resnSlots;
    126123                        }
    127124                        assertf(false, "Mode was not already resnSlots");
     
    130127
    131128                InferredParams& inferParams() {
    132                         if (!data.inferParams) {
    133                                 data.inferParams = new InferredParams();
     129                        switch (mode) {
     130                        case Slots: data.resnSlots.~ResnSlots(); // fallthrough
     131                        case Empty: new(&data.inferParams) InferredParams{}; mode = Params; // fallthrough
     132                        case Params: return data.inferParams;
    134133                        }
    135                         return *data.inferParams;
     134                        assertf(false, "unreachable");
    136135                }
    137136
    138137                const InferredParams& inferParams() const {
    139                         if (data.inferParams) {
    140                                 return *data.inferParams;
     138                        if (mode == Params) {
     139                                return data.inferParams;
    141140                        }
    142141                        assertf(false, "Mode was not already Params");
     
    144143                }
    145144
    146                 void set_inferParams( InferredParams * ps ) {
    147                         delete data.resnSlots;
    148                         data.resnSlots = nullptr;
    149                         delete data.inferParams;
    150                         data.inferParams = ps;
     145                void set_inferParams( InferredParams && ps ) {
     146                        switch(mode) {
     147                        case Slots:
     148                                data.resnSlots.~ResnSlots();
     149                                // fallthrough
     150                        case Empty:
     151                                new(&data.inferParams) InferredParams{ std::move( ps ) };
     152                                mode = Params;
     153                                break;
     154                        case Params:
     155                                data.inferParams = std::move( ps );
     156                                break;
     157                        }
    151158                }
    152159
     
    154161                /// and the other is in `Params`.
    155162                void splice( InferUnion && o ) {
    156                         if (o.data.resnSlots) {
    157                                 if (data.resnSlots) {
    158                                         data.resnSlots->insert(
    159                                                 data.resnSlots->end(), o.data.resnSlots->begin(), o.data.resnSlots->end() );
    160                                         delete o.data.resnSlots;
     163                        if ( o.mode == Empty ) return;
     164                        if ( mode == Empty ) { init_from( o ); return; }
     165                        assert( mode == o.mode && "attempt to splice incompatible InferUnion" );
     166
     167                        if ( mode == Slots ){
     168                                data.resnSlots.insert(
     169                                        data.resnSlots.end(), o.data.resnSlots.begin(), o.data.resnSlots.end() );
     170                        } else if ( mode == Params ) {
     171                                for ( const auto & p : o.data.inferParams ) {
     172                                        data.inferParams[p.first] = std::move(p.second);
    161173                                }
    162                                 else {
    163                                         data.resnSlots = o.data.resnSlots;
    164                                 }
    165                                 o.data.resnSlots = nullptr;
    166                         }
    167 
    168                         if (o.data.inferParams) {
    169                                 if (data.inferParams) {
    170                                         for ( const auto & p : *o.data.inferParams ) {
    171                                                 (*data.inferParams)[p.first] = std::move(p.second);
    172                                         }
    173                                         delete o.data.inferParams;
    174                                 }
    175                                 else {
    176                                         data.inferParams = o.data.inferParams;
    177                                 }
    178                                 o.data.inferParams = nullptr;
    179                         }
     174                        } else assertf(false, "invalid mode");
    180175                }
    181176        };
     
    190185
    191186        Expr * set_extension( bool ex ) { extension = ex; return this; }
    192         virtual bool get_lvalue() const;
    193187
    194188        virtual const Expr * accept( Visitor & v ) const override = 0;
     
    207201        ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} );
    208202
    209         bool get_lvalue() const final;
    210 
    211203        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    212204private:
     
    224216        : Expr( loc ), func( f ), args( std::move(as) ) {}
    225217
    226         bool get_lvalue() const final;
    227 
    228218        /// Creates a new dereference expression
    229         static UntypedExpr * createDeref( const CodeLocation & loc, const Expr * arg );
     219        static UntypedExpr * createDeref( const CodeLocation & loc, Expr * arg );
    230220        /// Creates a new assignment expression
    231         static UntypedExpr * createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs );
     221        static UntypedExpr * createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs );
    232222
    233223        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    251241};
    252242
    253 /// A reference to a named variable.
    254 class VariableExpr final : public Expr {
    255 public:
    256         readonly<DeclWithType> var;
    257 
    258         VariableExpr( const CodeLocation & loc );
    259         VariableExpr( const CodeLocation & loc, const DeclWithType * v );
    260 
    261         bool get_lvalue() const final;
    262 
    263         /// generates a function pointer for a given function
    264         static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl );
    265 
    266         const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    267 private:
    268         VariableExpr * clone() const override { return new VariableExpr{ *this }; }
    269         MUTATE_FRIEND
    270 };
    271 
    272243/// Address-of expression `&e`
    273244class AddressExpr final : public Expr {
     
    300271};
    301272
    302 /// Inidicates whether the cast is introduced by the CFA type system.
    303 /// GeneratedCast for casts that the resolver introduces to force a return type
    304 /// ExplicitCast for casts from user code
    305 /// ExplicitCast for casts from desugaring advanced CFA features into simpler CFA
    306 /// example
    307 ///   int * p;     // declaration
    308 ///   (float *) p; // use, with subject cast
    309 /// subject cast being GeneratedCast means we are considering an interpretation with a type mismatch
    310 /// subject cast being ExplicitCast means someone in charge wants it that way
     273/// Whether a cast existed in the program source or not
    311274enum GeneratedFlag { ExplicitCast, GeneratedCast };
    312275
     
    328291        CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {}
    329292
    330         bool get_lvalue() const final;
    331 
    332293        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    333294private:
     
    340301public:
    341302        ptr<Expr> arg;
    342         struct Concrete {
    343                 std::string field;
    344                 std::string getter;
    345 
    346                 Concrete() = default;
    347                 Concrete(const Concrete &) = default;
    348         };
    349303        ast::AggregateDecl::Aggregate target;
    350         Concrete concrete_target;
    351 
    352304
    353305        KeywordCastExpr( const CodeLocation & loc, const Expr * a, ast::AggregateDecl::Aggregate t )
    354306        : Expr( loc ), arg( a ), target( t ) {}
    355307
    356         KeywordCastExpr( const CodeLocation & loc, const Expr * a, ast::AggregateDecl::Aggregate t, const Concrete & ct )
    357         : Expr( loc ), arg( a ), target( t ), concrete_target( ct ) {}
    358 
    359308        /// Get a name for the target type
    360309        const char * targetString() const;
     
    389338        : Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); }
    390339
    391         bool get_lvalue() const final;
    392 
    393340        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    394341private:
     
    405352        MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg );
    406353
    407         bool get_lvalue() const final;
    408 
    409354        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    410355private:
    411356        MemberExpr * clone() const override { return new MemberExpr{ *this }; }
    412357        MUTATE_FRIEND
    413 
    414         // Custructor overload meant only for AST conversion
    415         enum NoOpConstruction { NoOpConstructionChosen };
    416         MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
    417             NoOpConstruction overloadSelector );
    418         friend class ::ConverterOldToNew;
    419         friend class ::ConverterNewToOld;
     358};
     359
     360/// A reference to a named variable.
     361class VariableExpr final : public Expr {
     362public:
     363        readonly<DeclWithType> var;
     364
     365        VariableExpr( const CodeLocation & loc );
     366        VariableExpr( const CodeLocation & loc, const DeclWithType * v );
     367
     368        /// generates a function pointer for a given function
     369        static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl );
     370
     371        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     372private:
     373        VariableExpr * clone() const override { return new VariableExpr{ *this }; }
     374        MUTATE_FRIEND
    420375};
    421376
     
    431386                const CodeLocation & loc, const Type * ty, const std::string & r,
    432387                        std::optional<unsigned long long> i )
    433         : Expr( loc, ty ), rep( r ), ival( i ), underlyer(ty) {}
     388        : Expr( loc, ty ), rep( r ), ival( i ) {}
    434389
    435390        /// Gets the integer value of this constant, if one is appropriate to its type.
     
    577532
    578533        CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 )
    579         : Expr( loc ), arg1( a1 ), arg2( a2 ) {
    580                 this->result = a2->result;
    581         }
    582 
    583         bool get_lvalue() const final;
     534        : Expr( loc ), arg1( a1 ), arg2( a2 ) {}
    584535
    585536        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    626577
    627578        ImplicitCopyCtorExpr( const CodeLocation& loc, const ApplicationExpr * call )
    628         : Expr( loc, call->result ), callExpr(call) { assert( call ); assert(call->result); }
     579        : Expr( loc, call->result ) { assert( call ); }
    629580
    630581        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    654605        CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i );
    655606
    656         bool get_lvalue() const final;
    657 
    658607        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    659608private:
     
    711660
    712661        TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i );
    713 
    714         bool get_lvalue() const final;
    715662
    716663        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    751698        std::vector<ptr<Expr>> dtors;              ///< destructor(s) for return variable(s)
    752699
    753         readonly<ExprStmt> resultExpr;
    754 
    755700        StmtExpr( const CodeLocation & loc, const CompoundStmt * ss );
    756701
  • src/AST/Fwd.hpp

    reef8dfb rbdfc032  
    1010// Created On       : Wed May  8 16:05:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Jul 23 14:15:00 2020
    13 // Update Count     : 2
     12// Last Modified On : Mon Jun 24 09:48:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    5353class CatchStmt;
    5454class FinallyStmt;
    55 class SuspendStmt;
    5655class WaitForStmt;
    5756class WithStmt;
     
    107106class QualifiedType;
    108107class FunctionType;
    109 class BaseInstType;
    110 template<typename decl_t> class SueInstType;
    111 using StructInstType = SueInstType<StructDecl>;
    112 using UnionInstType = SueInstType<UnionDecl>;
    113 using EnumInstType = SueInstType<EnumDecl>;
     108class ReferenceToType;
     109class StructInstType;
     110class UnionInstType;
     111class EnumInstType;
    114112class TraitInstType;
    115113class TypeInstType;
     
    137135typedef unsigned int UniqueId;
    138136
    139 struct TranslationUnit;
    140 // TODO: Get from the TranslationUnit:
    141 extern ptr<Type> sizeType;
    142 extern const FunctionDecl * dereferenceOperator;
    143 extern const StructDecl   * dtorStruct;
    144 extern const FunctionDecl * dtorStructDestroy;
    145 
    146137}
  • src/AST/GenericSubstitution.cpp

    reef8dfb rbdfc032  
    4242        private:
    4343                // make substitution for generic type
    44                 void makeSub( const BaseInstType * ty ) {
     44                void makeSub( const ReferenceToType * ty ) {
    4545                        visit_children = false;
    4646                        const AggregateDecl * aggr = ty->aggr();
     
    6262        Pass<GenericSubstitutionBuilder> builder;
    6363        maybe_accept( ty, builder );
    64         return std::move(builder.core.sub);
     64        return std::move(builder.pass.sub);
    6565}
    6666
  • src/AST/Init.hpp

    reef8dfb rbdfc032  
    2525
    2626// Must be included in *all* AST classes; should be #undef'd at the end of the file
    27 #define MUTATE_FRIEND \
    28     template<typename node_t> friend node_t * mutate(const node_t * node); \
    29         template<typename node_t> friend node_t * shallowCopy(const node_t * node);
     27#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
    3028
    3129namespace ast {
     
    5048
    5149/// Flag for whether to construct from initialzier
    52 enum ConstructFlag { NoConstruct, MaybeConstruct };
     50enum ConstructFlag { DoConstruct, MaybeConstruct };
    5351
    5452/// Object initializer base class
     
    7169        ptr<Expr> value;
    7270
    73         SingleInit( const CodeLocation & loc, const Expr * val, ConstructFlag mc = NoConstruct )
     71        SingleInit( const CodeLocation & loc, const Expr * val, ConstructFlag mc = DoConstruct )
    7472        : Init( loc, mc ), value( val ) {}
    7573
     
    9088
    9189        ListInit( const CodeLocation & loc, std::vector<ptr<Init>> && is,
    92                 std::vector<ptr<Designation>> && ds = {}, ConstructFlag mc = NoConstruct );
     90                std::vector<ptr<Designation>> && ds = {}, ConstructFlag mc = DoConstruct );
    9391
    9492        using iterator = std::vector<ptr<Init>>::iterator;
     
    118116        ConstructorInit(
    119117                const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init )
    120         : Init( loc, MaybeConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
     118        : Init( loc, DoConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
    121119
    122120        const Init * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Node.cpp

    reef8dfb rbdfc032  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 16 14:16:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jun  5 10:21:00 2020
    13 // Update Count     : 1
     11// Last Modified By :
     12// Last Modified On :
     13// Update Count     :
    1414//
    1515
     
    1717#include "Fwd.hpp"
    1818
    19 #include <csignal>  // MEMORY DEBUG -- for raise
    2019#include <iostream>
    2120
     
    3029#include "Print.hpp"
    3130
    32 /// MEMORY DEBUG -- allows breaking on ref-count changes of dynamically chosen object.
    33 /// Process to use in GDB:
    34 ///   break ast::Node::_trap()
    35 ///   run
    36 ///   set variable MEM_TRAP_OBJ = <target>
    37 ///   disable <first breakpoint>
    38 ///   continue
    39 void * MEM_TRAP_OBJ = nullptr;
    40 
    41 void _trap( const void * node ) {
    42         if ( node == MEM_TRAP_OBJ ) std::raise(SIGTRAP);
    43 }
    44 
    45 [[noreturn]] static inline void strict_fail(const ast::Node * node) {
    46         assertf(node, "strict_as had nullptr input.");
    47         const ast::ParseNode * parse = dynamic_cast<const ast::ParseNode *>( node );
    48         if ( nullptr == parse ) {
    49                 assertf(nullptr, "%s (no location)", toString(node).c_str());
    50         } else if ( parse->location.isUnset() ) {
    51                 assertf(nullptr, "%s (unset location)", toString(node).c_str());
    52         } else {
    53                 assertf(nullptr, "%s (at %s:%d)", toString(node).c_str(),
    54                         parse->location.filename.c_str(), parse->location.first_line);
    55         }
    56 }
    57 
    58 template< typename node_t, enum ast::Node::ref_type ref_t >
    59 void ast::ptr_base<node_t, ref_t>::_strict_fail() const {
    60         strict_fail(node);
    61 }
    62 
    63 template< typename node_t, enum ast::Node::ref_type ref_t >
    64 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) {
    65         node->increment(ref_t);
    66         _trap( node );
    67 }
    68 
    69 template< typename node_t, enum ast::Node::ref_type ref_t >
    70 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node, bool do_delete ) {
    71         _trap( node );
    72         node->decrement( ref_t, do_delete );
    73 }
    74 
    75 template< typename node_t, enum ast::Node::ref_type ref_t >
    76 void ast::ptr_base<node_t, ref_t>::_check() const {
    77         // if(node) assert(node->was_ever_strong == false || node->strong_count > 0);
    78 }
     31template< typename node_t, enum ast::Node::ref_type ref_t >
     32void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); }
     33
     34template< typename node_t, enum ast::Node::ref_type ref_t >
     35void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
     36
     37template< typename node_t, enum ast::Node::ref_type ref_t >
     38void ast::ptr_base<node_t, ref_t>::_check() const { if(node) assert(node->was_ever_strong == false || node->strong_count > 0); }
    7939
    8040template< typename node_t, enum ast::Node::ref_type ref_t >
     
    266226template class ast::ptr_base< ast::FunctionType, ast::Node::ref_type::weak >;
    267227template class ast::ptr_base< ast::FunctionType, ast::Node::ref_type::strong >;
    268 template class ast::ptr_base< ast::BaseInstType, ast::Node::ref_type::weak >;
    269 template class ast::ptr_base< ast::BaseInstType, ast::Node::ref_type::strong >;
     228template class ast::ptr_base< ast::ReferenceToType, ast::Node::ref_type::weak >;
     229template class ast::ptr_base< ast::ReferenceToType, ast::Node::ref_type::strong >;
    270230template class ast::ptr_base< ast::StructInstType, ast::Node::ref_type::weak >;
    271231template class ast::ptr_base< ast::StructInstType, ast::Node::ref_type::strong >;
  • src/AST/Node.hpp

    reef8dfb rbdfc032  
    1010// Created On       : Wed May 8 10:27:04 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jun 5 9:47:00 2020
    13 // Update Count     : 6
     12// Last Modified On : Mon Jun  3 13:26:00 2019
     13// Update Count     : 5
    1414//
    1515
     
    3838        Node& operator= (const Node&) = delete;
    3939        Node& operator= (Node&&) = delete;
    40         virtual ~Node() {}
     40        virtual ~Node() = default;
    4141
    4242        virtual const Node * accept( Visitor & v ) const = 0;
     
    4949
    5050        bool unique() const { return strong_count == 1; }
    51         bool isManaged() const {return strong_count > 0; }
    5251
    5352private:
     
    5857        template<typename node_t>
    5958        friend node_t * mutate(const node_t * node);
    60         template<typename node_t>
    61         friend node_t * shallowCopy(const node_t * node);
    6259
    6360        mutable size_t strong_count = 0;
     
    7269        }
    7370
    74         void decrement(ast::Node::ref_type ref, bool do_delete = true) const {
     71        void decrement(ast::Node::ref_type ref) const {
    7572                switch (ref) {
    7673                        case ref_type::strong: strong_count--; break;
     
    7875                }
    7976
    80                 if( do_delete && !strong_count && !weak_count) {
     77                if(!strong_count && !weak_count) {
    8178                        delete this;
    8279                }
     
    9794        assertf(
    9895                node->weak_count == 0,
    99                 "Error: mutating node with weak references to it will invalidate some references"
     96                "Error: mutating node with weak references to it will invalided some references"
    10097        );
    10198        return node->clone();
     
    107104        // skip mutate if equivalent
    108105        if ( node->*field == val ) return node;
    109 
     106       
    110107        // mutate and return
    111108        node_t * ret = mutate( node );
     
    126123        (ret->*field)[i] = std::forward< field_t >( val );
    127124        return ret;
    128 }
    129 
    130 /// Mutate an entire indexed collection by cloning to accepted value
    131 template<typename node_t, typename parent_t, typename coll_t>
    132 const node_t * mutate_each( const node_t * node, coll_t parent_t::* field, Visitor & v ) {
    133         for ( unsigned i = 0; i < (node->*field).size(); ++i ) {
    134                 node = mutate_field_index( node, field, i, (node->*field)[i]->accept( v ) );
    135         }
    136         return node;
    137125}
    138126
     
    229217        const node_t & operator* () const { _check(); return *node; }
    230218        explicit operator bool() const { _check(); return node; }
    231         operator const node_t * () const & { _check(); return node; }
    232         operator const node_t * () && = delete;
    233 
    234         const node_t * release() {
    235                 const node_t * ret = node;
    236                 if ( node ) {
    237                         _dec(node, false);
    238                         node = nullptr;
    239                 }
    240                 return ret;
    241         }
     219        operator const node_t * () const { _check(); return node; }
    242220
    243221        /// wrapper for convenient access to dynamic_cast
     
    245223        const o_node_t * as() const { _check(); return dynamic_cast<const o_node_t *>(node); }
    246224
    247         /// Wrapper that makes sure dynamic_cast returns non-null.
     225        /// wrapper for convenient access to strict_dynamic_cast
    248226        template<typename o_node_t>
    249         const o_node_t * strict_as() const {
    250                 if (const o_node_t * ret = as<o_node_t>()) return ret;
    251                 _strict_fail();
    252         }
    253 
    254         /// Wrapper that makes sure dynamic_cast does not fail.
    255         template<typename o_node_t, decltype(nullptr) null>
    256         const o_node_t * strict_as() const { return node ? strict_as<o_node_t>() : nullptr; }
     227        const o_node_t * strict_as() const { _check(); return strict_dynamic_cast<const o_node_t *>(node); }
    257228
    258229        /// Returns a mutable version of the pointer in this node.
     
    273244
    274245        void _inc( const node_t * other );
    275         void _dec( const node_t * other, bool do_delete = true );
     246        void _dec( const node_t * other );
    276247        void _check() const;
    277         void _strict_fail() const __attribute__((noreturn));
    278248
    279249        const node_t * node;
  • src/AST/Pass.hpp

    reef8dfb rbdfc032  
    88//
    99// Author           : Thierry Delisle
    10 // Created On       : Thu May 09 15:37:05 2019
     10// Created On       : Thu May 09 15::37::05 2019
    1111// Last Modified By :
    1212// Last Modified On :
     
    4646//
    4747// Several additional features are available through inheritance
    48 // | PureVisitor           - makes the visitor pure, it never modifies nodes in place and always
    49 //                           clones nodes it needs to make changes to
    50 // | WithConstTypeSubstitution - provides polymorphic const TypeSubstitution * typeSubs for the
    51 //                           current expression
    52 // | WithStmtsToAdd        - provides the ability to insert statements before or after the current
    53 //                           statement by adding new statements into stmtsToAddBefore or
    54 //                           stmtsToAddAfter respectively.
    55 // | WithDeclsToAdd        - provides the ability to insert declarations before or after the
    56 //                           current declarations by adding new DeclStmt into declsToAddBefore or
    57 //                           declsToAddAfter respectively.
    58 // | WithShortCircuiting   - provides the ability to skip visiting child nodes; set visit_children
    59 //                           to false in pre{visit,visit} to skip visiting children
    60 // | WithGuards            - provides the ability to save/restore data like a LIFO stack; to save,
    61 //                           call GuardValue with the variable to save, the variable will
    62 //                           automatically be restored to its previous value after the
    63 //                           corresponding postvisit/postmutate teminates.
    64 // | WithVisitorRef        - provides an pointer to the templated visitor wrapper
    65 // | WithSymbolTable       - provides symbol table functionality
    66 //
    67 // Other Special Members:
    68 // | result                - Either a method that takes no parameters or a field. If a method (or
    69 //                           callable field) get_result calls it, otherwise the value is returned.
     48// | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the
     49//                          current expression
     50// | WithStmtsToAdd       - provides the ability to insert statements before or after the current
     51//                          statement by adding new statements into stmtsToAddBefore or
     52//                          stmtsToAddAfter respectively.
     53// | WithDeclsToAdd       - provides the ability to insert declarations before or after the current
     54//                          declarations by adding new DeclStmt into declsToAddBefore or
     55//                          declsToAddAfter respectively.
     56// | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children
     57//                          to false in pre{visit,visit} to skip visiting children
     58// | WithGuards           - provides the ability to save/restore data like a LIFO stack; to save,
     59//                          call GuardValue with the variable to save, the variable will
     60//                          automatically be restored to its previous value after the corresponding
     61//                          postvisit/postmutate teminates.
     62// | WithVisitorRef       - provides an pointer to the templated visitor wrapper
     63// | WithSymbolTable      - provides symbol table functionality
    7064//-------------------------------------------------------------------------------------------------
    71 template< typename core_t >
     65template< typename pass_t >
    7266class Pass final : public ast::Visitor {
    7367public:
    74         using core_type = core_t;
    75         using type = Pass<core_t>;
    76 
    7768        /// Forward any arguments to the pass constructor
    7869        /// Propagate 'this' if necessary
    7970        template< typename... Args >
    8071        Pass( Args &&... args)
    81                 : core( std::forward<Args>( args )... )
     72                : pass( std::forward<Args>( args )... )
    8273        {
    8374                // After the pass is constructed, check if it wants the have a pointer to the wrapping visitor
    84                 type * const * visitor = __pass::visitor(core, 0);
     75                typedef Pass<pass_t> this_t;
     76                this_t * const * visitor = __pass::visitor(pass, 0);
    8577                if(visitor) {
    86                         *const_cast<type **>( visitor ) = this;
     78                        *const_cast<this_t **>( visitor ) = this;
    8779                }
    8880        }
     
    9082        virtual ~Pass() = default;
    9183
    92         /// Storage for the actual pass.
    93         core_t core;
    94 
    95         /// If the core defines a result, call it if possible, otherwise return it.
    96         inline auto get_result() -> decltype( __pass::get_result( core, '0' ) ) {
    97                 return __pass::get_result( core, '0' );
    98         }
    99 
    100         /// Construct and run a pass on a translation unit.
    101         template< typename... Args >
    102         static void run( TranslationUnit & decls, Args &&... args ) {
    103                 Pass<core_t> visitor( std::forward<Args>( args )... );
    104                 accept_all( decls, visitor );
    105         }
    106 
    107         /// Contruct and run a pass on a pointer to extract a value.
    108         template< typename node_type, typename... Args >
    109         static auto read( node_type const * node, Args&&... args ) {
    110                 Pass<core_t> visitor( std::forward<Args>( args )... );
    111                 node_type const * temp = node->accept( visitor );
    112                 assert( temp == node );
    113                 return visitor.get_result();
    114         }
    115 
    116         // Versions of the above for older compilers.
    117         template< typename... Args >
    118         static void run( TranslationUnit & decls ) {
    119                 Pass<core_t> visitor;
    120                 accept_all( decls, visitor );
    121         }
    122 
    123         template< typename node_type, typename... Args >
    124         static auto read( node_type const * node ) {
    125                 Pass<core_t> visitor;
    126                 node_type const * temp = node->accept( visitor );
    127                 assert( temp == node );
    128                 return visitor.get_result();
    129         }
     84        /// Storage for the actual pass
     85        pass_t pass;
    13086
    13187        /// Visit function declarations
     
    155111        const ast::Stmt *             visit( const ast::CatchStmt            * ) override final;
    156112        const ast::Stmt *             visit( const ast::FinallyStmt          * ) override final;
    157         const ast::Stmt *             visit( const ast::SuspendStmt          * ) override final;
    158113        const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
    159114        const ast::Decl *             visit( const ast::WithStmt             * ) override final;
     
    223178        const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
    224179
    225         template<typename core_type>
    226         friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor );
    227 
    228         bool isInFunction() const {
    229                 return inFunction;
    230         }
    231 
     180        template<typename pass_type>
     181        friend void accept_all( std::list< ptr<Decl> > & decls, Pass<pass_type>& visitor );
    232182private:
    233183
    234         bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(core, 0); return ptr ? *ptr : true; }
     184        bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(pass, 0); return ptr ? *ptr : true; }
    235185
    236186private:
    237187        const ast::Stmt * call_accept( const ast::Stmt * );
    238188        const ast::Expr * call_accept( const ast::Expr * );
    239 
    240         // requests WithStmtsToAdd directly add to this statement, as if it is a compound.
    241 
    242         const ast::Stmt * call_accept_as_compound(const ast::Stmt *);
    243189
    244190        template< typename node_t >
     
    260206        void maybe_accept(const node_t * &, child_t parent_t::* child);
    261207
    262         template<typename node_t, typename parent_t, typename child_t>
    263         void maybe_accept_as_compound(const node_t * &, child_t parent_t::* child);
    264 
    265208private:
    266209        /// Internal RAII guard for symbol table features
    267210        struct guard_symtab {
    268                 guard_symtab( Pass<core_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.core, 0); }
    269                 ~guard_symtab()                                   { __pass::symtab::leave(pass.core, 0); }
    270                 Pass<core_t> & pass;
     211                guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass, 0); }
     212                ~guard_symtab()                                   { __pass::symtab::leave(pass, 0); }
     213                Pass<pass_t> & pass;
    271214        };
    272215
    273216        /// Internal RAII guard for scope features
    274217        struct guard_scope {
    275                 guard_scope( Pass<core_t> & pass ): pass( pass ) { __pass::scope::enter(pass.core, 0); }
    276                 ~guard_scope()                                   { __pass::scope::leave(pass.core, 0); }
    277                 Pass<core_t> & pass;
    278         };
    279 
    280         /// Internal RAII guard for forall substitutions
    281         struct guard_forall_subs {
    282                 guard_forall_subs( Pass<core_t> & pass, const FunctionType * type )
    283                 : pass( pass ), type( type ) { __pass::forall::enter(pass.core, 0, type ); }
    284                 ~guard_forall_subs()         { __pass::forall::leave(pass.core, 0, type ); }
    285                 Pass<core_t> & pass;
    286                 const FunctionType * type;
     218                guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); }
     219                ~guard_scope()                                   { __pass::scope::leave(pass, 0); }
     220                Pass<pass_t> & pass;
    287221        };
    288222
    289223private:
    290224        bool inFunction = false;
    291         bool atFunctionTop = false;
    292225};
    293226
    294227/// Apply a pass to an entire translation unit
    295 template<typename core_t>
    296 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor );
    297 
    298 template<typename core_t>
    299 void accept_all( ast::TranslationUnit &, ast::Pass<core_t> & visitor );
     228template<typename pass_t>
     229void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<pass_t> & visitor );
    300230
    301231//-------------------------------------------------------------------------------------------------
     
    303233//-------------------------------------------------------------------------------------------------
    304234
    305 /// If used the visitor will always clone nodes.
    306 struct PureVisitor {};
    307 
    308 /// Keep track of the polymorphic const TypeSubstitution * typeSubs for the current expression.
     235/// Keep track of the polymorphic const TypeSubstitution * env for the current expression
    309236struct WithConstTypeSubstitution {
    310         const TypeSubstitution * typeSubs = nullptr;
     237        const TypeSubstitution * env = nullptr;
    311238};
    312239
     
    340267        };
    341268
    342         template< typename core_t>
    343         friend auto __pass::at_cleanup( core_t & core, int ) -> decltype( &core.at_cleanup );
     269        template< typename pass_t>
     270        friend auto __pass::at_cleanup( pass_t & pass, int ) -> decltype( &pass.at_cleanup );
    344271public:
    345272
     
    377304
    378305/// Used to get a pointer to the pass with its wrapped type
    379 template<typename core_t>
     306template<typename pass_t>
    380307struct WithVisitorRef {
    381         Pass<core_t> * const visitor = nullptr;
    382 
    383         bool isInFunction() const {
    384                 return visitor->isInFunction();
    385         }
     308        Pass<pass_t> * const visitor = nullptr;
    386309};
    387310
     
    390313        SymbolTable symtab;
    391314};
    392 
    393315}
    394316
     
    398320extern struct PassVisitorStats {
    399321        size_t depth = 0;
    400         Stats::Counters::MaxCounter<double> * max;
    401         Stats::Counters::AverageCounter<double> * avg;
     322        Stats::Counters::MaxCounter<double> * max = nullptr;
     323        Stats::Counters::AverageCounter<double> * avg = nullptr;
    402324} pass_visitor_stats;
    403325}
  • src/AST/Pass.impl.hpp

    reef8dfb rbdfc032  
    2020#include <unordered_map>
    2121
    22 #include "AST/TranslationUnit.hpp"
    2322#include "AST/TypeSubstitution.hpp"
    2423
     
    2625        using namespace ast; \
    2726        /* back-up the visit children */ \
    28         __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(core, 0) ); \
     27        __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
    2928        /* setup the scope for passes that want to run code at exit */ \
    30         __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (core, 0) ); \
    31         /* begin tracing memory allocation if requested by this pass */ \
    32         __pass::beginTrace( core, 0 ); \
     29        __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (pass, 0) ); \
    3330        /* call the implementation of the previsit of this pass */ \
    34         __pass::previsit( core, node, 0 );
     31        __pass::previsit( pass, node, 0 );
    3532
    3633#define VISIT( code... ) \
     
    4340#define VISIT_END( type, node ) \
    4441        /* call the implementation of the postvisit of this pass */ \
    45         auto __return = __pass::postvisit( core, node, 0 ); \
     42        auto __return = __pass::postvisit( pass, node, 0 ); \
    4643        assertf(__return, "post visit should never return null"); \
    47         /* end tracing memory allocation if requested by this pass */ \
    48         __pass::endTrace( core, 0 ); \
    4944        return __return;
    5045
     
    5853
    5954namespace ast {
    60         template<typename node_t>
    61         node_t * shallowCopy( const node_t * node );
    62 
    6355        namespace __pass {
    6456                // Check if this is either a null pointer or a pointer to an empty container
     
    6860                }
    6961
    70                 template< typename core_t, typename node_t >
    71                 static inline node_t* mutate(const node_t *node) {
    72                         return std::is_base_of<PureVisitor, core_t>::value ? ::ast::shallowCopy(node) : ::ast::mutate(node);
    73                 }
    74 
    7562                //------------------------------
    7663                template<typename it_t, template <class...> class container_t>
     
    132119        }
    133120
    134         template< typename core_t >
     121        template< typename pass_t >
    135122        template< typename node_t >
    136         auto ast::Pass< core_t >::call_accept( const node_t * node )
     123        auto ast::Pass< pass_t >::call_accept( const node_t * node )
    137124                -> typename std::enable_if<
    138125                                !std::is_base_of<ast::Expr, node_t>::value &&
     
    140127                        , decltype( node->accept(*this) )
    141128                >::type
     129
    142130        {
    143131                __pedantic_pass_assert( __visit_children() );
    144                 __pedantic_pass_assert( node );
     132                __pedantic_pass_assert( expr );
    145133
    146134                static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
     
    150138        }
    151139
    152         template< typename core_t >
    153         const ast::Expr * ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
     140        template< typename pass_t >
     141        const ast::Expr * ast::Pass< pass_t >::call_accept( const ast::Expr * expr ) {
    154142                __pedantic_pass_assert( __visit_children() );
    155143                __pedantic_pass_assert( expr );
    156144
    157                 const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 );
    158                 if ( typeSubs_ptr && expr->env ) {
    159                         *typeSubs_ptr = expr->env;
     145                const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
     146                if ( env_ptr && expr->env ) {
     147                        *env_ptr = expr->env;
    160148                }
    161149
     
    163151        }
    164152
    165         template< typename core_t >
    166         const ast::Stmt * ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
     153        template< typename pass_t >
     154        const ast::Stmt * ast::Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
    167155                __pedantic_pass_assert( __visit_children() );
    168156                __pedantic_pass_assert( stmt );
    169157
    170                 return stmt->accept( *this );
    171         }
    172 
    173         template< typename core_t >
    174         const ast::Stmt * ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) {
    175                 __pedantic_pass_assert( __visit_children() );
    176                 __pedantic_pass_assert( stmt );
    177 
    178158                // add a few useful symbols to the scope
    179159                using __pass::empty;
    180160
    181161                // get the stmts/decls that will need to be spliced in
    182                 auto stmts_before = __pass::stmtsToAddBefore( core, 0);
    183                 auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
    184                 auto decls_before = __pass::declsToAddBefore( core, 0);
    185                 auto decls_after  = __pass::declsToAddAfter ( core, 0);
     162                auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
     163                auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
     164                auto decls_before = __pass::declsToAddBefore( pass, 0);
     165                auto decls_after  = __pass::declsToAddAfter ( pass, 0);
    186166
    187167                // These may be modified by subnode but most be restored once we exit this statemnet.
    188                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::typeSubs( core, 0 ) );
     168                ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( pass, 0) );
    189169                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    190170                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    222202        }
    223203
    224         template< typename core_t >
     204        template< typename pass_t >
    225205        template< template <class...> class container_t >
    226         container_t< ptr<Stmt> > ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
     206        container_t< ptr<Stmt> > ast::Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    227207                __pedantic_pass_assert( __visit_children() );
    228208                if( statements.empty() ) return {};
     
    235215
    236216                // get the stmts/decls that will need to be spliced in
    237                 auto stmts_before = __pass::stmtsToAddBefore( core, 0);
    238                 auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
    239                 auto decls_before = __pass::declsToAddBefore( core, 0);
    240                 auto decls_after  = __pass::declsToAddAfter ( core, 0);
     217                auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
     218                auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
     219                auto decls_before = __pass::declsToAddBefore( pass, 0);
     220                auto decls_after  = __pass::declsToAddAfter ( pass, 0);
    241221
    242222                // These may be modified by subnode but most be restored once we exit this statemnet.
     
    288268        }
    289269
    290         template< typename core_t >
     270        template< typename pass_t >
    291271        template< template <class...> class container_t, typename node_t >
    292         container_t< ast::ptr<node_t> > ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
     272        container_t< ast::ptr<node_t> > ast::Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
    293273                __pedantic_pass_assert( __visit_children() );
    294274                if( container.empty() ) return {};
     
    319299        }
    320300
    321         template< typename core_t >
     301        template< typename pass_t >
    322302        template<typename node_t, typename parent_t, typename child_t>
    323         void ast::Pass< core_t >::maybe_accept(
     303        void ast::Pass< pass_t >::maybe_accept(
    324304                const node_t * & parent,
    325305                child_t parent_t::*child
     
    337317
    338318                if( __pass::differs(old_val, new_val) ) {
    339                         auto new_parent = __pass::mutate<core_t>(parent);
    340                         new_parent->*child = new_val;
    341                         parent = new_parent;
    342                 }
    343         }
    344 
    345         template< typename core_t >
    346         template<typename node_t, typename parent_t, typename child_t>
    347         void ast::Pass< core_t >::maybe_accept_as_compound(
    348                 const node_t * & parent,
    349                 child_t parent_t::*child
    350         ) {
    351                 static_assert( std::is_base_of<parent_t, node_t>::value, "Error deducing member object" );
    352 
    353                 if(__pass::skip(parent->*child)) return;
    354                 const auto & old_val = __pass::get(parent->*child, 0);
    355 
    356                 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
    357 
    358                 auto new_val = call_accept_as_compound( old_val );
    359 
    360                 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR");
    361 
    362                 if( __pass::differs(old_val, new_val) ) {
    363                         auto new_parent = __pass::mutate<core_t>(parent);
     319                        auto new_parent = mutate(parent);
    364320                        new_parent->*child = new_val;
    365321                        parent = new_parent;
     
    377333//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    378334
    379 template< typename core_t >
    380 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< core_t > & visitor ) {
     335template< typename pass_t >
     336inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
    381337        // We are going to aggregate errors for all these statements
    382338        SemanticErrorException errors;
     
    386342
    387343        // get the stmts/decls that will need to be spliced in
    388         auto decls_before = __pass::declsToAddBefore( visitor.core, 0);
    389         auto decls_after  = __pass::declsToAddAfter ( visitor.core, 0);
     344        auto decls_before = __pass::declsToAddBefore( visitor.pass, 0);
     345        auto decls_after  = __pass::declsToAddAfter ( visitor.pass, 0);
    390346
    391347        // update pass statitistics
     
    407363                }
    408364                catch( SemanticErrorException &e ) {
    409                         if (__pass::on_error (visitor.core, *i, 0))
    410                                 errors.append( e );
     365                        errors.append( e );
    411366                }
    412367
     
    416371        pass_visitor_stats.depth--;
    417372        if ( !errors.isEmpty() ) { throw errors; }
    418 }
    419 
    420 template< typename core_t >
    421 inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) {
    422         return ast::accept_all( unit.decls, visitor );
    423373}
    424374
     
    442392//--------------------------------------------------------------------------
    443393// ObjectDecl
    444 template< typename core_t >
    445 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::ObjectDecl * node ) {
     394template< typename pass_t >
     395const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
    446396        VISIT_START( node );
    447397
     
    456406        )
    457407
    458         __pass::symtab::addId( core, 0, node );
     408        __pass::symtab::addId( pass, 0, node );
    459409
    460410        VISIT_END( DeclWithType, node );
     
    463413//--------------------------------------------------------------------------
    464414// FunctionDecl
    465 template< typename core_t >
    466 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::FunctionDecl * node ) {
    467         VISIT_START( node );
    468 
    469         __pass::symtab::addId( core, 0, node );
     415template< typename pass_t >
     416const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {
     417        VISIT_START( node );
     418
     419        __pass::symtab::addId( pass, 0, node );
    470420
    471421        VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
     
    475425                // shadow with exprs and not the other way around.
    476426                guard_symtab guard { *this };
    477                 __pass::symtab::addWith( core, 0, node->withExprs, node );
     427                __pass::symtab::addWith( pass, 0, node->withExprs, node );
    478428                {
    479429                        guard_symtab guard { *this };
    480430                        // implicit add __func__ identifier as specified in the C manual 6.4.2.2
    481                         static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{
    482                                 CodeLocation{}, "__func__",
    483                                 new ast::ArrayType{
    484                                         new ast::BasicType{ ast::BasicType::Char, ast::CV::Const },
     431                        static ast::ObjectDecl func(
     432                                node->location, "__func__",
     433                                new ast::ArrayType(
     434                                        new ast::BasicType( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),
    485435                                        nullptr, VariableLen, DynamicDim
    486                                 }
    487                         } };
    488                         __pass::symtab::addId( core, 0, func );
     436                                )
     437                        );
     438                        __pass::symtab::addId( pass, 0, &func );
    489439                        VISIT(
    490                                 // parameter declarations
    491                                 maybe_accept( node, &FunctionDecl::params );
    492                                 maybe_accept( node, &FunctionDecl::returns );
    493                                 // type params and assertions
    494                                 maybe_accept( node, &FunctionDecl::type_params );
    495                                 maybe_accept( node, &FunctionDecl::assertions );
    496                                 // First remember that we are now within a function.
     440                                maybe_accept( node, &FunctionDecl::type );
     441                                // function body needs to have the same scope as parameters - CompoundStmt will not enter
     442                                // a new scope if inFunction is true
    497443                                ValueGuard< bool > oldInFunction( inFunction );
    498444                                inFunction = true;
    499                                 // The function body needs to have the same scope as parameters.
    500                                 // A CompoundStmt will not enter a new scope if atFunctionTop is true.
    501                                 ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
    502                                 atFunctionTop = true;
    503445                                maybe_accept( node, &FunctionDecl::stmts );
    504446                                maybe_accept( node, &FunctionDecl::attributes );
     
    512454//--------------------------------------------------------------------------
    513455// StructDecl
    514 template< typename core_t >
    515 const ast::Decl * ast::Pass< core_t >::visit( const ast::StructDecl * node ) {
     456template< typename pass_t >
     457const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {
    516458        VISIT_START( node );
    517459
    518460        // make up a forward declaration and add it before processing the members
    519461        // needs to be on the heap because addStruct saves the pointer
    520         __pass::symtab::addStructFwd( core, 0, node );
     462        __pass::symtab::addStructFwd( pass, 0, node );
    521463
    522464        VISIT({
     
    527469
    528470        // this addition replaces the forward declaration
    529         __pass::symtab::addStruct( core, 0, node );
     471        __pass::symtab::addStruct( pass, 0, node );
    530472
    531473        VISIT_END( Decl, node );
     
    534476//--------------------------------------------------------------------------
    535477// UnionDecl
    536 template< typename core_t >
    537 const ast::Decl * ast::Pass< core_t >::visit( const ast::UnionDecl * node ) {
     478template< typename pass_t >
     479const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {
    538480        VISIT_START( node );
    539481
    540482        // make up a forward declaration and add it before processing the members
    541         __pass::symtab::addUnionFwd( core, 0, node );
     483        __pass::symtab::addUnionFwd( pass, 0, node );
    542484
    543485        VISIT({
     
    547489        })
    548490
    549         __pass::symtab::addUnion( core, 0, node );
     491        __pass::symtab::addUnion( pass, 0, node );
    550492
    551493        VISIT_END( Decl, node );
     
    554496//--------------------------------------------------------------------------
    555497// EnumDecl
    556 template< typename core_t >
    557 const ast::Decl * ast::Pass< core_t >::visit( const ast::EnumDecl * node ) {
    558         VISIT_START( node );
    559 
    560         __pass::symtab::addEnum( core, 0, node );
     498template< typename pass_t >
     499const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {
     500        VISIT_START( node );
     501
     502        __pass::symtab::addEnum( pass, 0, node );
    561503
    562504        VISIT(
     
    571513//--------------------------------------------------------------------------
    572514// TraitDecl
    573 template< typename core_t >
    574 const ast::Decl * ast::Pass< core_t >::visit( const ast::TraitDecl * node ) {
     515template< typename pass_t >
     516const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {
    575517        VISIT_START( node );
    576518
     
    581523        })
    582524
    583         __pass::symtab::addTrait( core, 0, node );
     525        __pass::symtab::addTrait( pass, 0, node );
    584526
    585527        VISIT_END( Decl, node );
     
    588530//--------------------------------------------------------------------------
    589531// TypeDecl
    590 template< typename core_t >
    591 const ast::Decl * ast::Pass< core_t >::visit( const ast::TypeDecl * node ) {
     532template< typename pass_t >
     533const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {
    592534        VISIT_START( node );
    593535
    594536        VISIT({
    595537                guard_symtab guard { *this };
     538                maybe_accept( node, &TypeDecl::params );
    596539                maybe_accept( node, &TypeDecl::base   );
    597540        })
     
    600543        // note that assertions come after the type is added to the symtab, since they are not part of the type proper
    601544        // and may depend on the type itself
    602         __pass::symtab::addType( core, 0, node );
     545        __pass::symtab::addType( pass, 0, node );
    603546
    604547        VISIT(
     
    616559//--------------------------------------------------------------------------
    617560// TypedefDecl
    618 template< typename core_t >
    619 const ast::Decl * ast::Pass< core_t >::visit( const ast::TypedefDecl * node ) {
     561template< typename pass_t >
     562const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {
    620563        VISIT_START( node );
    621564
    622565        VISIT({
    623566                guard_symtab guard { *this };
     567                maybe_accept( node, &TypedefDecl::params );
    624568                maybe_accept( node, &TypedefDecl::base   );
    625569        })
    626570
    627         __pass::symtab::addType( core, 0, node );
     571        __pass::symtab::addType( pass, 0, node );
    628572
    629573        VISIT( maybe_accept( node, &TypedefDecl::assertions ); )
     
    634578//--------------------------------------------------------------------------
    635579// AsmDecl
    636 template< typename core_t >
    637 const ast::AsmDecl * ast::Pass< core_t >::visit( const ast::AsmDecl * node ) {
     580template< typename pass_t >
     581const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {
    638582        VISIT_START( node );
    639583
     
    647591//--------------------------------------------------------------------------
    648592// StaticAssertDecl
    649 template< typename core_t >
    650 const ast::StaticAssertDecl * ast::Pass< core_t >::visit( const ast::StaticAssertDecl * node ) {
     593template< typename pass_t >
     594const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {
    651595        VISIT_START( node );
    652596
     
    661605//--------------------------------------------------------------------------
    662606// CompoundStmt
    663 template< typename core_t >
    664 const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) {
    665         VISIT_START( node );
    666         VISIT(
    667                 // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result.
    668                 auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() {
    669                         if ( enterScope ) {
    670                                 __pass::symtab::enter(core, 0);
    671                                 __pass::scope::enter(core, 0);
    672                         }
    673                 }, [this, leaveScope = !this->atFunctionTop]() {
    674                         if ( leaveScope ) {
    675                                 __pass::symtab::leave(core, 0);
    676                                 __pass::scope::leave(core, 0);
    677                         }
     607template< typename pass_t >
     608const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {
     609        VISIT_START( node );
     610        VISIT({
     611                // do not enter a new scope if inFunction is true - needs to check old state before the assignment
     612                auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {
     613                        if ( ! inFunction ) __pass::symtab::enter(pass, 0);
     614                }, [this, inFunction = this->inFunction]() {
     615                        if ( ! inFunction ) __pass::symtab::leave(pass, 0);
    678616                });
    679                 ValueGuard< bool > guard2( atFunctionTop );
    680                 atFunctionTop = false;
     617                ValueGuard< bool > guard2( inFunction );
    681618                guard_scope guard3 { *this };
     619                inFunction = false;
    682620                maybe_accept( node, &CompoundStmt::kids );
    683         )
     621        })
    684622        VISIT_END( CompoundStmt, node );
    685623}
     
    687625//--------------------------------------------------------------------------
    688626// ExprStmt
    689 template< typename core_t >
    690 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ExprStmt * node ) {
     627template< typename pass_t >
     628const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ExprStmt * node ) {
    691629        VISIT_START( node );
    692630
     
    700638//--------------------------------------------------------------------------
    701639// AsmStmt
    702 template< typename core_t >
    703 const ast::Stmt * ast::Pass< core_t >::visit( const ast::AsmStmt * node ) {
     640template< typename pass_t >
     641const ast::Stmt * ast::Pass< pass_t >::visit( const ast::AsmStmt * node ) {
    704642        VISIT_START( node )
    705643
     
    716654//--------------------------------------------------------------------------
    717655// DirectiveStmt
    718 template< typename core_t >
    719 const ast::Stmt * ast::Pass< core_t >::visit( const ast::DirectiveStmt * node ) {
     656template< typename pass_t >
     657const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DirectiveStmt * node ) {
    720658        VISIT_START( node )
    721659
     
    725663//--------------------------------------------------------------------------
    726664// IfStmt
    727 template< typename core_t >
    728 const ast::Stmt * ast::Pass< core_t >::visit( const ast::IfStmt * node ) {
     665template< typename pass_t >
     666const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {
    729667        VISIT_START( node );
    730668
     
    734672                maybe_accept( node, &IfStmt::inits    );
    735673                maybe_accept( node, &IfStmt::cond     );
    736                 maybe_accept_as_compound( node, &IfStmt::thenPart );
    737                 maybe_accept_as_compound( node, &IfStmt::elsePart );
     674                maybe_accept( node, &IfStmt::thenPart );
     675                maybe_accept( node, &IfStmt::elsePart );
    738676        })
    739677
     
    743681//--------------------------------------------------------------------------
    744682// WhileStmt
    745 template< typename core_t >
    746 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileStmt * node ) {
     683template< typename pass_t >
     684const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WhileStmt * node ) {
    747685        VISIT_START( node );
    748686
     
    752690                maybe_accept( node, &WhileStmt::inits );
    753691                maybe_accept( node, &WhileStmt::cond  );
    754                 maybe_accept_as_compound( node, &WhileStmt::body  );
     692                maybe_accept( node, &WhileStmt::body  );
    755693        })
    756694
     
    760698//--------------------------------------------------------------------------
    761699// ForStmt
    762 template< typename core_t >
    763 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ForStmt * node ) {
     700template< typename pass_t >
     701const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ForStmt * node ) {
    764702        VISIT_START( node );
    765703
     
    767705                // for statements introduce a level of scope (for the initialization)
    768706                guard_symtab guard { *this };
    769                 // xxx - old ast does not create WithStmtsToAdd scope for loop inits. should revisit this later.
    770707                maybe_accept( node, &ForStmt::inits );
    771708                maybe_accept( node, &ForStmt::cond  );
    772709                maybe_accept( node, &ForStmt::inc   );
    773                 maybe_accept_as_compound( node, &ForStmt::body  );
     710                maybe_accept( node, &ForStmt::body  );
    774711        })
    775712
     
    779716//--------------------------------------------------------------------------
    780717// SwitchStmt
    781 template< typename core_t >
    782 const ast::Stmt * ast::Pass< core_t >::visit( const ast::SwitchStmt * node ) {
     718template< typename pass_t >
     719const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SwitchStmt * node ) {
    783720        VISIT_START( node );
    784721
     
    793730//--------------------------------------------------------------------------
    794731// CaseStmt
    795 template< typename core_t >
    796 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CaseStmt * node ) {
     732template< typename pass_t >
     733const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CaseStmt * node ) {
    797734        VISIT_START( node );
    798735
     
    807744//--------------------------------------------------------------------------
    808745// BranchStmt
    809 template< typename core_t >
    810 const ast::Stmt * ast::Pass< core_t >::visit( const ast::BranchStmt * node ) {
     746template< typename pass_t >
     747const ast::Stmt * ast::Pass< pass_t >::visit( const ast::BranchStmt * node ) {
    811748        VISIT_START( node );
    812749        VISIT_END( Stmt, node );
     
    815752//--------------------------------------------------------------------------
    816753// ReturnStmt
    817 template< typename core_t >
    818 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ReturnStmt * node ) {
     754template< typename pass_t >
     755const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ReturnStmt * node ) {
    819756        VISIT_START( node );
    820757
     
    828765//--------------------------------------------------------------------------
    829766// ThrowStmt
    830 template< typename core_t >
    831 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ThrowStmt * node ) {
     767template< typename pass_t >
     768const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ThrowStmt * node ) {
    832769        VISIT_START( node );
    833770
     
    842779//--------------------------------------------------------------------------
    843780// TryStmt
    844 template< typename core_t >
    845 const ast::Stmt * ast::Pass< core_t >::visit( const ast::TryStmt * node ) {
     781template< typename pass_t >
     782const ast::Stmt * ast::Pass< pass_t >::visit( const ast::TryStmt * node ) {
    846783        VISIT_START( node );
    847784
     
    857794//--------------------------------------------------------------------------
    858795// CatchStmt
    859 template< typename core_t >
    860 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CatchStmt * node ) {
     796template< typename pass_t >
     797const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {
    861798        VISIT_START( node );
    862799
     
    866803                maybe_accept( node, &CatchStmt::decl );
    867804                maybe_accept( node, &CatchStmt::cond );
    868                 maybe_accept_as_compound( node, &CatchStmt::body );
     805                maybe_accept( node, &CatchStmt::body );
    869806        })
    870807
     
    874811//--------------------------------------------------------------------------
    875812// FinallyStmt
    876 template< typename core_t >
    877 const ast::Stmt * ast::Pass< core_t >::visit( const ast::FinallyStmt * node ) {
     813template< typename pass_t >
     814const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {
    878815        VISIT_START( node );
    879816
     
    886823
    887824//--------------------------------------------------------------------------
    888 // FinallyStmt
    889 template< typename core_t >
    890 const ast::Stmt * ast::Pass< core_t >::visit( const ast::SuspendStmt * node ) {
    891         VISIT_START( node );
    892 
    893         VISIT(
    894                 maybe_accept( node, &SuspendStmt::then   );
    895         )
    896 
    897         VISIT_END( Stmt, node );
    898 }
    899 
    900 //--------------------------------------------------------------------------
    901825// WaitForStmt
    902 template< typename core_t >
    903 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitForStmt * node ) {
     826template< typename pass_t >
     827const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {
    904828        VISIT_START( node );
    905829                // for( auto & clause : node->clauses ) {
     
    938862
    939863                if(mutated) {
    940                         auto n = __pass::mutate<core_t>(node);
     864                        auto n = mutate(node);
    941865                        n->clauses = std::move( new_clauses );
    942866                        node = n;
     
    948872                        auto nval = call_accept( node->field ); \
    949873                        if(nval != node->field ) { \
    950                                 auto nparent = __pass::mutate<core_t>(node); \
     874                                auto nparent = mutate(node); \
    951875                                nparent->field = nval; \
    952876                                node = nparent; \
     
    969893//--------------------------------------------------------------------------
    970894// WithStmt
    971 template< typename core_t >
    972 const ast::Decl * ast::Pass< core_t >::visit( const ast::WithStmt * node ) {
     895template< typename pass_t >
     896const ast::Decl * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {
    973897        VISIT_START( node );
    974898
     
    978902                        // catch statements introduce a level of scope (for the caught exception)
    979903                        guard_symtab guard { *this };
    980                         __pass::symtab::addWith( core, 0, node->exprs, node );
     904                        __pass::symtab::addWith( pass, 0, node->exprs, node );
    981905                        maybe_accept( node, &WithStmt::stmt );
    982906                }
     
    987911//--------------------------------------------------------------------------
    988912// NullStmt
    989 template< typename core_t >
    990 const ast::NullStmt * ast::Pass< core_t >::visit( const ast::NullStmt * node ) {
     913template< typename pass_t >
     914const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {
    991915        VISIT_START( node );
    992916        VISIT_END( NullStmt, node );
     
    995919//--------------------------------------------------------------------------
    996920// DeclStmt
    997 template< typename core_t >
    998 const ast::Stmt * ast::Pass< core_t >::visit( const ast::DeclStmt * node ) {
     921template< typename pass_t >
     922const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {
    999923        VISIT_START( node );
    1000924
     
    1008932//--------------------------------------------------------------------------
    1009933// ImplicitCtorDtorStmt
    1010 template< typename core_t >
    1011 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
     934template< typename pass_t >
     935const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
    1012936        VISIT_START( node );
    1013937
    1014938        // For now this isn't visited, it is unclear if this causes problem
    1015939        // if all tests are known to pass, remove this code
    1016         VISIT(
    1017                 maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
    1018         )
     940        // VISIT(
     941        //      maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
     942        // )
    1019943
    1020944        VISIT_END( Stmt, node );
     
    1023947//--------------------------------------------------------------------------
    1024948// ApplicationExpr
    1025 template< typename core_t >
    1026 const ast::Expr * ast::Pass< core_t >::visit( const ast::ApplicationExpr * node ) {
     949template< typename pass_t >
     950const ast::Expr * ast::Pass< pass_t >::visit( const ast::ApplicationExpr * node ) {
    1027951        VISIT_START( node );
    1028952
     
    1041965//--------------------------------------------------------------------------
    1042966// UntypedExpr
    1043 template< typename core_t >
    1044 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedExpr * node ) {
     967template< typename pass_t >
     968const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedExpr * node ) {
    1045969        VISIT_START( node );
    1046970
     
    1059983//--------------------------------------------------------------------------
    1060984// NameExpr
    1061 template< typename core_t >
    1062 const ast::Expr * ast::Pass< core_t >::visit( const ast::NameExpr * node ) {
     985template< typename pass_t >
     986const ast::Expr * ast::Pass< pass_t >::visit( const ast::NameExpr * node ) {
    1063987        VISIT_START( node );
    1064988
     
    1073997//--------------------------------------------------------------------------
    1074998// CastExpr
    1075 template< typename core_t >
    1076 const ast::Expr * ast::Pass< core_t >::visit( const ast::CastExpr * node ) {
     999template< typename pass_t >
     1000const ast::Expr * ast::Pass< pass_t >::visit( const ast::CastExpr * node ) {
    10771001        VISIT_START( node );
    10781002
     
    10891013//--------------------------------------------------------------------------
    10901014// KeywordCastExpr
    1091 template< typename core_t >
    1092 const ast::Expr * ast::Pass< core_t >::visit( const ast::KeywordCastExpr * node ) {
     1015template< typename pass_t >
     1016const ast::Expr * ast::Pass< pass_t >::visit( const ast::KeywordCastExpr * node ) {
    10931017        VISIT_START( node );
    10941018
     
    11051029//--------------------------------------------------------------------------
    11061030// VirtualCastExpr
    1107 template< typename core_t >
    1108 const ast::Expr * ast::Pass< core_t >::visit( const ast::VirtualCastExpr * node ) {
     1031template< typename pass_t >
     1032const ast::Expr * ast::Pass< pass_t >::visit( const ast::VirtualCastExpr * node ) {
    11091033        VISIT_START( node );
    11101034
     
    11211045//--------------------------------------------------------------------------
    11221046// AddressExpr
    1123 template< typename core_t >
    1124 const ast::Expr * ast::Pass< core_t >::visit( const ast::AddressExpr * node ) {
     1047template< typename pass_t >
     1048const ast::Expr * ast::Pass< pass_t >::visit( const ast::AddressExpr * node ) {
    11251049        VISIT_START( node );
    11261050
     
    11371061//--------------------------------------------------------------------------
    11381062// LabelAddressExpr
    1139 template< typename core_t >
    1140 const ast::Expr * ast::Pass< core_t >::visit( const ast::LabelAddressExpr * node ) {
     1063template< typename pass_t >
     1064const ast::Expr * ast::Pass< pass_t >::visit( const ast::LabelAddressExpr * node ) {
    11411065        VISIT_START( node );
    11421066
     
    11511075//--------------------------------------------------------------------------
    11521076// UntypedMemberExpr
    1153 template< typename core_t >
    1154 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedMemberExpr * node ) {
     1077template< typename pass_t >
     1078const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedMemberExpr * node ) {
    11551079        VISIT_START( node );
    11561080
     
    11681092//--------------------------------------------------------------------------
    11691093// MemberExpr
    1170 template< typename core_t >
    1171 const ast::Expr * ast::Pass< core_t >::visit( const ast::MemberExpr * node ) {
     1094template< typename pass_t >
     1095const ast::Expr * ast::Pass< pass_t >::visit( const ast::MemberExpr * node ) {
    11721096        VISIT_START( node );
    11731097
     
    11841108//--------------------------------------------------------------------------
    11851109// VariableExpr
    1186 template< typename core_t >
    1187 const ast::Expr * ast::Pass< core_t >::visit( const ast::VariableExpr * node ) {
     1110template< typename pass_t >
     1111const ast::Expr * ast::Pass< pass_t >::visit( const ast::VariableExpr * node ) {
    11881112        VISIT_START( node );
    11891113
     
    11981122//--------------------------------------------------------------------------
    11991123// ConstantExpr
    1200 template< typename core_t >
    1201 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstantExpr * node ) {
     1124template< typename pass_t >
     1125const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstantExpr * node ) {
    12021126        VISIT_START( node );
    12031127
     
    12121136//--------------------------------------------------------------------------
    12131137// SizeofExpr
    1214 template< typename core_t >
    1215 const ast::Expr * ast::Pass< core_t >::visit( const ast::SizeofExpr * node ) {
     1138template< typename pass_t >
     1139const ast::Expr * ast::Pass< pass_t >::visit( const ast::SizeofExpr * node ) {
    12161140        VISIT_START( node );
    12171141
     
    12321156//--------------------------------------------------------------------------
    12331157// AlignofExpr
    1234 template< typename core_t >
    1235 const ast::Expr * ast::Pass< core_t >::visit( const ast::AlignofExpr * node ) {
     1158template< typename pass_t >
     1159const ast::Expr * ast::Pass< pass_t >::visit( const ast::AlignofExpr * node ) {
    12361160        VISIT_START( node );
    12371161
     
    12521176//--------------------------------------------------------------------------
    12531177// UntypedOffsetofExpr
    1254 template< typename core_t >
    1255 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedOffsetofExpr * node ) {
     1178template< typename pass_t >
     1179const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedOffsetofExpr * node ) {
    12561180        VISIT_START( node );
    12571181
     
    12681192//--------------------------------------------------------------------------
    12691193// OffsetofExpr
    1270 template< typename core_t >
    1271 const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetofExpr * node ) {
     1194template< typename pass_t >
     1195const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetofExpr * node ) {
    12721196        VISIT_START( node );
    12731197
     
    12841208//--------------------------------------------------------------------------
    12851209// OffsetPackExpr
    1286 template< typename core_t >
    1287 const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetPackExpr * node ) {
     1210template< typename pass_t >
     1211const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetPackExpr * node ) {
    12881212        VISIT_START( node );
    12891213
     
    13001224//--------------------------------------------------------------------------
    13011225// LogicalExpr
    1302 template< typename core_t >
    1303 const ast::Expr * ast::Pass< core_t >::visit( const ast::LogicalExpr * node ) {
     1226template< typename pass_t >
     1227const ast::Expr * ast::Pass< pass_t >::visit( const ast::LogicalExpr * node ) {
    13041228        VISIT_START( node );
    13051229
     
    13171241//--------------------------------------------------------------------------
    13181242// ConditionalExpr
    1319 template< typename core_t >
    1320 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConditionalExpr * node ) {
     1243template< typename pass_t >
     1244const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConditionalExpr * node ) {
    13211245        VISIT_START( node );
    13221246
     
    13351259//--------------------------------------------------------------------------
    13361260// CommaExpr
    1337 template< typename core_t >
    1338 const ast::Expr * ast::Pass< core_t >::visit( const ast::CommaExpr * node ) {
     1261template< typename pass_t >
     1262const ast::Expr * ast::Pass< pass_t >::visit( const ast::CommaExpr * node ) {
    13391263        VISIT_START( node );
    13401264
     
    13521276//--------------------------------------------------------------------------
    13531277// TypeExpr
    1354 template< typename core_t >
    1355 const ast::Expr * ast::Pass< core_t >::visit( const ast::TypeExpr * node ) {
     1278template< typename pass_t >
     1279const ast::Expr * ast::Pass< pass_t >::visit( const ast::TypeExpr * node ) {
    13561280        VISIT_START( node );
    13571281
     
    13681292//--------------------------------------------------------------------------
    13691293// AsmExpr
    1370 template< typename core_t >
    1371 const ast::Expr * ast::Pass< core_t >::visit( const ast::AsmExpr * node ) {
     1294template< typename pass_t >
     1295const ast::Expr * ast::Pass< pass_t >::visit( const ast::AsmExpr * node ) {
    13721296        VISIT_START( node );
    13731297
     
    13851309//--------------------------------------------------------------------------
    13861310// ImplicitCopyCtorExpr
    1387 template< typename core_t >
    1388 const ast::Expr * ast::Pass< core_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
     1311template< typename pass_t >
     1312const ast::Expr * ast::Pass< pass_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
    13891313        VISIT_START( node );
    13901314
     
    14011325//--------------------------------------------------------------------------
    14021326// ConstructorExpr
    1403 template< typename core_t >
    1404 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstructorExpr * node ) {
     1327template< typename pass_t >
     1328const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstructorExpr * node ) {
    14051329        VISIT_START( node );
    14061330
     
    14171341//--------------------------------------------------------------------------
    14181342// CompoundLiteralExpr
    1419 template< typename core_t >
    1420 const ast::Expr * ast::Pass< core_t >::visit( const ast::CompoundLiteralExpr * node ) {
     1343template< typename pass_t >
     1344const ast::Expr * ast::Pass< pass_t >::visit( const ast::CompoundLiteralExpr * node ) {
    14211345        VISIT_START( node );
    14221346
     
    14331357//--------------------------------------------------------------------------
    14341358// RangeExpr
    1435 template< typename core_t >
    1436 const ast::Expr * ast::Pass< core_t >::visit( const ast::RangeExpr * node ) {
     1359template< typename pass_t >
     1360const ast::Expr * ast::Pass< pass_t >::visit( const ast::RangeExpr * node ) {
    14371361        VISIT_START( node );
    14381362
     
    14501374//--------------------------------------------------------------------------
    14511375// UntypedTupleExpr
    1452 template< typename core_t >
    1453 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedTupleExpr * node ) {
     1376template< typename pass_t >
     1377const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedTupleExpr * node ) {
    14541378        VISIT_START( node );
    14551379
     
    14661390//--------------------------------------------------------------------------
    14671391// TupleExpr
    1468 template< typename core_t >
    1469 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleExpr * node ) {
     1392template< typename pass_t >
     1393const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleExpr * node ) {
    14701394        VISIT_START( node );
    14711395
     
    14821406//--------------------------------------------------------------------------
    14831407// TupleIndexExpr
    1484 template< typename core_t >
    1485 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleIndexExpr * node ) {
     1408template< typename pass_t >
     1409const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleIndexExpr * node ) {
    14861410        VISIT_START( node );
    14871411
     
    14981422//--------------------------------------------------------------------------
    14991423// TupleAssignExpr
    1500 template< typename core_t >
    1501 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleAssignExpr * node ) {
     1424template< typename pass_t >
     1425const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleAssignExpr * node ) {
    15021426        VISIT_START( node );
    15031427
     
    15141438//--------------------------------------------------------------------------
    15151439// StmtExpr
    1516 template< typename core_t >
    1517 const ast::Expr * ast::Pass< core_t >::visit( const ast::StmtExpr * node ) {
     1440template< typename pass_t >
     1441const ast::Expr * ast::Pass< pass_t >::visit( const ast::StmtExpr * node ) {
    15181442        VISIT_START( node );
    15191443
    15201444        VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr
    15211445                // get the stmts that will need to be spliced in
    1522                 auto stmts_before = __pass::stmtsToAddBefore( core, 0);
    1523                 auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
     1446                auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
     1447                auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
    15241448
    15251449                // These may be modified by subnode but most be restored once we exit this statemnet.
    1526                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::typeSubs( core, 0 ) );
     1450                ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( pass, 0) );
    15271451                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    15281452                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    15421466//--------------------------------------------------------------------------
    15431467// UniqueExpr
    1544 template< typename core_t >
    1545 const ast::Expr * ast::Pass< core_t >::visit( const ast::UniqueExpr * node ) {
     1468template< typename pass_t >
     1469const ast::Expr * ast::Pass< pass_t >::visit( const ast::UniqueExpr * node ) {
    15461470        VISIT_START( node );
    15471471
     
    15581482//--------------------------------------------------------------------------
    15591483// UntypedInitExpr
    1560 template< typename core_t >
    1561 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedInitExpr * node ) {
     1484template< typename pass_t >
     1485const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedInitExpr * node ) {
    15621486        VISIT_START( node );
    15631487
     
    15751499//--------------------------------------------------------------------------
    15761500// InitExpr
    1577 template< typename core_t >
    1578 const ast::Expr * ast::Pass< core_t >::visit( const ast::InitExpr * node ) {
     1501template< typename pass_t >
     1502const ast::Expr * ast::Pass< pass_t >::visit( const ast::InitExpr * node ) {
    15791503        VISIT_START( node );
    15801504
     
    15921516//--------------------------------------------------------------------------
    15931517// DeletedExpr
    1594 template< typename core_t >
    1595 const ast::Expr * ast::Pass< core_t >::visit( const ast::DeletedExpr * node ) {
     1518template< typename pass_t >
     1519const ast::Expr * ast::Pass< pass_t >::visit( const ast::DeletedExpr * node ) {
    15961520        VISIT_START( node );
    15971521
     
    16091533//--------------------------------------------------------------------------
    16101534// DefaultArgExpr
    1611 template< typename core_t >
    1612 const ast::Expr * ast::Pass< core_t >::visit( const ast::DefaultArgExpr * node ) {
     1535template< typename pass_t >
     1536const ast::Expr * ast::Pass< pass_t >::visit( const ast::DefaultArgExpr * node ) {
    16131537        VISIT_START( node );
    16141538
     
    16251549//--------------------------------------------------------------------------
    16261550// GenericExpr
    1627 template< typename core_t >
    1628 const ast::Expr * ast::Pass< core_t >::visit( const ast::GenericExpr * node ) {
     1551template< typename pass_t >
     1552const ast::Expr * ast::Pass< pass_t >::visit( const ast::GenericExpr * node ) {
    16291553        VISIT_START( node );
    16301554
     
    16541578
    16551579                if(mutated) {
    1656                         auto n = __pass::mutate<core_t>(node);
     1580                        auto n = mutate(node);
    16571581                        n->associations = std::move( new_kids );
    16581582                        node = n;
     
    16651589//--------------------------------------------------------------------------
    16661590// VoidType
    1667 template< typename core_t >
    1668 const ast::Type * ast::Pass< core_t >::visit( const ast::VoidType * node ) {
     1591template< typename pass_t >
     1592const ast::Type * ast::Pass< pass_t >::visit( const ast::VoidType * node ) {
    16691593        VISIT_START( node );
    16701594
     
    16741598//--------------------------------------------------------------------------
    16751599// BasicType
    1676 template< typename core_t >
    1677 const ast::Type * ast::Pass< core_t >::visit( const ast::BasicType * node ) {
     1600template< typename pass_t >
     1601const ast::Type * ast::Pass< pass_t >::visit( const ast::BasicType * node ) {
    16781602        VISIT_START( node );
    16791603
     
    16831607//--------------------------------------------------------------------------
    16841608// PointerType
    1685 template< typename core_t >
    1686 const ast::Type * ast::Pass< core_t >::visit( const ast::PointerType * node ) {
     1609template< typename pass_t >
     1610const ast::Type * ast::Pass< pass_t >::visit( const ast::PointerType * node ) {
    16871611        VISIT_START( node );
    16881612
     
    16971621//--------------------------------------------------------------------------
    16981622// ArrayType
    1699 template< typename core_t >
    1700 const ast::Type * ast::Pass< core_t >::visit( const ast::ArrayType * node ) {
     1623template< typename pass_t >
     1624const ast::Type * ast::Pass< pass_t >::visit( const ast::ArrayType * node ) {
    17011625        VISIT_START( node );
    17021626
     
    17111635//--------------------------------------------------------------------------
    17121636// ReferenceType
    1713 template< typename core_t >
    1714 const ast::Type * ast::Pass< core_t >::visit( const ast::ReferenceType * node ) {
     1637template< typename pass_t >
     1638const ast::Type * ast::Pass< pass_t >::visit( const ast::ReferenceType * node ) {
    17151639        VISIT_START( node );
    17161640
     
    17241648//--------------------------------------------------------------------------
    17251649// QualifiedType
    1726 template< typename core_t >
    1727 const ast::Type * ast::Pass< core_t >::visit( const ast::QualifiedType * node ) {
     1650template< typename pass_t >
     1651const ast::Type * ast::Pass< pass_t >::visit( const ast::QualifiedType * node ) {
    17281652        VISIT_START( node );
    17291653
     
    17381662//--------------------------------------------------------------------------
    17391663// FunctionType
    1740 template< typename core_t >
    1741 const ast::Type * ast::Pass< core_t >::visit( const ast::FunctionType * node ) {
    1742         VISIT_START( node );
    1743 
    1744         VISIT({
    1745                 // guard_forall_subs forall_guard { *this, node };
    1746                 // mutate_forall( node );
    1747                 maybe_accept( node, &FunctionType::assertions );
     1664template< typename pass_t >
     1665const ast::Type * ast::Pass< pass_t >::visit( const ast::FunctionType * node ) {
     1666        VISIT_START( node );
     1667
     1668        VISIT(
     1669                maybe_accept( node, &FunctionType::forall  );
    17481670                maybe_accept( node, &FunctionType::returns );
    17491671                maybe_accept( node, &FunctionType::params  );
    1750         })
     1672        )
    17511673
    17521674        VISIT_END( Type, node );
     
    17551677//--------------------------------------------------------------------------
    17561678// StructInstType
    1757 template< typename core_t >
    1758 const ast::Type * ast::Pass< core_t >::visit( const ast::StructInstType * node ) {
    1759         VISIT_START( node );
    1760 
    1761         __pass::symtab::addStruct( core, 0, node->name );
     1679template< typename pass_t >
     1680const ast::Type * ast::Pass< pass_t >::visit( const ast::StructInstType * node ) {
     1681        VISIT_START( node );
     1682
     1683        __pass::symtab::addStruct( pass, 0, node->name );
    17621684
    17631685        VISIT({
    17641686                guard_symtab guard { *this };
     1687                maybe_accept( node, &StructInstType::forall );
    17651688                maybe_accept( node, &StructInstType::params );
    17661689        })
     
    17711694//--------------------------------------------------------------------------
    17721695// UnionInstType
    1773 template< typename core_t >
    1774 const ast::Type * ast::Pass< core_t >::visit( const ast::UnionInstType * node ) {
    1775         VISIT_START( node );
    1776 
    1777         __pass::symtab::addUnion( core, 0, node->name );
    1778 
    1779         VISIT({
     1696template< typename pass_t >
     1697const ast::Type * ast::Pass< pass_t >::visit( const ast::UnionInstType * node ) {
     1698        VISIT_START( node );
     1699
     1700        __pass::symtab::addStruct( pass, 0, node->name );
     1701
     1702        {
    17801703                guard_symtab guard { *this };
     1704                maybe_accept( node, &UnionInstType::forall );
    17811705                maybe_accept( node, &UnionInstType::params );
    1782         })
     1706        }
    17831707
    17841708        VISIT_END( Type, node );
     
    17871711//--------------------------------------------------------------------------
    17881712// EnumInstType
    1789 template< typename core_t >
    1790 const ast::Type * ast::Pass< core_t >::visit( const ast::EnumInstType * node ) {
    1791         VISIT_START( node );
    1792 
    1793         VISIT({
     1713template< typename pass_t >
     1714const ast::Type * ast::Pass< pass_t >::visit( const ast::EnumInstType * node ) {
     1715        VISIT_START( node );
     1716
     1717        VISIT(
     1718                maybe_accept( node, &EnumInstType::forall );
    17941719                maybe_accept( node, &EnumInstType::params );
    1795         })
     1720        )
    17961721
    17971722        VISIT_END( Type, node );
     
    18001725//--------------------------------------------------------------------------
    18011726// TraitInstType
    1802 template< typename core_t >
    1803 const ast::Type * ast::Pass< core_t >::visit( const ast::TraitInstType * node ) {
    1804         VISIT_START( node );
    1805 
    1806         VISIT({
     1727template< typename pass_t >
     1728const ast::Type * ast::Pass< pass_t >::visit( const ast::TraitInstType * node ) {
     1729        VISIT_START( node );
     1730
     1731        VISIT(
     1732                maybe_accept( node, &TraitInstType::forall );
    18071733                maybe_accept( node, &TraitInstType::params );
    1808         })
     1734        )
    18091735
    18101736        VISIT_END( Type, node );
     
    18131739//--------------------------------------------------------------------------
    18141740// TypeInstType
    1815 template< typename core_t >
    1816 const ast::Type * ast::Pass< core_t >::visit( const ast::TypeInstType * node ) {
    1817         VISIT_START( node );
    1818 
    1819         VISIT(
    1820                 {
    1821                         maybe_accept( node, &TypeInstType::params );
    1822                 }
    1823                 // ensure that base re-bound if doing substitution
    1824                 __pass::forall::replace( core, 0, node );
     1741template< typename pass_t >
     1742const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeInstType * node ) {
     1743        VISIT_START( node );
     1744
     1745        VISIT(
     1746                maybe_accept( node, &TypeInstType::forall );
     1747                maybe_accept( node, &TypeInstType::params );
    18251748        )
    18261749
     
    18301753//--------------------------------------------------------------------------
    18311754// TupleType
    1832 template< typename core_t >
    1833 const ast::Type * ast::Pass< core_t >::visit( const ast::TupleType * node ) {
     1755template< typename pass_t >
     1756const ast::Type * ast::Pass< pass_t >::visit( const ast::TupleType * node ) {
    18341757        VISIT_START( node );
    18351758
     
    18441767//--------------------------------------------------------------------------
    18451768// TypeofType
    1846 template< typename core_t >
    1847 const ast::Type * ast::Pass< core_t >::visit( const ast::TypeofType * node ) {
     1769template< typename pass_t >
     1770const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeofType * node ) {
    18481771        VISIT_START( node );
    18491772
     
    18571780//--------------------------------------------------------------------------
    18581781// VarArgsType
    1859 template< typename core_t >
    1860 const ast::Type * ast::Pass< core_t >::visit( const ast::VarArgsType * node ) {
     1782template< typename pass_t >
     1783const ast::Type * ast::Pass< pass_t >::visit( const ast::VarArgsType * node ) {
    18611784        VISIT_START( node );
    18621785
     
    18661789//--------------------------------------------------------------------------
    18671790// ZeroType
    1868 template< typename core_t >
    1869 const ast::Type * ast::Pass< core_t >::visit( const ast::ZeroType * node ) {
     1791template< typename pass_t >
     1792const ast::Type * ast::Pass< pass_t >::visit( const ast::ZeroType * node ) {
    18701793        VISIT_START( node );
    18711794
     
    18751798//--------------------------------------------------------------------------
    18761799// OneType
    1877 template< typename core_t >
    1878 const ast::Type * ast::Pass< core_t >::visit( const ast::OneType * node ) {
     1800template< typename pass_t >
     1801const ast::Type * ast::Pass< pass_t >::visit( const ast::OneType * node ) {
    18791802        VISIT_START( node );
    18801803
     
    18841807//--------------------------------------------------------------------------
    18851808// GlobalScopeType
    1886 template< typename core_t >
    1887 const ast::Type * ast::Pass< core_t >::visit( const ast::GlobalScopeType * node ) {
     1809template< typename pass_t >
     1810const ast::Type * ast::Pass< pass_t >::visit( const ast::GlobalScopeType * node ) {
    18881811        VISIT_START( node );
    18891812
     
    18941817//--------------------------------------------------------------------------
    18951818// Designation
    1896 template< typename core_t >
    1897 const ast::Designation * ast::Pass< core_t >::visit( const ast::Designation * node ) {
     1819template< typename pass_t >
     1820const ast::Designation * ast::Pass< pass_t >::visit( const ast::Designation * node ) {
    18981821        VISIT_START( node );
    18991822
     
    19051828//--------------------------------------------------------------------------
    19061829// SingleInit
    1907 template< typename core_t >
    1908 const ast::Init * ast::Pass< core_t >::visit( const ast::SingleInit * node ) {
     1830template< typename pass_t >
     1831const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {
    19091832        VISIT_START( node );
    19101833
     
    19181841//--------------------------------------------------------------------------
    19191842// ListInit
    1920 template< typename core_t >
    1921 const ast::Init * ast::Pass< core_t >::visit( const ast::ListInit * node ) {
     1843template< typename pass_t >
     1844const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {
    19221845        VISIT_START( node );
    19231846
     
    19321855//--------------------------------------------------------------------------
    19331856// ConstructorInit
    1934 template< typename core_t >
    1935 const ast::Init * ast::Pass< core_t >::visit( const ast::ConstructorInit * node ) {
     1857template< typename pass_t >
     1858const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {
    19361859        VISIT_START( node );
    19371860
     
    19471870//--------------------------------------------------------------------------
    19481871// Attribute
    1949 template< typename core_t >
    1950 const ast::Attribute * ast::Pass< core_t >::visit( const ast::Attribute * node  )  {
     1872template< typename pass_t >
     1873const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node  )  {
    19511874        VISIT_START( node );
    19521875
     
    19601883//--------------------------------------------------------------------------
    19611884// TypeSubstitution
    1962 template< typename core_t >
    1963 const ast::TypeSubstitution * ast::Pass< core_t >::visit( const ast::TypeSubstitution * node ) {
     1885template< typename pass_t >
     1886const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
    19641887        VISIT_START( node );
    19651888
     
    19671890                {
    19681891                        bool mutated = false;
    1969                         std::unordered_map< ast::TypeInstType::TypeEnvKey, ast::ptr< ast::Type > > new_map;
     1892                        std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;
    19701893                        for ( const auto & p : node->typeEnv ) {
    19711894                                guard_symtab guard { *this };
    19721895                                auto new_node = p.second->accept( *this );
    1973                                 if (new_node != p.second) mutated = true;
     1896                                if (new_node != p.second) mutated = false;
    19741897                                new_map.insert({ p.first, new_node });
    19751898                        }
    19761899                        if (mutated) {
    1977                                 auto new_node = __pass::mutate<core_t>( node );
     1900                                auto new_node = mutate( node );
    19781901                                new_node->typeEnv.swap( new_map );
    19791902                                node = new_node;
    19801903                        }
    19811904                }
     1905
     1906                {
     1907                        bool mutated = false;
     1908                        std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;
     1909                        for ( const auto & p : node->varEnv ) {
     1910                                guard_symtab guard { *this };
     1911                                auto new_node = p.second->accept( *this );
     1912                                if (new_node != p.second) mutated = false;
     1913                                new_map.insert({ p.first, new_node });
     1914                        }
     1915                        if (mutated) {
     1916                                auto new_node = mutate( node );
     1917                                new_node->varEnv.swap( new_map );
     1918                                node = new_node;
     1919                        }
     1920                }
    19821921        )
    19831922
  • src/AST/Pass.proto.hpp

    reef8dfb rbdfc032  
    1717// IWYU pragma: private, include "Pass.hpp"
    1818
    19 #include "Common/Stats/Heap.h"
    20 
    2119namespace ast {
    22 template<typename core_t>
     20template<typename pass_type>
    2321class Pass;
    24 
    25 struct TranslationUnit;
    26 
    27 struct PureVisitor;
    2822
    2923namespace __pass {
     
    8882                };
    8983
    90                 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
     84                std::stack< cleanup_t > cleanups;
    9185        };
    9286
     
    117111        /// "Short hand" to check if this is a valid previsit function
    118112        /// Mostly used to make the static_assert look (and print) prettier
    119         template<typename core_t, typename node_t>
     113        template<typename pass_t, typename node_t>
    120114        struct is_valid_previsit {
    121                 using ret_t = decltype( ((core_t*)nullptr)->previsit( (const node_t *)nullptr ) );
     115                using ret_t = decltype( ((pass_t*)nullptr)->previsit( (const node_t *)nullptr ) );
    122116
    123117                static constexpr bool value = std::is_void< ret_t >::value ||
     
    133127        template<>
    134128        struct __assign<true> {
    135                 template<typename core_t, typename node_t>
    136                 static inline void result( core_t & core, const node_t * & node ) {
    137                         core.previsit( node );
     129                template<typename pass_t, typename node_t>
     130                static inline void result( pass_t & pass, const node_t * & node ) {
     131                        pass.previsit( node );
    138132                }
    139133        };
     
    141135        template<>
    142136        struct __assign<false> {
    143                 template<typename core_t, typename node_t>
    144                 static inline void result( core_t & core, const node_t * & node ) {
    145                         node = core.previsit( node );
     137                template<typename pass_t, typename node_t>
     138                static inline void result( pass_t & pass, const node_t * & node ) {
     139                        node = pass.previsit( node );
    146140                        assertf(node, "Previsit must not return NULL");
    147141                }
     
    156150        template<>
    157151        struct __return<true> {
    158                 template<typename core_t, typename node_t>
    159                 static inline const node_t * result( core_t & core, const node_t * & node ) {
    160                         core.postvisit( node );
     152                template<typename pass_t, typename node_t>
     153                static inline const node_t * result( pass_t & pass, const node_t * & node ) {
     154                        pass.postvisit( node );
    161155                        return node;
    162156                }
     
    165159        template<>
    166160        struct __return<false> {
    167                 template<typename core_t, typename node_t>
    168                 static inline auto result( core_t & core, const node_t * & node ) {
    169                         return core.postvisit( node );
     161                template<typename pass_t, typename node_t>
     162                static inline auto result( pass_t & pass, const node_t * & node ) {
     163                        return pass.postvisit( node );
    170164                }
    171165        };
     
    186180        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    187181        // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
    188         template<typename core_t, typename node_t>
    189         static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) {
     182        template<typename pass_t, typename node_t>
     183        static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
    190184                static_assert(
    191                         is_valid_previsit<core_t, node_t>::value,
     185                        is_valid_previsit<pass_t, node_t>::value,
    192186                        "Previsit may not change the type of the node. It must return its paremeter or void."
    193187                );
     
    195189                __assign<
    196190                        std::is_void<
    197                                 decltype( core.previsit( node ) )
     191                                decltype( pass.previsit( node ) )
    198192                        >::value
    199                 >::result( core, node );
     193                >::result( pass, node );
    200194        }
    201195
    202         template<typename core_t, typename node_t>
    203         static inline auto previsit( core_t &, const node_t *, long ) {}
     196        template<typename pass_t, typename node_t>
     197        static inline auto previsit( pass_t &, const node_t *, long ) {}
    204198
    205199        // PostVisit : never mutates the passed pointer but may return a different node
    206         template<typename core_t, typename node_t>
    207         static inline auto postvisit( core_t & core, const node_t * node, int ) ->
    208                 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
     200        template<typename pass_t, typename node_t>
     201        static inline auto postvisit( pass_t & pass, const node_t * node, int ) ->
     202                decltype( pass.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
    209203        {
    210204                return __return<
    211205                        std::is_void<
    212                                 decltype( core.postvisit( node ) )
     206                                decltype( pass.postvisit( node ) )
    213207                        >::value
    214                 >::result( core, node );
     208                >::result( pass, node );
    215209        }
    216210
    217         template<typename core_t, typename node_t>
    218         static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; }
     211        template<typename pass_t, typename node_t>
     212        static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
    219213
    220214        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     
    231225        // The type is not strictly enforced but does match the accessory
    232226        #define FIELD_PTR( name, default_type ) \
    233         template< typename core_t > \
    234         static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
     227        template< typename pass_t > \
     228        static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
    235229        \
    236         template< typename core_t > \
    237         static inline default_type * name( core_t &, long ) { return nullptr; }
     230        template< typename pass_t > \
     231        static inline default_type * name( pass_t &, long ) { return nullptr; }
    238232
    239233        // List of fields and their expected types
    240         FIELD_PTR( typeSubs, const ast::TypeSubstitution * )
     234        FIELD_PTR( env, const ast::TypeSubstitution * )
    241235        FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
    242236        FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
     
    245239        FIELD_PTR( visit_children, __pass::bool_ref )
    246240        FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    247         FIELD_PTR( visitor, ast::Pass<core_t> * const )
     241        FIELD_PTR( visitor, ast::Pass<pass_t> * const )
    248242
    249243        // Remove the macro to make sure we don't clash
    250244        #undef FIELD_PTR
    251 
    252         template< typename core_t >
    253         static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
    254                 // Stats::Heap::stacktrace_push(core_t::traceId);
    255         }
    256 
    257         template< typename core_t >
    258         static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
    259                 // Stats::Heap::stacktrace_pop();
    260         }
    261 
    262         template< typename core_t >
    263         static void beginTrace(core_t &, long) {}
    264 
    265         template< typename core_t >
    266         static void endTrace(core_t &, long) {}
    267 
    268         // Allows visitor to handle an error on top-level declarations, and possibly suppress the error.
    269         // If onError() returns false, the error will be ignored. By default, it returns true.
    270 
    271         template< typename core_t >
    272         static bool on_error (core_t &, ptr<Decl> &, long) { return true; }
    273 
    274         template< typename core_t >
    275         static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) {
    276                 return core.on_error(decl);
    277         }
    278245
    279246        // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
     
    281248        // detect it using the same strategy
    282249        namespace scope {
    283                 template<typename core_t>
    284                 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) {
    285                         core.beginScope();
    286                 }
    287 
    288                 template<typename core_t>
    289                 static inline void enter( core_t &, long ) {}
    290 
    291                 template<typename core_t>
    292                 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) {
    293                         core.endScope();
    294                 }
    295 
    296                 template<typename core_t>
    297                 static inline void leave( core_t &, long ) {}
    298         } // namespace scope
    299 
    300         // Certain passes desire an up to date symbol table automatically
     250                template<typename pass_t>
     251                static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {
     252                        pass.beginScope();
     253                }
     254
     255                template<typename pass_t>
     256                static inline void enter( pass_t &, long ) {}
     257
     258                template<typename pass_t>
     259                static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {
     260                        pass.endScope();
     261                }
     262
     263                template<typename pass_t>
     264                static inline void leave( pass_t &, long ) {}
     265        };
     266
     267        // Finally certain pass desire an up to date symbol table automatically
    301268        // detect the presence of a member name `symtab` and call all the members appropriately
    302269        namespace symtab {
    303270                // Some simple scoping rules
    304                 template<typename core_t>
    305                 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) {
    306                         core.symtab.enterScope();
    307                 }
    308 
    309                 template<typename core_t>
    310                 static inline auto enter( core_t &, long ) {}
    311 
    312                 template<typename core_t>
    313                 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) {
    314                         core.symtab.leaveScope();
    315                 }
    316 
    317                 template<typename core_t>
    318                 static inline auto leave( core_t &, long ) {}
     271                template<typename pass_t>
     272                static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab.enterScope(), void() ) {
     273                        pass.symtab.enterScope();
     274                }
     275
     276                template<typename pass_t>
     277                static inline auto enter( pass_t &, long ) {}
     278
     279                template<typename pass_t>
     280                static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab.leaveScope(), void() ) {
     281                        pass.symtab.leaveScope();
     282                }
     283
     284                template<typename pass_t>
     285                static inline auto leave( pass_t &, long ) {}
    319286
    320287                // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments
    321288                // Create macro to condense these common patterns
    322289                #define SYMTAB_FUNC1( func, type ) \
    323                 template<typename core_t> \
    324                 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\
    325                         core.symtab.func( arg ); \
     290                template<typename pass_t> \
     291                static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.symtab.func( arg ), void() ) {\
     292                        pass.symtab.func( arg ); \
    326293                } \
    327294                \
    328                 template<typename core_t> \
    329                 static inline void func( core_t &, long, type ) {}
     295                template<typename pass_t> \
     296                static inline void func( pass_t &, long, type ) {}
    330297
    331298                #define SYMTAB_FUNC2( func, type1, type2 ) \
    332                 template<typename core_t> \
    333                 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\
    334                         core.symtab.func( arg1, arg2 ); \
     299                template<typename pass_t> \
     300                static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.symtab.func( arg1, arg2 ), void () ) {\
     301                        pass.symtab.func( arg1, arg2 ); \
    335302                } \
    336303                        \
    337                 template<typename core_t> \
    338                 static inline void func( core_t &, long, type1, type2 ) {}
     304                template<typename pass_t> \
     305                static inline void func( pass_t &, long, type1, type2 ) {}
    339306
    340307                SYMTAB_FUNC1( addId     , const DeclWithType *  );
     
    344311                SYMTAB_FUNC1( addUnion  , const UnionDecl *     );
    345312                SYMTAB_FUNC1( addTrait  , const TraitDecl *     );
    346                 SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Decl * );
     313                SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Node * );
    347314
    348315                // A few extra functions have more complicated behaviour, they are hand written
    349                 template<typename core_t>
    350                 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) {
     316                template<typename pass_t>
     317                static inline auto addStructFwd( pass_t & pass, int, const ast::StructDecl * decl ) -> decltype( pass.symtab.addStruct( decl ), void() ) {
    351318                        ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
    352319                        fwd->params = decl->params;
    353                         core.symtab.addStruct( fwd );
    354                 }
    355 
    356                 template<typename core_t>
    357                 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {}
    358 
    359                 template<typename core_t>
    360                 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) {
     320                        pass.symtab.addStruct( fwd );
     321                }
     322
     323                template<typename pass_t>
     324                static inline void addStructFwd( pass_t &, long, const ast::StructDecl * ) {}
     325
     326                template<typename pass_t>
     327                static inline auto addUnionFwd( pass_t & pass, int, const ast::UnionDecl * decl ) -> decltype( pass.symtab.addUnion( decl ), void() ) {
    361328                        UnionDecl * fwd = new UnionDecl( decl->location, decl->name );
    362329                        fwd->params = decl->params;
    363                         core.symtab.addUnion( fwd );
    364                 }
    365 
    366                 template<typename core_t>
    367                 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {}
    368 
    369                 template<typename core_t>
    370                 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) {
    371                         if ( ! core.symtab.lookupStruct( str ) ) {
    372                                 core.symtab.addStruct( str );
    373                         }
    374                 }
    375 
    376                 template<typename core_t>
    377                 static inline void addStruct( core_t &, long, const std::string & ) {}
    378 
    379                 template<typename core_t>
    380                 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) {
    381                         if ( ! core.symtab.lookupUnion( str ) ) {
    382                                 core.symtab.addUnion( str );
    383                         }
    384                 }
    385 
    386                 template<typename core_t>
    387                 static inline void addUnion( core_t &, long, const std::string & ) {}
     330                        pass.symtab.addUnion( fwd );
     331                }
     332
     333                template<typename pass_t>
     334                static inline void addUnionFwd( pass_t &, long, const ast::UnionDecl * ) {}
     335
     336                template<typename pass_t>
     337                static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addStruct( str ), void() ) {
     338                        if ( ! pass.symtab.lookupStruct( str ) ) {
     339                                pass.symtab.addStruct( str );
     340                        }
     341                }
     342
     343                template<typename pass_t>
     344                static inline void addStruct( pass_t &, long, const std::string & ) {}
     345
     346                template<typename pass_t>
     347                static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addUnion( str ), void() ) {
     348                        if ( ! pass.symtab.lookupUnion( str ) ) {
     349                                pass.symtab.addUnion( str );
     350                        }
     351                }
     352
     353                template<typename pass_t>
     354                static inline void addUnion( pass_t &, long, const std::string & ) {}
    388355
    389356                #undef SYMTAB_FUNC1
    390357                #undef SYMTAB_FUNC2
    391         } // namespace symtab
    392 
    393         // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType.
    394         // Detect the presence of a member name `subs` and call all members appropriately
    395         namespace forall {
    396                 // Some simple scoping rules
    397                 template<typename core_t>
    398                 static inline auto enter( core_t & core, int, const ast::FunctionType * type )
    399                 -> decltype( core.subs, void() ) {
    400                         if ( ! type->forall.empty() ) core.subs.beginScope();
    401                 }
    402 
    403                 template<typename core_t>
    404                 static inline auto enter( core_t &, long, const ast::FunctionType * ) {}
    405 
    406                 template<typename core_t>
    407                 static inline auto leave( core_t & core, int, const ast::FunctionType * type )
    408                 -> decltype( core.subs, void() ) {
    409                         if ( ! type->forall.empty() ) { core.subs.endScope(); }
    410                 }
    411 
    412                 template<typename core_t>
    413                 static inline auto leave( core_t &, long, const ast::FunctionType * ) {}
    414 
    415                 // Replaces a TypeInstType's base TypeDecl according to the table
    416                 template<typename core_t>
    417                 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst )
    418                 -> decltype( core.subs, void() ) {
    419                         inst = ast::mutate_field(
    420                                 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) );
    421                 }
    422 
    423                 template<typename core_t>
    424                 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {}
    425 
    426         } // namespace forall
    427 
    428         template<typename core_t>
    429         static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) {
    430                 return core.result();
    431         }
    432 
    433         template<typename core_t>
    434         static inline auto get_result( core_t & core, int ) -> decltype( core.result ) {
    435                 return core.result;
    436         }
    437 
    438         template<typename core_t>
    439         static inline void get_result( core_t &, long ) {}
    440 } // namespace __pass
    441 } // namespace ast
     358        };
     359};
     360};
  • src/AST/Print.cpp

    reef8dfb rbdfc032  
    2121#include "Type.hpp"
    2222#include "TypeSubstitution.hpp"
    23 #include "CompilationState.h"
    2423
    2524#include "Common/utility.h" // for group_iterate
     
    3029
    3130template <typename C, typename... T>
    32 constexpr array<C,sizeof...(T)> make_array(T&&... values)
     31constexpr auto make_array(T&&... values) ->
     32        array<C,sizeof...(T)>
    3333{
    3434        return array<C,sizeof...(T)>{
     
    129129
    130130        void print( const ast::Expr::InferUnion & inferred, unsigned level = 0 ) {
    131                 if (inferred.data.resnSlots && !inferred.data.resnSlots->empty()) {
    132                         os << indent << "with " << inferred.data.resnSlots->size()
     131                switch ( inferred.mode ) {
     132                case ast::Expr::InferUnion::Empty: return;
     133                case ast::Expr::InferUnion::Slots: {
     134                        os << indent << "with " << inferred.data.resnSlots.size()
    133135                           << " pending inference slots" << endl;
    134                 }
    135                 if (inferred.data.inferParams && !inferred.data.inferParams->empty()) {
     136                        return;
     137                }
     138                case ast::Expr::InferUnion::Params: {
    136139                        os << indent << "with inferred parameters " << level << ":" << endl;
    137140                        ++indent;
    138                         for ( const auto & i : *inferred.data.inferParams ) {
     141                        for ( const auto & i : inferred.data.inferParams ) {
    139142                                os << indent;
    140                                 short_print( i.second.declptr );
     143                                short_print( Decl::fromId( i.second.decl ) );
    141144                                os << endl;
    142145                                print( i.second.expr->inferred, level+1 );
    143146                        }
    144147                        --indent;
    145                 }
    146         }
    147 
    148         void print( const ast::FunctionType::ForallList & forall ) {
     148                        return;
     149                }
     150                }
     151        }
     152
     153        void print( const ast::ParameterizedType::ForallList & forall ) {
    149154                if ( forall.empty() ) return;
    150155                os << "forall" << endl;
    151156                ++indent;
    152157                printAll( forall );
    153                 os << indent;
    154                 --indent;
    155         }
    156 
    157         void print( const ast::FunctionType::AssertionList & assts ) {
    158                 if (assts.empty()) return;
    159                 os << "with assertions" << endl;
    160                 ++indent;
    161                 printAll(assts);
    162158                os << indent;
    163159                --indent;
     
    214210
    215211        void preprint( const ast::NamedTypeDecl * node ) {
    216                 if ( ! node->name.empty() ) {
    217                         os << node->name << ": ";
    218                 }
     212                if ( ! node->name.empty() ) os << node->name << ": ";
    219213
    220214                if ( ! short_mode && node->linkage != Linkage::Cforall ) {
     
    232226                }
    233227
    234                 if ( ! node->assertions.empty() ) {
     228                if ( ! node->params.empty() ) {
     229                        os << endl << indent << "... with parameters" << endl;
     230                        ++indent;
     231                        printAll( node->params );
     232                        --indent;
     233                }
     234
     235                if ( ! short_mode && ! node->assertions.empty() ) {
    235236                        os << endl << indent << "... with assertions" << endl;
    236237                        ++indent;
     
    243244                print( node->inferred );
    244245
    245                 if ( node->result ) {
    246                         os << endl << indent << "... with resolved type:" << endl;
    247                         ++indent;
    248                         os << indent;
    249                         node->result->accept( *this );
    250                         --indent;
    251                 }
    252 
    253246                if ( node->env ) {
    254247                        os << endl << indent << "... with environment:" << endl;
     
    267260        }
    268261
    269         void preprint( const ast::FunctionType * node ) {
     262        void preprint( const ast::ParameterizedType * node ) {
    270263                print( node->forall );
    271                 print( node->assertions );
    272264                print( node->qualifiers );
    273265        }
    274266
    275         void preprint( const ast::BaseInstType * node ) {
     267        void preprint( const ast::ReferenceToType * node ) {
     268                print( node->forall );
    276269                print( node->attributes );
    277270                print( node->qualifiers );
     
    685678        }
    686679
    687         virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final {
    688                 os << "Suspend Statement";
    689                 switch (node->type) {
    690                         case ast::SuspendStmt::None     : os << " with implicit target"; break;
    691                         case ast::SuspendStmt::Generator: os << " for generator"; break;
    692                         case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;
    693                 }
    694                 os << endl;
    695 
    696                 ++indent;
    697                 if(node->then) {
    698                         os << indent << " with post statement :" << endl;
    699                         safe_print( node->then );
    700                 }
    701                 ++indent;
    702 
    703                 return node;
    704         }
    705 
    706680        virtual const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
    707681                os << "Waitfor Statement" << endl;
     
    849823        virtual const ast::Expr * visit( const ast::CastExpr * node ) override final {
    850824                ++indent;
    851                 os << (node->isGenerated ? "Generated" : "Explicit") << " Cast of:" << endl << indent;
     825                os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << endl << indent;
    852826                safe_print( node->arg );
    853827                os << endl << indent-1 << "... to:";
     
    13841358        virtual const ast::Type * visit( const ast::TypeInstType * node ) override final {
    13851359                preprint( node );
    1386                 const auto & _name = deterministic_output && isUnboundType(node) ? "[unbound]" : node->typeString();
    1387                 os << "instance of type " << _name
     1360                os << "instance of type " << node->name
    13881361                   << " (" << (node->kind == ast::TypeDecl::Ftype ? "" : "not ") << "function type)";
    13891362                print( node->params );
     
    15111484                os << indent << "Types:" << endl;
    15121485                for ( const auto& i : *node ) {
    1513                         os << indent+1 << i.first.typeString() << " -> ";
     1486                        os << indent+1 << i.first << " -> ";
    15141487                        indent += 2;
    15151488                        safe_print( i.second );
     1489                        indent -= 2;
     1490                        os << endl;
     1491                }
     1492                os << indent << "Non-types:" << endl;
     1493                for ( auto i = node->beginVar(); i != node->endVar(); ++i ) {
     1494                        os << indent+1 << i->first << " -> ";
     1495                        indent += 2;
     1496                        safe_print( i->second );
    15161497                        indent -= 2;
    15171498                        os << endl;
  • src/AST/Stmt.hpp

    reef8dfb rbdfc032  
    2727
    2828// Must be included in *all* AST classes; should be #undef'd at the end of the file
    29 #define MUTATE_FRIEND \
    30     template<typename node_t> friend node_t * mutate(const node_t * node); \
    31         template<typename node_t> friend node_t * shallowCopy(const node_t * node);
     29#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
    3230
    3331namespace ast {
     
    344342};
    345343
    346 /// Suspend statement
    347 class SuspendStmt final : public Stmt {
    348 public:
    349         ptr<CompoundStmt> then;
    350         enum Type { None, Coroutine, Generator } type = None;
    351 
    352         SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, std::vector<Label> && labels = {} )
    353         : Stmt(loc, std::move(labels)), then(then), type(type) {}
    354 
    355         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    356 private:
    357         SuspendStmt * clone() const override { return new SuspendStmt{ *this }; }
    358         MUTATE_FRIEND
    359 };
    360 
    361344/// Wait for concurrency statement `when (...) waitfor (... , ...) ... timeout(...) ... else ...`
    362345class WaitForStmt final : public Stmt {
     
    414397class ImplicitCtorDtorStmt final : public Stmt {
    415398public:
    416         ptr<Stmt> callStmt;
     399        readonly<Stmt> callStmt;
    417400
    418401        ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt,
  • src/AST/SymbolTable.cpp

    reef8dfb rbdfc032  
    9595}
    9696
    97 SymbolTable::SpecialFunctionKind SymbolTable::getSpecialFunctionKind(const std::string & name) {
    98         if (name == "?{}") return CTOR;
    99         if (name == "^?{}") return DTOR;
    100         if (name == "?=?") return ASSIGN;
    101         return NUMBER_OF_KINDS;
    102 }
    103 
    10497std::vector<SymbolTable::IdData> SymbolTable::lookupId( const std::string &id ) const {
    105         static Stats::Counters::CounterGroup * name_lookup_stats = Stats::Counters::build<Stats::Counters::CounterGroup>("Name Lookup Stats");
    106         static std::map<std::string, Stats::Counters::SimpleCounter *> lookups_by_name;
    107         static std::map<std::string, Stats::Counters::SimpleCounter *> candidates_by_name;
    108 
    109         SpecialFunctionKind kind = getSpecialFunctionKind(id);
    110         if (kind != NUMBER_OF_KINDS) return specialLookupId(kind);
    111 
    11298        ++*stats().lookup_calls;
    11399        if ( ! idTable ) return {};
     
    121107                out.push_back( decl.second );
    122108        }
    123 
    124         if (Stats::Counters::enabled) {
    125                 if (! lookups_by_name.count(id)) {
    126                         // leaks some strings, but it is because Counters do not hold them
    127                         auto lookupCounterName = new std::string(id + "%count");
    128                         auto candidatesCounterName = new std::string(id + "%candidate");
    129                         lookups_by_name.emplace(id, new Stats::Counters::SimpleCounter(lookupCounterName->c_str(), name_lookup_stats));
    130                         candidates_by_name.emplace(id, new Stats::Counters::SimpleCounter(candidatesCounterName->c_str(), name_lookup_stats));
    131                 }
    132                 (*lookups_by_name[id]) ++;
    133                 *candidates_by_name[id] += out.size();
    134         }
    135 
    136         return out;
    137 }
    138 
    139 std::vector<SymbolTable::IdData> SymbolTable::specialLookupId( SymbolTable::SpecialFunctionKind kind, const std::string & otypeKey ) const {
    140         static Stats::Counters::CounterGroup * special_stats = Stats::Counters::build<Stats::Counters::CounterGroup>("Special Lookups");
    141         static Stats::Counters::SimpleCounter * stat_counts[3] = {
    142                 Stats::Counters::build<Stats::Counters::SimpleCounter>("constructor - count", special_stats),
    143                 Stats::Counters::build<Stats::Counters::SimpleCounter>("destructor - count", special_stats),
    144                 Stats::Counters::build<Stats::Counters::SimpleCounter>("assignment - count", special_stats)
    145         };
    146 
    147         static Stats::Counters::SimpleCounter * stat_candidates[3] = {
    148                 Stats::Counters::build<Stats::Counters::SimpleCounter>("constructor - candidates", special_stats),
    149                 Stats::Counters::build<Stats::Counters::SimpleCounter>("destructor - candidates", special_stats),
    150                 Stats::Counters::build<Stats::Counters::SimpleCounter>("assignment - candidates", special_stats)
    151         };
    152 
    153         static Stats::Counters::SimpleCounter * num_lookup_with_key
    154                 = Stats::Counters::build<Stats::Counters::SimpleCounter>("keyed lookups", special_stats);
    155         static Stats::Counters::SimpleCounter * num_lookup_without_key
    156                 = Stats::Counters::build<Stats::Counters::SimpleCounter>("unkeyed lookups", special_stats);
    157 
    158         assert (kind != NUMBER_OF_KINDS);
    159         ++*stats().lookup_calls;
    160         if ( ! specialFunctionTable[kind] ) return {};
    161 
    162         std::vector<IdData> out;
    163 
    164         if (otypeKey.empty()) { // returns everything
    165                 ++*num_lookup_without_key;
    166                 for (auto & table : *specialFunctionTable[kind]) {
    167                         for (auto & decl : *table.second) {
    168                                 out.push_back(decl.second);
    169                         }
    170                 }
    171         }
    172         else {
    173                 ++*num_lookup_with_key;
    174                 ++*stats().map_lookups;
    175                 auto decls = specialFunctionTable[kind]->find(otypeKey);
    176                 if (decls == specialFunctionTable[kind]->end()) return {};
    177 
    178                 for (auto decl : *(decls->second)) {
    179                         out.push_back(decl.second);
    180                 }
    181         }
    182 
    183         ++*stat_counts[kind];
    184         *stat_candidates[kind] += out.size();
    185 
    186109        return out;
    187110}
     
    390313                if ( ! expr->result ) continue;
    391314                const Type * resTy = expr->result->stripReferences();
    392                 auto aggrType = dynamic_cast< const BaseInstType * >( resTy );
     315                auto aggrType = dynamic_cast< const ReferenceToType * >( resTy );
    393316                assertf( aggrType, "WithStmt expr has non-aggregate type: %s",
    394317                        toString( expr->result ).c_str() );
     
    412335}
    413336
    414 
    415 void 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 );
    423         addIds( func->returns );
    424         addIds( func->params );
    425 }
    426 
     337void SymbolTable::addFunctionType( const FunctionType * ftype ) {
     338        addTypes( ftype->forall );
     339        addIds( ftype->returns );
     340        addIds( ftype->params );
     341}
    427342
    428343void SymbolTable::lazyInitScope() {
     
    449364namespace {
    450365        /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function
    451         std::string getOtypeKey( const FunctionType * ftype, bool stripParams = true ) {
    452                 const auto & params = ftype->params;
     366        std::string getOtypeKey( const FunctionDecl * function ) {
     367                const auto & params = function->type->params;
    453368                assert( ! params.empty() );
    454369                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
    455                 const Type * base = InitTweak::getPointerBase( params.front() );
     370                const Type * base = InitTweak::getPointerBase( params.front()->get_type() );
    456371                assert( base );
    457                 if (stripParams) {
    458                         if (dynamic_cast<const PointerType *>(base)) return Mangle::Encoding::pointer;
    459                         return Mangle::mangle( base, Mangle::Type | Mangle::NoGenericParams );
    460                 }
    461                 else
    462                         return Mangle::mangle( base ); 
     372                return Mangle::mangle( base );
    463373        }
    464374
     
    468378                        const DeclWithType * decl, const std::string & otypeKey ) {
    469379                auto func = dynamic_cast< const FunctionDecl * >( decl );
    470                 if ( ! func || otypeKey != getOtypeKey( func->type, false ) ) return nullptr;
     380                if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr;
    471381                return func;
    472382        }
     
    493403        bool dataIsUserDefinedFunc = ! function->linkage.is_overrideable;
    494404        bool dataIsCopyFunc = InitTweak::isCopyFunction( function );
    495         std::string dataOtypeKey = getOtypeKey( function->type, false ); // requires exact match to override autogen
     405        std::string dataOtypeKey = getOtypeKey( function );
    496406
    497407        if ( dataIsUserDefinedFunc && dataIsCopyFunc ) {
     
    665575                const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    666576                const Decl * deleter ) {
    667         SpecialFunctionKind kind = getSpecialFunctionKind(decl->name);
    668         if (kind == NUMBER_OF_KINDS) { // not a special decl
    669                 addId(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
    670         }
    671         else {
    672                 std::string key;
    673                 if (auto func = dynamic_cast<const FunctionDecl *>(decl)) {
    674                         key = getOtypeKey(func->type);
    675                 }
    676                 else if (auto obj = dynamic_cast<const ObjectDecl *>(decl)) {
    677                         key = getOtypeKey(obj->type.strict_as<PointerType>()->base.strict_as<FunctionType>());
    678                 }
    679                 else {
    680                         assertf(false, "special decl with non-function type");
    681                 }
    682                 addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
    683         }
    684 }
    685 
    686 void SymbolTable::addId(
    687                 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    688                 const Decl * deleter ) {
    689577        ++*stats().add_calls;
    690578        const std::string &name = decl->name;
     
    717605        // ensure tables exist and add identifier
    718606        MangleTable::Ptr mangleTable;
    719         if ( ! table ) {
    720                 table = IdTable::new_ptr();
     607        if ( ! idTable ) {
     608                idTable = IdTable::new_ptr();
    721609                mangleTable = MangleTable::new_ptr();
    722610        } else {
    723611                ++*stats().map_lookups;
    724                 auto decls = table->find( lookupKey );
    725                 if ( decls == table->end() ) {
     612                auto decls = idTable->find( name );
     613                if ( decls == idTable->end() ) {
    726614                        mangleTable = MangleTable::new_ptr();
    727615                } else {
     
    738626                                                lazyInitScope();
    739627                                                *stats().map_mutations += 2;
    740                                                 table = table->set(
    741                                                         lookupKey,
     628                                                idTable = idTable->set(
     629                                                        name,
    742630                                                        mangleTable->set(
    743631                                                                mangleName,
     
    754642        IdData data{ decl, baseExpr, deleter, scope };
    755643        // Ensure that auto-generated ctor/dtor/assignment are deleted if necessary
    756         if (table != idTable) { // adding to special table
    757                 if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
    758         }
     644        if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
    759645        *stats().map_mutations += 2;
    760         table = table->set( lookupKey, mangleTable->set( mangleName, std::move(data) ) );
     646        idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) );
    761647}
    762648
     
    768654                        if ( dwt->name == "" ) {
    769655                                const Type * t = dwt->get_type()->stripReferences();
    770                                 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {
     656                                if ( auto rty = dynamic_cast<const ReferenceToType *>( t ) ) {
    771657                                        if ( ! dynamic_cast<const StructInstType *>(rty)
    772658                                                && ! dynamic_cast<const UnionInstType *>(rty) ) continue;
  • src/AST/SymbolTable.hpp

    reef8dfb rbdfc032  
    3333class SymbolTable final : public std::enable_shared_from_this<ast::SymbolTable> {
    3434public:
    35         /// special functions stored in dedicated tables, with different lookup keys
    36         enum SpecialFunctionKind {CTOR, DTOR, ASSIGN, NUMBER_OF_KINDS};
    37         static SpecialFunctionKind getSpecialFunctionKind(const std::string & name);
    38 
    3935        /// Stored information about a declaration
    4036        struct IdData {
     
    8177        UnionTable::Ptr unionTable;    ///< union namespace
    8278        TraitTable::Ptr traitTable;    ///< trait namespace
    83         IdTable::Ptr specialFunctionTable[NUMBER_OF_KINDS];
    84 
    85         // using SpecialFuncTable = PersistentMap< std::string, IdTable::Ptr >; // fname (ctor/dtor/assign) - otypekey
    86         // SpecialFuncTable::Ptr specialFuncTable;
    8779
    8880        using Ptr = std::shared_ptr<const SymbolTable>;
     
    10395        /// Gets all declarations with the given ID
    10496        std::vector<IdData> lookupId( const std::string &id ) const;
    105         /// Gets special functions associated with a type; if no key is given, returns everything
    106         std::vector<IdData> specialLookupId( SpecialFunctionKind kind, const std::string & otypeKey = "" ) const;
    10797        /// Gets the top-most type declaration with the given ID
    10898        const NamedTypeDecl * lookupType( const std::string &id ) const;
     
    155145
    156146        /// convenience function for adding all of the declarations in a function type to the indexer
    157         void addFunction( const FunctionDecl * );
     147        void addFunctionType( const FunctionType * ftype );
    158148
    159149private:
     
    196186                const Decl * deleter = nullptr );
    197187
    198         /// common code for addId when special decls are placed into separate tables
    199         void addId(
    200                 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & idTable, OnConflict handleConflicts,
    201                 const Expr * baseExpr = nullptr, const Decl * deleter = nullptr);
    202        
    203188        /// adds all of the members of the Aggregate (addWith helper)
    204189        void addMembers( const AggregateDecl * aggr, const Expr * expr, OnConflict handleConflicts );
  • src/AST/Type.cpp

    reef8dfb rbdfc032  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon May 13 15:00:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Jul 23 14:16:00 2020
    13 // Update Count     : 5
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Dec 15 16:56:28 2019
     13// Update Count     : 4
    1414//
    1515
     
    2222#include "Decl.hpp"
    2323#include "Init.hpp"
    24 #include "Common/utility.h"      // for copy, move
    2524#include "InitTweak/InitTweak.h" // for getPointerBase
    2625#include "Tuples/Tuples.h"       // for isTtype
     
    9291
    9392// --- FunctionType
     93
    9494namespace {
    95         bool containsTtype( const std::vector<ptr<Type>> & l ) {
     95        bool containsTtype( const std::vector<ptr<DeclWithType>> & l ) {
    9696                if ( ! l.empty() ) {
    97                         return Tuples::isTtype( l.back() );
     97                        return Tuples::isTtype( l.back()->get_type() );
    9898                }
    9999                return false;
     
    105105}
    106106
    107 std::vector<readonly<Decl>> BaseInstType::lookup( const std::string& name ) const {
     107// --- ReferenceToType
     108std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const {
    108109        assertf( aggr(), "Must have aggregate to perform lookup" );
    109110
     
    115116}
    116117
    117 // --- SueInstType (StructInstType, UnionInstType, EnumInstType)
     118// --- StructInstType
    118119
    119 template<typename decl_t>
    120 SueInstType<decl_t>::SueInstType(
    121         const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
    122 : BaseInstType( b->name, q, move(as) ), base( b ) {}
     120StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q,
     121        std::vector<ptr<Attribute>>&& as )
     122: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    123123
    124 template<typename decl_t>
    125 SueInstType<decl_t>::SueInstType(
    126         const base_type * b, std::vector<ptr<Expr>> && params,
    127         CV::Qualifiers q, std::vector<ptr<Attribute>> && as )
    128 : BaseInstType( b->name, std::move(params), q, std::move(as) ), base( b ) {}
     124bool StructInstType::isComplete() const { return base ? base->body : false; }
    129125
    130 template<typename decl_t>
    131 bool SueInstType<decl_t>::isComplete() const {
    132         return base ? base->body : false;
    133 }
     126// --- UnionInstType
    134127
    135 template class SueInstType<StructDecl>;
    136 template class SueInstType<UnionDecl>;
    137 template class SueInstType<EnumDecl>;
     128UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q,
     129        std::vector<ptr<Attribute>>&& as )
     130: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
     131
     132bool UnionInstType::isComplete() const { return base ? base->body : false; }
     133
     134// --- EnumInstType
     135
     136EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q,
     137        std::vector<ptr<Attribute>>&& as )
     138: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
     139
     140bool EnumInstType::isComplete() const { return base ? base->body : false; }
    138141
    139142// --- TraitInstType
    140143
    141 TraitInstType::TraitInstType(
    142         const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
    143 : BaseInstType( b->name, q, move(as) ), base( b ) {}
     144TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,
     145        std::vector<ptr<Attribute>>&& as )
     146: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
     147
     148// --- TypeInstType
    144149
    145150void TypeInstType::set_base( const TypeDecl * b ) {
     
    153158
    154159TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
    155 : Type( q ), types( move(ts) ), members() {
     160: Type( q ), types( std::move(ts) ), members() {
    156161        // This constructor is awkward. `TupleType` needs to contain objects so that members can be
    157162        // named, but members without initializer nodes end up getting constructors, which breaks
     
    168173        for ( const Type * ty : types ) {
    169174                members.emplace_back( new ObjectDecl{
    170                         CodeLocation{}, "", ty, new ListInit( CodeLocation{}, {}, {}, NoConstruct ),
     175                        CodeLocation{}, "", ty, new ListInit( CodeLocation{}, {}, {}, MaybeConstruct ),
    171176                        Storage::Classes{}, Linkage::Cforall } );
    172177        }
    173 }
    174 
    175 bool isUnboundType(const Type * type) {
    176         if (auto typeInst = dynamic_cast<const TypeInstType *>(type)) {
    177                 // xxx - look for a type name produced by renameTyVars.
    178 
    179                 // TODO: once TypeInstType representation is updated, it should properly check
    180                 // if the context id is filled. this is a temporary hack for now
    181                 return typeInst->formal_usage > 0;
    182         }
    183         return false;
    184178}
    185179
  • src/AST/Type.hpp

    reef8dfb rbdfc032  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Jul 23 14:15:00 2020
    13 // Update Count     : 6
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Dec 11 21:56:46 2019
     13// Update Count     : 5
    1414//
    1515
     
    2929
    3030// Must be included in *all* AST classes; should be #undef'd at the end of the file
    31 #define MUTATE_FRIEND \
    32     template<typename node_t> friend node_t * mutate(const node_t * node); \
    33         template<typename node_t> friend node_t * shallowCopy(const node_t * node);
     31#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
    3432
    3533namespace ast {
    36 
    37 template< typename T > class Pass;
    3834
    3935class Type : public Node {
     
    4844        bool is_volatile() const { return qualifiers.is_volatile; }
    4945        bool is_restrict() const { return qualifiers.is_restrict; }
     46        bool is_lvalue() const { return qualifiers.is_lvalue; }
    5047        bool is_mutex() const { return qualifiers.is_mutex; }
    5148        bool is_atomic() const { return qualifiers.is_atomic; }
     
    5451        Type * set_volatile( bool v ) { qualifiers.is_volatile = v; return this; }
    5552        Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; }
     53        Type * set_lvalue( bool v ) { qualifiers.is_lvalue = v; return this; }
    5654        Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; }
    5755        Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; }
     
    165163        static const char *typeNames[];
    166164
    167         BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
     165        BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 
    168166        : Type(q, std::move(as)), kind(k) {}
    169167
     
    265263};
    266264
     265/// Base type for potentially forall-qualified types
     266class ParameterizedType : public Type {
     267public:
     268        using ForallList = std::vector<ptr<TypeDecl>>;
     269
     270        ForallList forall;
     271
     272        ParameterizedType( ForallList&& fs = {}, CV::Qualifiers q = {},
     273                std::vector<ptr<Attribute>> && as = {} )
     274        : Type(q, std::move(as)), forall(std::move(fs)) {}
     275
     276        ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} )
     277        : Type(q, std::move(as)), forall() {}
     278
     279private:
     280        virtual ParameterizedType * clone() const override = 0;
     281        MUTATE_FRIEND
     282};
     283
    267284/// Function variable arguments flag
    268285enum ArgumentFlag { FixedArgs, VariableArgs };
    269286
    270287/// Type of a function `[R1, R2](*)(P1, P2, P3)`
    271 class FunctionType final : public Type {
    272 public:
    273         using ForallList = std::vector<ptr<TypeInstType>>;
    274         using AssertionList = std::vector<ptr<VariableExpr>>;
    275         ForallList forall;
    276         AssertionList assertions;
    277 
    278         std::vector<ptr<Type>> returns;
    279         std::vector<ptr<Type>> params;
     288class FunctionType final : public ParameterizedType {
     289public:
     290        std::vector<ptr<DeclWithType>> returns;
     291        std::vector<ptr<DeclWithType>> params;
    280292
    281293        /// Does the function accept a variable number of arguments following the arguments specified
     
    287299
    288300        FunctionType( ArgumentFlag va = FixedArgs, CV::Qualifiers q = {} )
    289         : Type(q), returns(), params(), isVarArgs(va) {}
    290 
    291         FunctionType( const FunctionType & o ) = default;
     301        : ParameterizedType(q), returns(), params(), isVarArgs(va) {}
    292302
    293303        /// true if either the parameters or return values contain a tttype
     
    303313
    304314/// base class for types that refer to types declared elsewhere (aggregates and typedefs)
    305 class BaseInstType : public Type {
     315class ReferenceToType : public ParameterizedType {
    306316public:
    307317        std::vector<ptr<Expr>> params;
     
    309319        bool hoistType = false;
    310320
    311         BaseInstType(
    312                 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    313         : Type(q, std::move(as)), params(), name(n) {}
    314 
    315         BaseInstType(
    316                 const std::string& n, std::vector<ptr<Expr>> && params,
    317                 CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    318         : Type(q, std::move(as)), params(std::move(params)), name(n) {}
    319 
    320         BaseInstType( const BaseInstType & o ) = default;
     321        ReferenceToType( const std::string& n, CV::Qualifiers q = {},
     322                std::vector<ptr<Attribute>> && as = {} )
     323        : ParameterizedType(q, std::move(as)), params(), name(n) {}
    321324
    322325        /// Gets aggregate declaration this type refers to
     
    326329
    327330private:
    328         virtual BaseInstType * clone() const override = 0;
    329         MUTATE_FRIEND
    330 };
    331 
    332 // Common implementation for the SUE instance types. Not to be used directly.
    333 template<typename decl_t>
    334 class SueInstType final : public BaseInstType {
    335 public:
    336         using base_type = decl_t;
    337         readonly<decl_t> base;
    338 
    339         SueInstType(
    340                 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    341         : BaseInstType( n, q, std::move(as) ), base() {}
    342 
    343         SueInstType(
    344                 const base_type * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
    345 
    346         SueInstType(
    347                 const base_type * b, std::vector<ptr<Expr>> && params,
    348                 CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
     331        virtual ReferenceToType * clone() const override = 0;
     332        MUTATE_FRIEND
     333};
     334
     335/// instance of struct type
     336class StructInstType final : public ReferenceToType {
     337public:
     338        readonly<StructDecl> base;
     339
     340        StructInstType( const std::string& n, CV::Qualifiers q = {},
     341                std::vector<ptr<Attribute>> && as = {} )
     342        : ReferenceToType( n, q, std::move(as) ), base() {}
     343        StructInstType( const StructDecl * b, CV::Qualifiers q = {},
     344                std::vector<ptr<Attribute>> && as = {} );
    349345
    350346        bool isComplete() const override;
    351347
    352         const decl_t * aggr() const override { return base; }
    353 
    354         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    355 private:
    356         SueInstType<decl_t> * clone() const override { return new SueInstType<decl_t>{ *this }; }
    357         MUTATE_FRIEND
    358 };
    359 
    360 /// An instance of a struct type.
    361 using StructInstType = SueInstType<StructDecl>;
    362 
    363 /// An instance of a union type.
    364 using UnionInstType = SueInstType<UnionDecl>;
    365 
    366 /// An instance of an enum type.
    367 using EnumInstType = SueInstType<EnumDecl>;
    368 
    369 /// An instance of a trait type.
    370 class TraitInstType final : public BaseInstType {
     348        const StructDecl * aggr() const override { return base; }
     349
     350        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     351private:
     352        StructInstType * clone() const override { return new StructInstType{ *this }; }
     353        MUTATE_FRIEND
     354};
     355
     356/// instance of union type
     357class UnionInstType final : public ReferenceToType {
     358public:
     359        readonly<UnionDecl> base;
     360
     361        UnionInstType( const std::string& n, CV::Qualifiers q = {},
     362                std::vector<ptr<Attribute>> && as = {} )
     363        : ReferenceToType( n, q, std::move(as) ), base() {}
     364        UnionInstType( const UnionDecl * b, CV::Qualifiers q = {},
     365                std::vector<ptr<Attribute>> && as = {} );
     366
     367        bool isComplete() const override;
     368
     369        const UnionDecl * aggr() const override { return base; }
     370
     371        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     372private:
     373        UnionInstType * clone() const override { return new UnionInstType{ *this }; }
     374        MUTATE_FRIEND
     375};
     376
     377/// instance of enum type
     378class EnumInstType final : public ReferenceToType {
     379public:
     380        readonly<EnumDecl> base;
     381
     382        EnumInstType( const std::string& n, CV::Qualifiers q = {},
     383                std::vector<ptr<Attribute>> && as = {} )
     384        : ReferenceToType( n, q, std::move(as) ), base() {}
     385        EnumInstType( const EnumDecl * b, CV::Qualifiers q = {},
     386                std::vector<ptr<Attribute>> && as = {} );
     387
     388        bool isComplete() const override;
     389
     390        const EnumDecl * aggr() const override { return base; }
     391
     392        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     393private:
     394        EnumInstType * clone() const override { return new EnumInstType{ *this }; }
     395        MUTATE_FRIEND
     396};
     397
     398/// instance of trait type
     399class TraitInstType final : public ReferenceToType {
    371400public:
    372401        readonly<TraitDecl> base;
    373402
    374         TraitInstType(
    375                 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    376         : BaseInstType( n, q, std::move(as) ), base() {}
    377 
    378         TraitInstType(
    379                 const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
     403        TraitInstType( const std::string& n, CV::Qualifiers q = {},
     404                std::vector<ptr<Attribute>> && as = {} )
     405        : ReferenceToType( n, q, std::move(as) ), base() {}
     406        TraitInstType( const TraitDecl * b, CV::Qualifiers q = {},
     407                std::vector<ptr<Attribute>> && as = {} );
    380408
    381409        // not meaningful for TraitInstType
     
    391419
    392420/// instance of named type alias (typedef or variable)
    393 class TypeInstType final : public BaseInstType {
     421class TypeInstType final : public ReferenceToType {
    394422public:
    395423        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)
    399424        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; }
    418 
    419         TypeInstType(
    420                 const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
    421                 std::vector<ptr<Attribute>> && as = {} )
    422         : BaseInstType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
     425
     426        TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
     427                std::vector<ptr<Attribute>> && as = {} )
     428        : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
    423429        TypeInstType( const std::string& n, TypeDecl::Kind k, CV::Qualifiers q = {},
    424430                std::vector<ptr<Attribute>> && as = {} )
    425         : BaseInstType( n, q, std::move(as) ), base(), kind( k ) {}
    426 
    427         TypeInstType( const TypeInstType & o ) = default;
    428 
    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        : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {}
    431432
    432433        /// sets `base`, updating `kind` correctly
     
    439440
    440441        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         }
    446442private:
    447443        TypeInstType * clone() const override { return new TypeInstType{ *this }; }
     
    535531};
    536532
    537 bool 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         };
    552533}
    553534
  • src/AST/TypeEnvironment.cpp

    reef8dfb rbdfc032  
    3434#include "ResolvExpr/Unify.h"      // for unifyInexact
    3535#include "Tuples/Tuples.h"         // for isTtype
    36 #include "CompilationState.h"
    3736
    3837using ResolvExpr::WidenMode;
     
    5251        for ( const auto & i : open ) {
    5352                if ( first ) { first = false; } else { out << ' '; }
    54                 out << i.first.typeString() << "(" << i.second << ")";
     53                out << i.first << "(" << i.second << ")";
    5554        }
    5655}
    5756
    5857void print( std::ostream & out, const EqvClass & clz, Indenter indent ) {
    59         out << "(";
    60         bool first = true;
    61         for(const auto & var : clz.vars) {
    62                 if(first) first = false;
    63                 else out << " ";
    64 
    65                 if( deterministic_output ) out << "[unbound]";
    66                 else out << "_" << var.formal_usage << "_" << var.expr_id << "_";
    67 
    68                 out << var.base->name;
    69         }
     58        out << "( ";
     59        std::copy( clz.vars.begin(), clz.vars.end(), std::ostream_iterator< std::string >( out, " " ) );
    7060        out << ")";
    71 
     61       
    7262        if ( clz.bound ) {
    7363                out << " -> ";
     
    8272}
    8373
    84 const EqvClass * TypeEnvironment::lookup( const TypeInstType::TypeEnvKey & var ) const {
     74const EqvClass * TypeEnvironment::lookup( const std::string & var ) const {
    8575        for ( ClassList::const_iterator i = env.begin(); i != env.end(); ++i ) {
    8676                if ( i->vars.find( var ) != i->vars.end() ) return &*i;
     
    10292                                }
    10393                        }
    104 
     94                       
    10595                        i = next;  // go to next node even if this removed
    10696                }
     
    10898}
    10999
    110 void TypeEnvironment::add( const FunctionType::ForallList & tyDecls ) {
    111         for ( auto & tyDecl : tyDecls ) {
     100void TypeEnvironment::add( const ParameterizedType::ForallList & tyDecls ) {
     101        for ( const TypeDecl * tyDecl : tyDecls ) {
    112102                env.emplace_back( tyDecl );
    113103        }
     
    122112void TypeEnvironment::writeToSubstitution( TypeSubstitution & sub ) const {
    123113        for ( const auto & clz : env ) {
    124                 TypeInstType::TypeEnvKey clzRep;
    125                 bool first = true;
     114                std::string clzRep;
    126115                for ( const auto & var : clz.vars ) {
    127116                        if ( clz.bound ) {
    128117                                sub.add( var, clz.bound );
    129                         } else if ( first ) {
     118                        } else if ( clzRep.empty() ) {
    130119                                clzRep = var;
    131                                 first = false;
    132120                        } else {
    133                                 sub.add( var, new TypeInstType{ clzRep } );
     121                                sub.add( var, new TypeInstType{ clzRep, clz.data.kind } );
    134122                        }
    135123                }
     
    146134        struct Occurs : public ast::WithVisitorRef<Occurs> {
    147135                bool result;
    148                 std::unordered_set< TypeInstType::TypeEnvKey > vars;
     136                std::set< std::string > vars;
    149137                const TypeEnvironment & tenv;
    150138
    151                 Occurs( const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env )
     139                Occurs( const std::string & var, const TypeEnvironment & env )
    152140                : result( false ), vars(), tenv( env ) {
    153141                        if ( const EqvClass * clz = tenv.lookup( var ) ) {
     
    159147
    160148                void previsit( const TypeInstType * typeInst ) {
    161                         if ( vars.count( *typeInst ) ) {
     149                        if ( vars.count( typeInst->name ) ) {
    162150                                result = true;
    163                         } else if ( const EqvClass * clz = tenv.lookup( *typeInst ) ) {
     151                        } else if ( const EqvClass * clz = tenv.lookup( typeInst->name ) ) {
    164152                                if ( clz->bound ) {
    165153                                        clz->bound->accept( *visitor );
     
    170158
    171159        /// true if `var` occurs in `ty` under `env`
    172         bool occurs( const Type * ty, const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env ) {
     160        bool occurs( const Type * ty, const std::string & var, const TypeEnvironment & env ) {
    173161                Pass<Occurs> occur{ var, env };
    174162                maybe_accept( ty, occur );
    175                 return occur.core.result;
    176         }
    177 }
    178 
    179 bool TypeEnvironment::combine(
     163                return occur.pass.result;
     164        }
     165}
     166
     167bool TypeEnvironment::combine( 
    180168                const TypeEnvironment & o, OpenVarSet & open, const SymbolTable & symtab ) {
    181169        // short-circuit easy cases
     
    211199                                auto st = internal_lookup( *vt );
    212200                                if ( st == env.end() ) {
    213                                         // unbound, safe to add if occurs
     201                                        // unbound, safe to add if occurs 
    214202                                        if ( r.bound && occurs( r.bound, *vt, *this ) ) return false;
    215203                                        r.vars.emplace( *vt );
     
    278266}
    279267
    280 bool TypeEnvironment::bindVar(
    281                 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
    282                 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen,
    283                 const SymbolTable & symtab
     268bool TypeEnvironment::bindVar( 
     269                const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
     270                AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen, 
     271                const SymbolTable & symtab 
    284272) {
    285273        // remove references from bound type, so that type variables can only bind to value types
    286274        ptr<Type> target = bindTo->stripReferences();
    287         auto tyvar = open.find( *typeInst );
     275        auto tyvar = open.find( typeInst->name );
    288276        assert( tyvar != open.end() );
    289277        if ( ! tyVarCompatible( tyvar->second, target ) ) return false;
    290         if ( occurs( target, *typeInst, *this ) ) return false;
    291 
    292         auto it = internal_lookup( *typeInst );
     278        if ( occurs( target, typeInst->name, *this ) ) return false;
     279
     280        auto it = internal_lookup( typeInst->name );
    293281        if ( it != env.end() ) {
    294282                if ( it->bound ) {
     
    298286                        ptr<Type> newType = it->bound;
    299287                        reset_qualifiers( newType, typeInst->qualifiers );
    300                         if ( unifyInexact(
    301                                         newType, target, *this, need, have, open,
     288                        if ( unifyInexact( 
     289                                        newType, target, *this, need, have, open, 
    302290                                        widen & WidenMode{ it->allowWidening, true }, symtab, common ) ) {
    303291                                if ( common ) {
     
    312300                }
    313301        } else {
    314                 env.emplace_back(
    315                         *typeInst, target, widen.first && widen.second, data );
     302                env.emplace_back( 
     303                        typeInst->name, target, widen.first && widen.second, data );
    316304        }
    317305        return true;
    318306}
    319307
    320 bool TypeEnvironment::bindVarToVar(
    321                 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
    322                 AssertionSet & need, AssertionSet & have, const OpenVarSet & open,
    323                 WidenMode widen, const SymbolTable & symtab
     308bool TypeEnvironment::bindVarToVar( 
     309                const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
     310                AssertionSet & need, AssertionSet & have, const OpenVarSet & open, 
     311                WidenMode widen, const SymbolTable & symtab 
    324312) {
    325         auto c1 = internal_lookup( *var1 );
    326         auto c2 = internal_lookup( *var2 );
    327 
     313        auto c1 = internal_lookup( var1->name );
     314        auto c2 = internal_lookup( var2->name );
     315       
    328316        // exit early if variables already bound together
    329317        if ( c1 != env.end() && c1 == c2 ) {
     
    338326        if ( c1 != env.end() ) {
    339327                if ( c1->bound ) {
    340                         if ( occurs( c1->bound, *var2, *this ) ) return false;
     328                        if ( occurs( c1->bound, var2->name, *this ) ) return false;
    341329                        type1 = c1->bound;
    342330                }
     
    345333        if ( c2 != env.end() ) {
    346334                if ( c2->bound ) {
    347                         if ( occurs( c2->bound, *var1, *this ) ) return false;
     335                        if ( occurs( c2->bound, var1->name, *this ) ) return false;
    348336                        type2 = c2->bound;
    349337                }
     
    383371        } else if ( c1 != env.end() ) {
    384372                // var2 unbound, add to env[c1]
    385                 c1->vars.emplace( *var2 );
     373                c1->vars.emplace( var2->name );
    386374                c1->allowWidening = widen1;
    387375                c1->data.isComplete |= data.isComplete;
    388376        } else if ( c2 != env.end() ) {
    389377                // var1 unbound, add to env[c2]
    390                 c2->vars.emplace( *var1 );
     378                c2->vars.emplace( var1->name );
    391379                c2->allowWidening = widen2;
    392380                c2->data.isComplete |= data.isComplete;
    393381        } else {
    394382                // neither var bound, create new class
    395                 env.emplace_back( *var1, *var2, widen1 && widen2, data );
     383                env.emplace_back( var1->name, var2->name, widen1 && widen2, data );
    396384        }
    397385
     
    408396}
    409397
    410 bool TypeEnvironment::mergeBound(
     398bool TypeEnvironment::mergeBound( 
    411399                EqvClass & to, const EqvClass & from, OpenVarSet & open, const SymbolTable & symtab ) {
    412400        if ( from.bound ) {
     
    418406                        AssertionSet need, have;
    419407
    420                         if ( unifyInexact(
     408                        if ( unifyInexact( 
    421409                                        toType, fromType, *this, need, have, open, widen, symtab, common ) ) {
    422410                                // unifies, set common type if necessary
     
    436424}
    437425
    438 bool TypeEnvironment::mergeClasses(
     426bool TypeEnvironment::mergeClasses( 
    439427        ClassList::iterator to, ClassList::iterator from, OpenVarSet & open, const SymbolTable & symtab
    440428) {
     
    457445}
    458446
    459 TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const TypeInstType::TypeEnvKey & var ) {
     447TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const std::string & var ) {
    460448        for ( ClassList::iterator i = env.begin(); i != env.end(); ++i ) {
    461449                if ( i->vars.count( var ) ) return i;
  • src/AST/TypeEnvironment.hpp

    reef8dfb rbdfc032  
    3737/// Adding this comparison operator significantly improves assertion satisfaction run time for
    3838/// some cases. The current satisfaction algorithm's speed partially depends on the order of
    39 /// assertions. Assertions which have fewer possible matches should appear before assertions
    40 /// which have more possible matches. This seems to imply that this could be further improved
    41 /// by providing an indexer as an additional argument and ordering based on the number of
     39/// assertions. Assertions which have fewer possible matches should appear before assertions 
     40/// which have more possible matches. This seems to imply that this could be further improved 
     41/// by providing an indexer as an additional argument and ordering based on the number of 
    4242/// matches of the same kind (object, function) for the names of the declarations.
    4343///
    44 /// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this
     44/// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 
    4545/// comparator.
    4646///
    47 /// Note: since this compares pointers for position, minor changes in the source file that
    48 /// affect memory layout can alter compilation time in unpredictable ways. For example, the
    49 /// placement of a line directive can reorder type pointers with respect to each other so that
    50 /// assertions are seen in different orders, causing a potentially different number of
    51 /// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27
    52 /// seconds by reordering line directives alone, so it would be nice to fix this comparison so
    53 /// that assertions compare more consistently. I've tried to modify this to compare on mangle
    54 /// name instead of type as the second comparator, but this causes some assertions to never be
     47/// Note: since this compares pointers for position, minor changes in the source file that 
     48/// affect memory layout can alter compilation time in unpredictable ways. For example, the 
     49/// placement of a line directive can reorder type pointers with respect to each other so that 
     50/// assertions are seen in different orders, causing a potentially different number of 
     51/// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 
     52/// seconds by reordering line directives alone, so it would be nice to fix this comparison so 
     53/// that assertions compare more consistently. I've tried to modify this to compare on mangle 
     54/// name instead of type as the second comparator, but this causes some assertions to never be 
    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
     
    8686void print( std::ostream &, const OpenVarSet &, Indenter indent = {} );
    8787
    88 /// Represents an equivalence class of bound type variables, optionally with the concrete type
     88/// Represents an equivalence class of bound type variables, optionally with the concrete type 
    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;
     
    9595
    9696        EqvClass() : vars(), bound(), allowWidening( true ), data() {}
    97 
     97       
    9898        /// Copy-with-bound constructor
    99         EqvClass( const EqvClass & o, const Type * b )
     99        EqvClass( const EqvClass & o, const Type * b ) 
    100100        : vars( o.vars ), bound( b ), allowWidening( o.allowWidening ), data( o.data ) {}
    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
    136         void add( const FunctionType::ForallList & tyDecls );
     136        void add( const ParameterizedType::ForallList & tyDecls );
    137137
    138138        /// Add a new equivalence class for each branch of the substitution, checking for conflicts
     
    142142        void writeToSubstitution( TypeSubstitution & sub ) const;
    143143
    144         template< typename node_t >
    145         auto apply( node_t && type ) const {
     144        template< typename node_t, enum Node::ref_type ref_t >
     145        int apply( ptr_base< node_t, ref_t > & type ) const {
    146146                TypeSubstitution sub;
    147147                writeToSubstitution( sub );
    148                 return sub.apply( std::forward<node_t>(type) );
    149         }
    150 
    151         template< typename node_t >
    152         auto applyFree( node_t && type ) const {
     148                return sub.apply( type );
     149        }
     150
     151        template< typename node_t, enum Node::ref_type ref_t >
     152        int applyFree( ptr_base< node_t, ref_t > & type ) const {
    153153                TypeSubstitution sub;
    154154                writeToSubstitution( sub );
    155                 return sub.applyFree( std::forward<node_t>(type) );
     155                return sub.applyFree( type );
    156156        }
    157157
     
    172172        void addActual( const TypeEnvironment & actualEnv, OpenVarSet & openVars );
    173173
    174         /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if
     174        /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 
    175175        /// needed. Returns false on failure.
    176         bool bindVar(
    177                 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
    178                 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
     176        bool bindVar( 
     177                const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
     178                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
    179179                ResolvExpr::WidenMode widen, const SymbolTable & symtab );
    180 
    181         /// Binds the type classes represented by `var1` and `var2` together; will add one or both
     180       
     181        /// Binds the type classes represented by `var1` and `var2` together; will add one or both 
    182182        /// classes if needed. Returns false on failure.
    183         bool bindVarToVar(
    184                 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
    185                 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
     183        bool bindVarToVar( 
     184                const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
     185                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
    186186                ResolvExpr::WidenMode widen, const SymbolTable & symtab );
    187187
     
    198198
    199199        /// Unifies the type bound of `to` with the type bound of `from`, returning false if fails
    200         bool mergeBound(
     200        bool mergeBound( 
    201201                EqvClass & to, const EqvClass & from, OpenVarSet & openVars, const SymbolTable & symtab );
    202202
    203203        /// Merges two type classes from local environment, returning false if fails
    204         bool mergeClasses(
    205                 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars,
     204        bool mergeClasses( 
     205                ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 
    206206                const SymbolTable & symtab );
    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

    reef8dfb rbdfc032  
    1919namespace ast {
    2020
    21 
    22 // size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");
    23 
    2421TypeSubstitution::TypeSubstitution() {
    2522}
     
    3936void TypeSubstitution::initialize( const TypeSubstitution &src, TypeSubstitution &dest ) {
    4037        dest.typeEnv.clear();
     38        dest.varEnv.clear();
    4139        dest.add( src );
    4240}
     
    4644                typeEnv[ i->first ] = i->second;
    4745        } // 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 );
     46        for ( VarEnvType::const_iterator i = other.varEnv.begin(); i != other.varEnv.end(); ++i ) {
     47                varEnv[ i->first ] = i->second;
     48        } // for
     49}
     50
     51void TypeSubstitution::add( std::string formalType, const Type *actualType ) {
     52        typeEnv[ formalType ] = actualType;
     53}
     54
     55void TypeSubstitution::addVar( std::string formalExpr, const Expr *actualExpr ) {
     56        varEnv[ formalExpr ] = actualExpr;
     57}
     58
     59void TypeSubstitution::remove( std::string formalType ) {
     60        TypeEnvType::iterator i = typeEnv.find( formalType );
    6061        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 );
     62                typeEnv.erase( formalType );
     63        } // if
     64}
     65
     66const Type *TypeSubstitution::lookup( std::string formalType ) const {
     67        TypeEnvType::const_iterator i = typeEnv.find( formalType );
    6768
    6869        // break on not in substitution set
     
    7172        // attempt to transitively follow TypeInstType links.
    7273        while ( const TypeInstType *actualType = i->second.as<TypeInstType>()) {
     74                const std::string& typeName = actualType->name;
     75
    7376                // break cycles in the transitive follow
    74                 if ( *formalType == *actualType ) break;
     77                if ( formalType == typeName ) break;
    7578
    7679                // Look for the type this maps to, returning previous mapping if none-such
    77                 i = typeEnv.find( *actualType );
     80                i = typeEnv.find( typeName );
    7881                if ( i == typeEnv.end() ) return actualType;
    7982        }
     
    8487
    8588bool TypeSubstitution::empty() const {
    86         return typeEnv.empty();
     89        return typeEnv.empty() && varEnv.empty();
    8790}
    8891
    8992namespace {
    9093        struct EnvTrimmer {
    91                 const TypeSubstitution * env;
     94                ptr<TypeSubstitution> env;
    9295                TypeSubstitution * newEnv;
    9396                EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
    94                 void previsit( FunctionType * ftype ) {
     97                void previsit( TypeDecl * tyDecl ) {
    9598                        // 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                                 }
     99                        if ( const Type * t = env->lookup( tyDecl->name ) ) {
     100                                newEnv->add( tyDecl->name, t );
    100101                        }
    101102                }
     
    107108        if ( env ) {
    108109                TypeSubstitution * newEnv = new TypeSubstitution();
     110#if TIME_TO_CONVERT_PASSES
    109111                Pass<EnvTrimmer> trimmer( env, newEnv );
    110112                expr->accept( trimmer );
     113#else
     114                (void)expr;
     115                (void)env;
     116#endif
    111117                return newEnv;
    112118        }
     
    115121
    116122void TypeSubstitution::normalize() {
    117         Pass<Substituter> sub( *this, true );
     123#if TIME_TO_CONVERT_PASSES
     124        PassVisitor<Substituter> sub( *this, true );
    118125        do {
    119                 sub.core.subCount = 0;
    120                 sub.core.freeOnly = true;
     126                sub.pass.subCount = 0;
     127                sub.pass.freeOnly = true;
    121128                for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) {
    122                         i->second = i->second->accept( sub );
     129                        i->second = i->second->acceptMutator( sub );
    123130                }
    124         } while ( sub.core.subCount );
    125 }
    126 
    127 const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
    128         BoundVarsType::const_iterator bound = boundVars.find( *inst );
     131        } while ( sub.pass.subCount );
     132#endif
     133}
     134
     135#if TIME_TO_CONVERT_PASSES
     136
     137Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) {
     138        BoundVarsType::const_iterator bound = boundVars.find( inst->name );
    129139        if ( bound != boundVars.end() ) return inst;
    130140
    131         TypeEnvType::const_iterator i = sub.typeEnv.find( *inst );
     141        TypeEnvType::const_iterator i = sub.typeEnv.find( inst->name );
    132142        if ( i == sub.typeEnv.end() ) {
    133143                return inst;
     
    136146                // Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here.
    137147                // TODO: investigate preventing type variables from being bound to themselves in the first place.
    138                 if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
    139                         if ( *inst == *replacement ) {
     148                if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {
     149                        if ( inst->name == replacement->name ) {
    140150                                return inst;
    141151                        }
     
    143153                // std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl;
    144154                subCount++;
    145                 ptr<Type> newType = i->second; // force clone if needed
    146                 add_qualifiers( newType, inst->qualifiers );
    147                 // Note: need to recursively apply substitution to the new type because normalize does not
    148                 // substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
    149                 newType = newType->accept( *visitor );
    150                 return newType.release();
    151         } // if
    152 }
    153 
    154 void TypeSubstitution::Substituter::previsit( const FunctionType * ptype ) {
     155                Type * newtype = i->second->clone();
     156                newtype->get_qualifiers() |= inst->get_qualifiers();
     157                delete inst;
     158                // Note: need to recursively apply substitution to the new type because normalize does not substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
     159                return newtype->acceptMutator( *visitor );
     160        } // if
     161}
     162
     163Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) {
     164        VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
     165        if ( i == sub.varEnv.end() ) {
     166                return nameExpr;
     167        } else {
     168                subCount++;
     169                delete nameExpr;
     170                return i->second->clone();
     171        } // if
     172}
     173
     174void TypeSubstitution::Substituter::premutate( Type * type ) {
    155175        GuardValue( boundVars );
    156176        // bind type variables from forall-qualifiers
    157177        if ( freeOnly ) {
    158                 for ( auto & tyvar : ptype->forall ) {
    159                                 boundVars.insert( *tyvar );
     178                for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
     179                        boundVars.insert( (*tyvar)->name );
    160180                } // for
    161181        } // if
    162182}
    163183
    164 /*
    165 void TypeSubstitution::Substituter::handleAggregateType( const BaseInstType * type ) {
     184template< typename TypeClass >
     185void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) {
    166186        GuardValue( boundVars );
    167187        // bind type variables from forall-qualifiers
    168188        if ( freeOnly ) {
     189                for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
     190                        boundVars.insert( (*tyvar)->name );
     191                } // for
    169192                // bind type variables from generic type instantiations
    170                 if ( auto decl = type->aggr() ) {
    171                         if ( ! type->params.empty() ) {
    172                                 for ( const TypeDecl * tyvar : decl->params ) {
    173                                         boundVars.insert( *tyvar );
    174                                 } // for
    175                         } // if
    176                 }
    177         } // if
    178 }
    179 
    180 void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) {
     193                std::list< TypeDecl* > *baseParameters = type->get_baseParameters();
     194                if ( baseParameters && ! type->parameters.empty() ) {
     195                        for ( std::list< TypeDecl* >::const_iterator tyvar = baseParameters->begin(); tyvar != baseParameters->end(); ++tyvar ) {
     196                                boundVars.insert( (*tyvar)->name );
     197                        } // for
     198                } // if
     199        } // if
     200}
     201
     202void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) {
    181203        handleAggregateType( aggregateUseType );
    182204}
    183205
    184 void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) {
     206void TypeSubstitution::Substituter::premutate( UnionInstType *aggregateUseType ) {
    185207        handleAggregateType( aggregateUseType );
    186208}
    187 */
     209
     210#endif
    188211
    189212} // namespace ast
  • src/AST/TypeSubstitution.hpp

    reef8dfb rbdfc032  
    4444        TypeSubstitution &operator=( const TypeSubstitution &other );
    4545
    46         template< typename SynTreeClass >
    47         struct ApplyResult {
    48                 ast::ptr<SynTreeClass> node;
    49                 int count;
    50         };
    51 
    52         template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const;
    53         template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const;
     46        template< typename SynTreeClass > int apply( const SynTreeClass *& input ) const;
     47        template< typename SynTreeClass > int applyFree( const SynTreeClass *& input ) const;
    5448
    5549        template< typename node_t, enum Node::ref_type ref_t >
    5650        int apply( ptr_base< node_t, ref_t > & input ) const {
    5751                const node_t * p = input.get();
    58                 auto ret = apply(p);
    59                 input = ret.node;
    60                 return ret.count;
     52                int ret = apply(p);
     53                input = p;
     54                return ret;
    6155        }
    6256
     
    6458        int applyFree( ptr_base< node_t, ref_t > & input ) const {
    6559                const node_t * p = input.get();
    66                 auto ret = applyFree(p);
    67                 input = ret.node;
    68                 return ret.count;
     60                int ret = applyFree(p);
     61                input = p;
     62                return ret;
    6963        }
    7064
    71         void add( const TypeInstType * formalType, const Type *actualType );
    72         void add( const TypeInstType::TypeEnvKey & key, const Type *actualType );
     65        void add( std::string formalType, const Type *actualType );
    7366        void add( const TypeSubstitution &other );
    74         void remove( const TypeInstType * formalType );
    75         const Type *lookup( const TypeInstType * formalType ) const;
     67        void remove( std::string formalType );
     68        const Type *lookup( std::string formalType ) const;
    7669        bool empty() const;
     70
     71        void addVar( std::string formalExpr, const Expr *actualExpr );
    7772
    7873        template< typename FormalIterator, typename ActualIterator >
     
    9792        void initialize( const TypeSubstitution &src, TypeSubstitution &dest );
    9893
    99         template<typename core_t>
     94        template<typename pass_type>
    10095        friend class Pass;
    10196
    102         typedef std::unordered_map< TypeInstType::TypeEnvKey, ptr<Type> > TypeEnvType;
     97        typedef std::unordered_map< std::string, ptr<Type> > TypeEnvType;
     98        typedef std::unordered_map< std::string, ptr<Expr> > VarEnvType;
    10399        TypeEnvType typeEnv;
     100        VarEnvType varEnv;
    104101
    105102  public:
     
    110107        auto   end() const -> decltype( typeEnv.  end() ) { return typeEnv.  end(); }
    111108
     109        auto beginVar()       -> decltype( varEnv.begin() ) { return varEnv.begin(); }
     110        auto   endVar()       -> decltype( varEnv.  end() ) { return varEnv.  end(); }
     111        auto beginVar() const -> decltype( varEnv.begin() ) { return varEnv.begin(); }
     112        auto   endVar() const -> decltype( varEnv.  end() ) { return varEnv.  end(); }
    112113};
    113114
    114 // this is the only place where type parameters outside a function formal may be substituted.
    115115template< typename FormalIterator, typename ActualIterator >
    116116void TypeSubstitution::add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
     
    123123                        if ( const TypeExpr *actual = actualIt->template as<TypeExpr>() ) {
    124124                                if ( formal->name != "" ) {
    125                                         typeEnv[ formal ] = actual->type;
     125                                        typeEnv[ formal->name ] = actual->type;
    126126                                } // if
    127127                        } else {
     
    129129                        } // if
    130130                } else {
    131                        
     131                        // TODO: type check the formal and actual parameters
     132                        if ( (*formalIt)->name != "" ) {
     133                                varEnv[ (*formalIt)->name ] = *actualIt;
     134                        } // if
    132135                } // if
    133136        } // for
    134137}
    135 
    136 
    137138
    138139template< typename FormalIterator, typename ActualIterator >
     
    141142}
    142143
    143 
    144144} // namespace ast
    145145
     
    147147// PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals.
    148148#include "Pass.hpp"
    149 #include "Copy.hpp"
    150149
    151150namespace ast {
    152151
    153152// definitition must happen after PassVisitor is included so that WithGuards can be used
    154 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter>, public PureVisitor {
    155                 static size_t traceId;
     153struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
    156154
    157155                Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
    158156
    159                 const Type * postvisit( const TypeInstType * aggregateUseType );
     157#if TIME_TO_CONVERT_PASSES
     158
     159                Type * postmutate( TypeInstType * aggregateUseType );
     160                Expression * postmutate( NameExpr * nameExpr );
    160161
    161162                /// Records type variable bindings from forall-statements
    162                 void previsit( const FunctionType * type );
     163                void premutate( Type * type );
    163164                /// 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 );
     165                template< typename TypeClass > void handleAggregateType( TypeClass * type );
     166
     167                void premutate( StructInstType * aggregateUseType );
     168                void premutate( UnionInstType * aggregateUseType );
     169
     170#endif
    168171
    169172                const TypeSubstitution & sub;
    170173                int subCount = 0;
    171174                bool freeOnly;
    172                 typedef std::unordered_set< TypeInstType::TypeEnvKey > BoundVarsType;
     175                typedef std::unordered_set< std::string > BoundVarsType;
    173176                BoundVarsType boundVars;
    174177
     
    176179
    177180template< typename SynTreeClass >
    178 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const {
     181int TypeSubstitution::apply( const SynTreeClass *& input ) const {
    179182        assert( input );
    180183        Pass<Substituter> sub( *this, false );
    181184        input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
    182         return { input, sub.core.subCount };
     185///     std::cerr << "substitution result is: ";
     186///     newType->print( std::cerr );
     187///     std::cerr << std::endl;
     188        return sub.pass.subCount;
    183189}
    184190
    185191template< typename SynTreeClass >
    186 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const {
     192int TypeSubstitution::applyFree( const SynTreeClass *& input ) const {
    187193        assert( input );
    188194        Pass<Substituter> sub( *this, true );
    189195        input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
    190         return { input, sub.core.subCount };
     196///     std::cerr << "substitution result is: ";
     197///     newType->print( std::cerr );
     198///     std::cerr << std::endl;
     199        return sub.pass.subCount;
    191200}
    192201
  • src/AST/Visitor.hpp

    reef8dfb rbdfc032  
    4747    virtual const ast::Stmt *             visit( const ast::CatchStmt            * ) = 0;
    4848    virtual const ast::Stmt *             visit( const ast::FinallyStmt          * ) = 0;
    49     virtual const ast::Stmt *             visit( const ast::SuspendStmt          * ) = 0;
    5049    virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) = 0;
    5150    virtual const ast::Decl *             visit( const ast::WithStmt             * ) = 0;
  • src/AST/module.mk

    reef8dfb rbdfc032  
    1717SRC_AST = \
    1818        AST/AssertAcyclic.cpp \
    19         AST/AssertAcyclic.hpp \
    2019        AST/Attribute.cpp \
    21         AST/Attribute.hpp \
    22         AST/Bitfield.hpp \
    23         AST/Chain.hpp \
    2420        AST/Convert.cpp \
    25         AST/Convert.hpp \
    26         AST/Copy.hpp \
    27         AST/CVQualifiers.hpp \
    2821        AST/Decl.cpp \
    29         AST/Decl.hpp \
    3022        AST/DeclReplacer.cpp \
    31         AST/DeclReplacer.hpp \
    32         AST/Eval.hpp \
    3323        AST/Expr.cpp \
    34         AST/Expr.hpp \
    35         AST/FunctionSpec.hpp \
    36         AST/Fwd.hpp \
    3724        AST/GenericSubstitution.cpp \
    38         AST/GenericSubstitution.hpp \
    3925        AST/Init.cpp \
    40         AST/Init.hpp \
    41         AST/Label.hpp \
    4226        AST/LinkageSpec.cpp \
    43         AST/LinkageSpec.hpp \
    4427        AST/Node.cpp \
    45         AST/Node.hpp \
    46         AST/ParseNode.hpp \
    4728        AST/Pass.cpp \
    48         AST/Pass.hpp \
    49         AST/Pass.impl.hpp \
    50         AST/Pass.proto.hpp \
    5129        AST/Print.cpp \
    52         AST/Print.hpp \
    5330        AST/Stmt.cpp \
    54         AST/Stmt.hpp \
    55         AST/StorageClasses.hpp \
    5631        AST/SymbolTable.cpp \
    57         AST/SymbolTable.hpp \
    58         AST/TranslationUnit.hpp \
    5932        AST/Type.cpp \
    60         AST/Type.hpp \
    6133        AST/TypeEnvironment.cpp \
    62         AST/TypeEnvironment.hpp \
    63         AST/TypeSubstitution.cpp \
    64         AST/TypeSubstitution.hpp \
    65         AST/Visitor.hpp
     34        AST/TypeSubstitution.cpp
    6635
    6736SRC += $(SRC_AST)
  • src/AST/porting.md

    reef8dfb rbdfc032  
    3030  * Base nodes now override `const Node * accept( Visitor & v ) const = 0` with, e.g. `const Stmt * accept( Visitor & v ) const override = 0`
    3131* `PassVisitor` is replaced with `ast::Pass`
    32   * Most one shot uses can use `ast::Pass::run` and `ast::Pass::read`.
    33 
    34 `WithConstTypeSubstitution`
    35 * `env` => `typeSubs`
    3632
    3733## Structural Changes ##
     
    5147      template<typename node_t>
    5248      friend node_t * mutate(const node_t * node);
    53       template<typename node_t>
    54       friend node_t * shallowCopy(const node_t * node);
    55     or equilant.
    56 * You should use the `mutate` function where possible as it avoids extra copies.
    57   * If you must copy use `shallowCopy` or `deepCopy` as required.
    5849
    5950All leaves of the `Node` inheritance tree are now declared `final`
     
    150141  * allows `newObject` as just default settings
    151142
    152 `FunctionDecl`
    153 * `params` and `returns` added.
    154   * Contain the declarations of the parameters and return variables.
    155   * Types should match (even be shared with) the fields of `type`.
    156 
    157143`NamedTypeDecl`
    158144* `parameters` => `params`
     
    163149`AggregateDecl`
    164150* `parameters` => `params`
    165 
    166 `StructDecl`
    167 * `makeInst` replaced by better constructor on `StructInstType`.
    168151
    169152`Expr`
     
    257240* **TODO** move `kind`, `typeNames` into code generator
    258241
    259 `ReferenceToType` => `BaseInstType`
     242`ReferenceToType`
    260243* deleted `get_baseParameters()` from children
    261244  * replace with `aggr() ? aggr()->params : nullptr`
     
    273256* `returnVals` => `returns`
    274257* `parameters` => `params`
    275   * Both now just point at types.
    276258* `bool isVarArgs;` => `enum ArgumentFlag { FixedArgs, VariableArgs }; ArgumentFlag isVarArgs;`
    277 
    278 `SueInstType`
    279 * Template class, with specializations and using to implement some other types:
    280   * `StructInstType`, `UnionInstType` & `EnumInstType`
    281259
    282260`TypeInstType`
  • src/CodeGen/CodeGenerator.cc

    reef8dfb rbdfc032  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 08:32:48 2020
    13 // Update Count     : 532
     12// Last Modified On : Fri Dec 13 23:13:28 2019
     13// Update Count     : 508
    1414//
    1515#include "CodeGenerator.h"
     
    3939        int CodeGenerator::tabsize = 4;
    4040
    41         // The kinds of statements that would ideally be followed by whitespace.
     41        // the kinds of statements that would ideally be followed by whitespace
    4242        bool wantSpacing( Statement * stmt) {
    4343                return dynamic_cast< IfStmt * >( stmt ) || dynamic_cast< CompoundStmt * >( stmt ) ||
     
    7878        }
    7979
    80         // Using updateLocation at the beginning of a node and endl within a node should become the method of formating.
     80        /* Using updateLocation at the beginning of a node and endl
     81         * within a node should become the method of formating.
     82         */
    8183        void CodeGenerator::updateLocation( CodeLocation const & to ) {
    8284                // skip if linemarks shouldn't appear or if codelocation is unset
     
    9395                } else {
    9496                        output << "\n# " << to.first_line << " \"" << to.filename
    95                                    << "\"\n" << indent;
     97                               << "\"\n" << indent;
    9698                        currentLocation = to;
    9799                }
     
    120122                // GCC builtins should always be printed unmangled
    121123                if ( options.pretty || decl->linkage.is_gcc_builtin ) return decl->name;
    122                 if ( LinkageSpec::isMangled(decl->linkage) && decl->mangleName != "" ) {
     124                if ( decl->mangleName != "" ) {
    123125                        // need to incorporate scope level in order to differentiate names for destructors
    124126                        return decl->get_scopedMangleName();
     
    129131
    130132        void CodeGenerator::genAttributes( list< Attribute * > & attributes ) {
    131                 if ( attributes.empty() ) return;
     133          if ( attributes.empty() ) return;
    132134                output << "__attribute__ ((";
    133135                for ( list< Attribute * >::iterator attr( attributes.begin() );; ) {
     
    138140                                output << ")";
    139141                        } // if
    140                         if ( ++attr == attributes.end() ) break;
     142                  if ( ++attr == attributes.end() ) break;
    141143                        output << ",";                                                          // separator
    142144                } // for
     
    163165                previsit( (BaseSyntaxNode *)node );
    164166                GuardAction( [this, node](){
    165                                 if ( options.printExprTypes && node->result ) {
    166                                         output << " /* " << genType( node->result, "", options ) << " */ ";
    167                                 }
    168                         } );
     167                        if ( options.printExprTypes && node->result ) {
     168                                output << " /* " << genType( node->result, "", options ) << " */ ";
     169                        }
     170                } );
    169171        }
    170172
     
    397399                extension( applicationExpr );
    398400                if ( VariableExpr * varExpr = dynamic_cast< VariableExpr* >( applicationExpr->get_function() ) ) {
    399                         const OperatorInfo * opInfo;
    400                         if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && ( opInfo = operatorLookup( varExpr->get_var()->get_name() ) ) ) {
     401                        OperatorInfo opInfo;
     402                        if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && operatorLookup( varExpr->get_var()->get_name(), opInfo ) ) {
    401403                                std::list< Expression* >::iterator arg = applicationExpr->get_args().begin();
    402                                 switch ( opInfo->type ) {
     404                                switch ( opInfo.type ) {
    403405                                  case OT_INDEX:
    404406                                        assert( applicationExpr->get_args().size() == 2 );
     
    421423                                                output << "(";
    422424                                                (*arg++)->accept( *visitor );
    423                                                 output << ") /* " << opInfo->inputName << " */";
     425                                                output << ") /* " << opInfo.inputName << " */";
    424426                                        } else if ( applicationExpr->get_args().size() == 2 ) {
    425427                                                // intrinsic two parameter constructors are essentially bitwise assignment
    426428                                                output << "(";
    427429                                                (*arg++)->accept( *visitor );
    428                                                 output << opInfo->symbol;
     430                                                output << opInfo.symbol;
    429431                                                (*arg)->accept( *visitor );
    430                                                 output << ") /* " << opInfo->inputName << " */";
     432                                                output << ") /* " << opInfo.inputName << " */";
    431433                                        } else {
    432434                                                // no constructors with 0 or more than 2 parameters
     
    439441                                        assert( applicationExpr->get_args().size() == 1 );
    440442                                        output << "(";
    441                                         output << opInfo->symbol;
     443                                        output << opInfo.symbol;
    442444                                        (*arg)->accept( *visitor );
    443445                                        output << ")";
     
    448450                                        assert( applicationExpr->get_args().size() == 1 );
    449451                                        (*arg)->accept( *visitor );
    450                                         output << opInfo->symbol;
     452                                        output << opInfo.symbol;
    451453                                        break;
    452454
     
    457459                                        output << "(";
    458460                                        (*arg++)->accept( *visitor );
    459                                         output << opInfo->symbol;
     461                                        output << opInfo.symbol;
    460462                                        (*arg)->accept( *visitor );
    461463                                        output << ")";
     
    484486                extension( untypedExpr );
    485487                if ( NameExpr * nameExpr = dynamic_cast< NameExpr* >( untypedExpr->function ) ) {
    486                         const OperatorInfo * opInfo = operatorLookup( nameExpr->name );
    487                         if ( opInfo ) {
     488                        OperatorInfo opInfo;
     489                        if ( operatorLookup( nameExpr->name, opInfo ) ) {
    488490                                std::list< Expression* >::iterator arg = untypedExpr->args.begin();
    489                                 switch ( opInfo->type ) {
     491                                switch ( opInfo.type ) {
    490492                                  case OT_INDEX:
    491493                                        assert( untypedExpr->args.size() == 2 );
     
    506508                                                output << "(";
    507509                                                (*arg++)->accept( *visitor );
    508                                                 output << ") /* " << opInfo->inputName << " */";
     510                                                output << ") /* " << opInfo.inputName << " */";
    509511                                        } else if ( untypedExpr->get_args().size() == 2 ) {
    510512                                                // intrinsic two parameter constructors are essentially bitwise assignment
    511513                                                output << "(";
    512514                                                (*arg++)->accept( *visitor );
    513                                                 output << opInfo->symbol;
     515                                                output << opInfo.symbol;
    514516                                                (*arg)->accept( *visitor );
    515                                                 output << ") /* " << opInfo->inputName << " */";
     517                                                output << ") /* " << opInfo.inputName << " */";
    516518                                        } else {
    517519                                                // no constructors with 0 or more than 2 parameters
     
    519521                                                output << "(";
    520522                                                (*arg++)->accept( *visitor );
    521                                                 output << opInfo->symbol << "{ ";
     523                                                output << opInfo.symbol << "{ ";
    522524                                                genCommaList( arg, untypedExpr->args.end() );
    523                                                 output << "}) /* " << opInfo->inputName << " */";
     525                                                output << "}) /* " << opInfo.inputName << " */";
    524526                                        } // if
    525527                                        break;
     
    530532                                        assert( untypedExpr->args.size() == 1 );
    531533                                        output << "(";
    532                                         output << opInfo->symbol;
     534                                        output << opInfo.symbol;
    533535                                        (*arg)->accept( *visitor );
    534536                                        output << ")";
     
    539541                                        assert( untypedExpr->args.size() == 1 );
    540542                                        (*arg)->accept( *visitor );
    541                                         output << opInfo->symbol;
     543                                        output << opInfo.symbol;
    542544                                        break;
    543545
     
    547549                                        output << "(";
    548550                                        (*arg++)->accept( *visitor );
    549                                         output << opInfo->symbol;
     551                                        output << opInfo.symbol;
    550552                                        (*arg)->accept( *visitor );
    551553                                        output << ")";
     
    579581        void CodeGenerator::postvisit( NameExpr * nameExpr ) {
    580582                extension( nameExpr );
    581                 const OperatorInfo * opInfo = operatorLookup( nameExpr->name );
    582                 if ( opInfo ) {
    583                         if ( opInfo->type == OT_CONSTANT ) {
    584                                 output << opInfo->symbol;
     583                OperatorInfo opInfo;
     584                if ( operatorLookup( nameExpr->name, opInfo ) ) {
     585                        if ( opInfo.type == OT_CONSTANT ) {
     586                                output << opInfo.symbol;
    585587                        } else {
    586                                 output << opInfo->outputName;
     588                                output << opInfo.outputName;
    587589                        }
    588590                } else {
     
    652654        void CodeGenerator::postvisit( VariableExpr * variableExpr ) {
    653655                extension( variableExpr );
    654                 const OperatorInfo * opInfo;
    655                 if ( variableExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && (opInfo = operatorLookup( variableExpr->get_var()->get_name() )) && opInfo->type == OT_CONSTANT ) {
    656                         output << opInfo->symbol;
     656                OperatorInfo opInfo;
     657                if ( variableExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && operatorLookup( variableExpr->get_var()->get_name(), opInfo ) && opInfo.type == OT_CONSTANT ) {
     658                        output << opInfo.symbol;
    657659                } else {
    658660                        output << mangleName( variableExpr->get_var() );
     
    10091011                  case BranchStmt::FallThroughDefault:
    10101012                        assertf( ! options.genC, "fallthru should not reach code generation." );
    1011                         output << "fallthru";
     1013                  output << "fallthru";
    10121014                        break;
    10131015                } // switch
     
    10331035
    10341036                output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ?
    1035                                    "throw" : "throwResume");
     1037                           "throw" : "throwResume");
    10361038                if (throwStmt->get_expr()) {
    10371039                        output << " ";
     
    10481050
    10491051                output << ((stmt->get_kind() == CatchStmt::Terminate) ?
    1050                                    "catch" : "catchResume");
     1052                "catch" : "catchResume");
    10511053                output << "( ";
    10521054                stmt->decl->accept( *visitor );
     
    11851187
    11861188        std::string genName( DeclarationWithType * decl ) {
    1187                 const OperatorInfo * opInfo = operatorLookup( decl->get_name() );
    1188                 if ( opInfo ) {
    1189                         return opInfo->outputName;
     1189                CodeGen::OperatorInfo opInfo;
     1190                if ( operatorLookup( decl->get_name(), opInfo ) ) {
     1191                        return opInfo.outputName;
    11901192                } else {
    11911193                        return decl->get_name();
  • src/CodeGen/CodeGenerator.h

    reef8dfb rbdfc032  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:58:31 2020
    13 // Update Count     : 62
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr 30 12:01:00 2019
     13// Update Count     : 57
    1414//
    1515
     
    2929namespace CodeGen {
    3030        struct CodeGenerator : public WithShortCircuiting, public WithGuards, public WithVisitorRef<CodeGenerator> {
    31                 static int tabsize;
     31          static int tabsize;
    3232
    3333                CodeGenerator( std::ostream &os, bool pretty = false, bool genC = false, bool lineMarks = false, bool printExprTypes = false );
     
    104104                void postvisit( AsmStmt * );
    105105                void postvisit( DirectiveStmt * );
    106                 void postvisit( AsmDecl * );                                    // special: statement in declaration context
     106                void postvisit( AsmDecl * );                            // special: statement in declaration context
    107107                void postvisit( IfStmt * );
    108108                void postvisit( SwitchStmt * );
     
    147147                LabelPrinter printLabels;
    148148                Options options;
    149           public:
     149        public:
    150150                LineEnder endl;
    151           private:
     151        private:
    152152
    153153                CodeLocation currentLocation;
     
    162162        template< class Iterator >
    163163        void CodeGenerator::genCommaList( Iterator begin, Iterator end ) {
    164                 if ( begin == end ) return;
     164          if ( begin == end ) return;
    165165                for ( ;; ) {
    166166                        (*begin++)->accept( *visitor );
    167                         if ( begin == end ) break;
     167                  if ( begin == end ) break;
    168168                        output << ", ";                                                         // separator
    169169                } // for
  • src/CodeGen/FixMain.cc

    reef8dfb rbdfc032  
    2626#include "SynTree/Declaration.h"   // for FunctionDecl, operator<<
    2727#include "SynTree/Type.h"          // for FunctionType
    28 #include "SymTab/Mangler.h"
    2928
    3029namespace CodeGen {
     
    4847                if( main_signature ) {
    4948                        os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";
    50                         main_signature->mangleName = SymTab::Mangler::mangle(main_signature.get());
    5149
    5250                        os << main_signature->get_scopedMangleName() << "(";
  • src/CodeGen/FixMain.h

    reef8dfb rbdfc032  
    1010// Created On       : Thr Jan 12 14:11:09 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:24:32 2020
    13 // Update Count     : 5
     12// Last Modified On : Fri Dec 13 23:12:21 2019
     13// Update Count     : 3
    1414//
    1515
     
    4242                static std::unique_ptr<FunctionDecl> main_signature;
    4343        };
    44 } // namespace CodeGen
     44};
  • src/CodeGen/FixNames.cc

    reef8dfb rbdfc032  
    3131#include "SynTree/Type.h"          // for Type, BasicType, Type::Qualifiers
    3232#include "SynTree/Visitor.h"       // for Visitor, acceptAll
    33 #include "CompilationState.h"
    3433
    3534namespace CodeGen {
     
    103102                if ( dwt->get_name() != "" ) {
    104103                        if ( LinkageSpec::isMangled( dwt->get_linkage() ) ) {
    105                                 if (!useNewAST) {
    106                                         dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) );
    107                                 }
     104                                dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) );
    108105                                dwt->set_scopeLevel( scopeLevel );
    109106                        } // if
  • src/CodeGen/GenType.h

    reef8dfb rbdfc032  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 04:11:40 2020
    13 // Update Count     : 5
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr 30 11:47:00 2019
     13// Update Count     : 3
    1414//
    1515
     
    2525        std::string genType( Type *type, const std::string &baseString, const Options &options );
    2626        std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false );
    27         std::string genPrettyType( Type * type, const std::string & baseString );
     27  std::string genPrettyType( Type * type, const std::string & baseString );
    2828} // namespace CodeGen
    2929
  • src/CodeGen/Generate.cc

    reef8dfb rbdfc032  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:01:51 2020
    13 // Update Count     : 9
     12// Last Modified On : Fri Dec 13 23:38:56 2019
     13// Update Count     : 8
    1414//
    1515#include "Generate.h"
     
    6464        void generate( BaseSyntaxNode * node, std::ostream & os ) {
    6565                if ( Type * type = dynamic_cast< Type * >( node ) ) {
    66                         os << genPrettyType( type, "" );
     66                        os << CodeGen::genPrettyType( type, "" );
    6767                } else {
    6868                        PassVisitor<CodeGenerator> cgv( os, true, false, false, false );
  • src/CodeGen/OperatorTable.cc

    reef8dfb rbdfc032  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 18 15:55:01 2020
    13 // Update Count     : 55
     12// Last Modified On : Sat Jul 15 17:12:22 2017
     13// Update Count     : 15
    1414//
    1515
     
    1717#include <map>        // for map, _Rb_tree_const_iterator, map<>::const_iterator
    1818#include <utility>    // for pair
    19 using namespace std;
    2019
    2120#include "OperatorTable.h"
     
    2322
    2423namespace CodeGen {
    25         const OperatorInfo CodeGen::tableValues[] = {
    26                 // inputName symbol   outputName                     friendlyName                  type
    27                 {       "?[?]",   "",     "_operator_index",             "Index",                      OT_INDEX          },
    28                 {       "?{}",    "=",    "_constructor",                "Constructor",                OT_CTOR           },
    29                 {       "^?{}",   "",     "_destructor",                 "Destructor",                 OT_DTOR           },
    30                 {       "?()",    "",     "_operator_call",              "Call Operator",              OT_CALL           },
    31                 {       "?++",    "++",   "_operator_postincr",          "Postfix Increment",          OT_POSTFIXASSIGN  },
    32                 {       "?--",    "--",   "_operator_postdecr",          "Postfix Decrement",          OT_POSTFIXASSIGN  },
    33                 {       "*?",     "*",    "_operator_deref",             "Dereference",                OT_PREFIX         },
    34                 {       "+?",     "+",    "_operator_unaryplus",         "Plus",                       OT_PREFIX         },
    35                 {       "-?",     "-",    "_operator_unaryminus",        "Minus",                      OT_PREFIX         },
    36                 {       "~?",     "~",    "_operator_bitnot",            "Bitwise Not",                OT_PREFIX         },
    37                 {       "!?",     "!",    "_operator_lognot",            "Logical Not",                OT_PREFIX         },
    38                 {       "++?",    "++",   "_operator_preincr",           "Prefix Increment",           OT_PREFIXASSIGN   },
    39                 {       "--?",    "--",   "_operator_predecr",           "Prefix Decrement",           OT_PREFIXASSIGN   },
    40                 {       "?\\?",   "\\",   "_operator_exponential",       "Exponentiation",             OT_INFIX          },
    41                 {       "?*?",    "*",    "_operator_multiply",          "Multiplication",             OT_INFIX          },
    42                 {       "?/?",    "/",    "_operator_divide",            "Division",                   OT_INFIX          },
    43                 {       "?%?",    "%",    "_operator_modulus",           "Modulo",                     OT_INFIX          },
    44                 {       "?+?",    "+",    "_operator_add",               "Addition",                   OT_INFIX          },
    45                 {       "?-?",    "-",    "_operator_subtract",          "Substraction",               OT_INFIX          },
    46                 {       "?<<?",   "<<",   "_operator_shiftleft",         "Shift Left",                 OT_INFIX          },
    47                 {       "?>>?",   ">>",   "_operator_shiftright",        "Shift Right",                OT_INFIX          },
    48                 {       "?<?",    "<",    "_operator_less",              "Less-than",                  OT_INFIX          },
    49                 {       "?>?",    ">",    "_operator_greater",           "Greater-than",               OT_INFIX          },
    50                 {       "?<=?",   "<=",   "_operator_lessequal",         "Less-than-or-Equal",         OT_INFIX          },
    51                 {       "?>=?",   ">=",   "_operator_greaterequal",      "Greater-than-or-Equal",      OT_INFIX          },
    52                 {       "?==?",   "==",   "_operator_equal",             "Equality",                   OT_INFIX          },
    53                 {       "?!=?",   "!=",   "_operator_notequal",          "Not-Equal",                  OT_INFIX          },
    54                 {       "?&?",    "&",    "_operator_bitand",            "Bitwise And",                OT_INFIX          },
    55                 {       "?^?",    "^",    "_operator_bitxor",            "Bitwise Xor",                OT_INFIX          },
    56                 {       "?|?",    "|",    "_operator_bitor",             "Bitwise Or",                 OT_INFIX          },
    57                 {       "?=?",    "=",    "_operator_assign",            "Assignment",                 OT_INFIXASSIGN    },
    58                 {       "?\\=?",  "\\=",  "_operator_expassign",         "Exponentiation Assignment",  OT_INFIXASSIGN    },
    59                 {       "?*=?",   "*=",   "_operator_multassign",        "Multiplication Assignment",  OT_INFIXASSIGN    },
    60                 {       "?/=?",   "/=",   "_operator_divassign",         "Division Assignment",        OT_INFIXASSIGN    },
    61                 {       "?%=?",   "%=",   "_operator_modassign",         "Modulo Assignment",          OT_INFIXASSIGN    },
    62                 {       "?+=?",   "+=",   "_operator_addassign",         "Addition Assignment",        OT_INFIXASSIGN    },
    63                 {       "?-=?",   "-=",   "_operator_subassign",         "Substrction Assignment",     OT_INFIXASSIGN    },
    64                 {       "?<<=?",  "<<=",  "_operator_shiftleftassign",   "Shift Left Assignment",      OT_INFIXASSIGN    },
    65                 {       "?>>=?",  ">>=",  "_operator_shiftrightassign",  "Shift Right Assignment",     OT_INFIXASSIGN    },
    66                 {       "?&=?",   "&=",   "_operator_bitandassign",      "Bitwise And Assignment",     OT_INFIXASSIGN    },
    67                 {       "?^=?",   "^=",   "_operator_bitxorassign",      "Bitwise Xor Assignment",     OT_INFIXASSIGN    },
    68                 {       "?|=?",   "|=",   "_operator_bitorassign",       "Bitwise Or Assignment",      OT_INFIXASSIGN    },
    69         }; // tableValues
     24        namespace {
     25                const OperatorInfo tableValues[] = {
     26                        {       "?[?]",         "",             "_operator_index",                              OT_INDEX                        },
     27                        {       "?{}",          "=",    "_constructor",                                 OT_CTOR                         },
     28                        {       "^?{}",         "",             "_destructor",                                  OT_DTOR                         },
     29                        {       "?()",          "",             "_operator_call",                               OT_CALL                         },
     30                        {       "?++",          "++",   "_operator_postincr",                   OT_POSTFIXASSIGN        },
     31                        {       "?--",          "--",   "_operator_postdecr",                   OT_POSTFIXASSIGN        },
     32                        {       "*?",           "*",    "_operator_deref",                              OT_PREFIX                       },
     33                        {       "+?",           "+",    "_operator_unaryplus",                  OT_PREFIX                       },
     34                        {       "-?",           "-",    "_operator_unaryminus",                 OT_PREFIX                       },
     35                        {       "~?",           "~",    "_operator_bitnot",                             OT_PREFIX                       },
     36                        {       "!?",           "!",    "_operator_lognot",                             OT_PREFIX                       },
     37                        {       "++?",          "++",   "_operator_preincr",                    OT_PREFIXASSIGN         },
     38                        {       "--?",          "--",   "_operator_predecr",                    OT_PREFIXASSIGN         },
     39                        {       "?\\?",         "\\",   "_operator_exponential",                OT_INFIX                        },
     40                        {       "?*?",          "*",    "_operator_multiply",                   OT_INFIX                        },
     41                        {       "?/?",          "/",    "_operator_divide",                             OT_INFIX                        },
     42                        {       "?%?",          "%",    "_operator_modulus",                    OT_INFIX                        },
     43                        {       "?+?",          "+",    "_operator_add",                                OT_INFIX                        },
     44                        {       "?-?",          "-",    "_operator_subtract",                   OT_INFIX                        },
     45                        {       "?<<?",         "<<",   "_operator_shiftleft",                  OT_INFIX                        },
     46                        {       "?>>?",         ">>",   "_operator_shiftright",                 OT_INFIX                        },
     47                        {       "?<?",          "<",    "_operator_less",                               OT_INFIX                        },
     48                        {       "?>?",          ">",    "_operator_greater",                    OT_INFIX                        },
     49                        {       "?<=?",         "<=",   "_operator_lessequal",                  OT_INFIX                        },
     50                        {       "?>=?",         ">=",   "_operator_greaterequal",               OT_INFIX                        },
     51                        {       "?==?",         "==",   "_operator_equal",                              OT_INFIX                        },
     52                        {       "?!=?",         "!=",   "_operator_notequal",                   OT_INFIX                        },
     53                        {       "?&?",          "&",    "_operator_bitand",                             OT_INFIX                        },
     54                        {       "?^?",          "^",    "_operator_bitxor",                             OT_INFIX                        },
     55                        {       "?|?",          "|",    "_operator_bitor",                              OT_INFIX                        },
     56                        {       "?=?",          "=",    "_operator_assign",                             OT_INFIXASSIGN          },
     57                        {       "?\\=?",        "\\=",  "_operator_expassign",                  OT_INFIXASSIGN          },
     58                        {       "?*=?",         "*=",   "_operator_multassign",                 OT_INFIXASSIGN          },
     59                        {       "?/=?",         "/=",   "_operator_divassign",                  OT_INFIXASSIGN          },
     60                        {       "?%=?",         "%=",   "_operator_modassign",                  OT_INFIXASSIGN          },
     61                        {       "?+=?",         "+=",   "_operator_addassign",                  OT_INFIXASSIGN          },
     62                        {       "?-=?",         "-=",   "_operator_subassign",                  OT_INFIXASSIGN          },
     63                        {       "?<<=?",        "<<=",  "_operator_shiftleftassign",    OT_INFIXASSIGN          },
     64                        {       "?>>=?",        ">>=",  "_operator_shiftrightassign",   OT_INFIXASSIGN          },
     65                        {       "?&=?",         "&=",   "_operator_bitandassign",               OT_INFIXASSIGN          },
     66                        {       "?^=?",         "^=",   "_operator_bitxorassign",               OT_INFIXASSIGN          },
     67                        {       "?|=?",         "|=",   "_operator_bitorassign",                OT_INFIXASSIGN          },
     68                };
    7069
    71         std::map< std::string, OperatorInfo > CodeGen::table;
     70                const int numOps = sizeof( tableValues ) / sizeof( OperatorInfo );
    7271
    73         CodeGen::CodeGen() {
    74                 enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) };
    75                 for ( int i = 0; i < numOps; i += 1 ) {
    76                         table[ tableValues[i].inputName ] = tableValues[i];
    77                 } // for
     72                std::map< std::string, OperatorInfo > table;
     73
     74                void initialize() {
     75                        for ( int i = 0; i < numOps; ++i ) {
     76                                table[ tableValues[i].inputName ] = tableValues[i];
     77                        } // for
     78                }
     79        } // namespace
     80
     81        bool operatorLookup( const std::string & funcName, OperatorInfo & info ) {
     82                static bool init = false;
     83                if ( ! init ) {
     84                        initialize();
     85                } // if
     86
     87                std::map< std::string, OperatorInfo >::const_iterator i = table.find( funcName );
     88                if ( i == table.end() ) {
     89                        if ( isPrefix( funcName, "?`" ) ) {
     90                                // handle literal suffixes, which are user-defined postfix operators
     91                                info.inputName = funcName;
     92                                info.symbol = funcName.substr(2);
     93                                info.outputName = toString( "__operator_literal_", info.symbol );
     94                                info.type = OT_POSTFIX;
     95                                return true;
     96                        }
     97                        return false;
     98                } else {
     99                        info = i->second;
     100                        return true;
     101                } // if
    78102        }
    79103
    80         const OperatorInfo * operatorLookup( const string & funcName ) {
    81                 if ( funcName.find_first_of( "?^*+-!", 0, 1 ) == string::npos ) return nullptr; // prefilter
    82                 const OperatorInfo * ret = &CodeGen::table.find( funcName )->second; // must be in the table
    83                 assert( ret );
    84                 return ret;
     104        bool isOperator( const std::string & funcName ) {
     105                OperatorInfo info;
     106                return operatorLookup( funcName, info );
    85107        }
    86108
    87         bool isOperator( const string & funcName ) {
    88                 return operatorLookup( funcName ) != nullptr;
    89         }
    90 
    91         string operatorFriendlyName( const string & funcName ) {
    92                 const OperatorInfo * info = operatorLookup( funcName );
    93                 if ( info ) return info->friendlyName;
    94                 return "";
    95         }
    96 
    97         bool isConstructor( const string & funcName ) {
    98                 const OperatorInfo * info = operatorLookup( funcName );
    99                 if ( info ) return info->type == OT_CTOR;
     109        /// determines if a given function name is one of the operator types between [begin, end)
     110        template<typename Iterator>
     111        bool isOperatorType( const std::string & funcName, Iterator begin, Iterator end ) {
     112                OperatorInfo info;
     113                if ( operatorLookup( funcName, info ) ) {
     114                        return std::find( begin, end, info.type ) != end;
     115                }
    100116                return false;
    101117        }
    102118
    103         bool isDestructor( const string & funcName ) {
    104                 const OperatorInfo * info = operatorLookup( funcName );
    105                 if ( info ) return info->type == OT_DTOR;
    106                 return false;
     119        bool isConstructor( const std::string & funcName ) {
     120                static OperatorType types[] = { OT_CTOR };
     121                return isOperatorType( funcName, std::begin(types), std::end(types) );
    107122        }
    108123
    109         bool isCtorDtor( const string & funcName ) {
    110                 const OperatorInfo * info = operatorLookup( funcName );
    111                 if ( info ) return info->type <= OT_CONSTRUCTOR;
    112                 return false;
     124        bool isDestructor( const std::string & funcName ) {
     125                static OperatorType types[] = { OT_DTOR };
     126                return isOperatorType( funcName, std::begin(types), std::end(types) );
    113127        }
    114128
    115         bool isAssignment( const string & funcName ) {
    116                 const OperatorInfo * info = operatorLookup( funcName );
    117                 if ( info ) return info->type > OT_CONSTRUCTOR && info->type <= OT_ASSIGNMENT;
    118                 return false;
     129        bool isAssignment( const std::string & funcName ) {
     130                static OperatorType types[] = { OT_PREFIXASSIGN, OT_POSTFIXASSIGN, OT_INFIXASSIGN };
     131                return isOperatorType( funcName, std::begin(types), std::end(types) );
    119132        }
    120133
    121         bool isCtorDtorAssign( const string & funcName ) {
    122                 const OperatorInfo * info = operatorLookup( funcName );
    123                 if ( info ) return info->type <= OT_ASSIGNMENT;
    124                 return false;
     134        bool isCtorDtor( const std::string & funcName ) {
     135                static OperatorType types[] = { OT_CTOR, OT_DTOR };
     136                return isOperatorType( funcName, std::begin(types), std::end(types) );
    125137        }
    126138
    127         CodeGen codegen;                                                                        // initialize singleton package
     139        bool isCtorDtorAssign( const std::string & funcName ) {
     140                static OperatorType types[] = { OT_CTOR, OT_DTOR, OT_PREFIXASSIGN, OT_POSTFIXASSIGN, OT_INFIXASSIGN };
     141                return isOperatorType( funcName, std::begin(types), std::end(types) );
     142        }
    128143} // namespace CodeGen
    129144
    130145// Local Variables: //
    131146// tab-width: 4 //
     147// mode: c++ //
     148// compile-command: "make install" //
    132149// End: //
  • src/CodeGen/OperatorTable.h

    reef8dfb rbdfc032  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 08:13:34 2020
    13 // Update Count     : 26
     12// Last Modified On : Fri Jul 21 22:17:11 2017
     13// Update Count     : 6
    1414//
    1515
     
    1717
    1818#include <string>
    19 #include <map>
    2019
    2120namespace CodeGen {
    2221        enum OperatorType {
     22                OT_INDEX,
    2323                OT_CTOR,
    2424                OT_DTOR,
    25                 OT_CONSTRUCTOR = OT_DTOR,
     25                OT_CALL,
     26                OT_PREFIX,
     27                OT_POSTFIX,
     28                OT_INFIX,
    2629                OT_PREFIXASSIGN,
    2730                OT_POSTFIXASSIGN,
    2831                OT_INFIXASSIGN,
    29                 OT_ASSIGNMENT = OT_INFIXASSIGN,
    30                 OT_CALL,
    31                 OT_PREFIX,
    32                 OT_INFIX,
    33                 OT_POSTFIX,
    34                 OT_INDEX,
    3532                OT_LABELADDRESS,
    3633                OT_CONSTANT
     
    4138                std::string symbol;
    4239                std::string outputName;
    43                 std::string friendlyName;
    4440                OperatorType type;
    4541        };
    4642
    47         class CodeGen {
    48                 friend const OperatorInfo * operatorLookup( const std::string & funcName );
    49 
    50                 static const OperatorInfo tableValues[];
    51                 static std::map< std::string, OperatorInfo > table;
    52           public:
    53                 CodeGen();
    54         }; // CodeGen
    55 
    5643        bool isOperator( const std::string & funcName );
    57         const OperatorInfo * operatorLookup( const std::string & funcName );
    58         std::string operatorFriendlyName( const std::string & funcName );
     44        bool operatorLookup( const std::string & funcName, OperatorInfo & info );
    5945
    6046        bool isConstructor( const std::string & );
  • src/CodeGen/Options.h

    reef8dfb rbdfc032  
    99// Author           : Andrew Beach
    1010// Created On       : Tue Apr 30 11:36:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 18:37:06 2020
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr May  2 10:45:00 2019
     13// Update Count     : 2
    1414//
    1515
    1616#pragma once
    1717
    18 struct Options {
    19         // External Options: Same thoughout a pass.
    20         bool pretty;
    21         bool genC;
    22         bool lineMarks;
    23         bool printExprTypes;
     18namespace CodeGen {
     19        struct Options {
     20                // External Options: Same thoughout a pass.
     21                bool pretty;
     22                bool genC;
     23                bool lineMarks;
     24                bool printExprTypes;
    2425
    25         // Internal Options: Changed on some recurisive calls.
    26         bool anonymousUnused = false;
     26                // Internal Options: Changed on some recurisive calls.
     27                bool anonymousUnused = false;
    2728
    28         Options(bool pretty, bool genC, bool lineMarks, bool printExprTypes) :
    29                 pretty(pretty), genC(genC), lineMarks(lineMarks), printExprTypes(printExprTypes)
     29                Options(bool pretty, bool genC, bool lineMarks, bool printExprTypes) :
     30                        pretty(pretty), genC(genC), lineMarks(lineMarks), printExprTypes(printExprTypes)
    3031                {}
    31 };
     32        };
     33} // namespace CodeGen
    3234
    3335// Local Variables: //
  • src/CodeGen/module.mk

    reef8dfb rbdfc032  
    2020SRC_CODEGEN = \
    2121        CodeGen/CodeGenerator.cc \
    22         CodeGen/CodeGenerator.h \
    2322        CodeGen/FixMain.cc \
    24         CodeGen/FixMain.h \
    2523        CodeGen/GenType.cc \
    26         CodeGen/GenType.h \
    27         CodeGen/OperatorTable.cc \
    28         CodeGen/OperatorTable.h \
    29         CodeGen/Options.h
     24        CodeGen/OperatorTable.cc
    3025
    31 SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/Generate.h CodeGen/FixNames.cc CodeGen/FixNames.h
     26SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/FixNames.cc
    3227SRCDEMANGLE += $(SRC_CODEGEN)
  • src/CodeTools/ResolvProtoDump.cc

    reef8dfb rbdfc032  
    99// Author           : Aaron Moss
    1010// Created On       : Tue Sep 11 09:04:00 2018
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 13:50:11 2020
    13 // Update Count     : 3
     11// Last Modified By : Aaron Moss
     12// Last Modified On : Tue Sep 11 09:04:00 2018
     13// Update Count     : 1
    1414//
    1515
     
    182182
    183183                        // replace operator names
    184                         const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( name );
    185                         if ( opInfo ) {
     184                        CodeGen::OperatorInfo info;
     185                        if ( CodeGen::operatorLookup( name, info ) ) {
    186186                                ss << new_prefix(pre, "");
    187                                 op_name( opInfo->outputName, ss );
     187                                op_name( info.outputName, ss );
    188188                                return;
    189189                        }
  • src/CodeTools/TrackLoc.cc

    reef8dfb rbdfc032  
    1010// Created On       : Tues May 2 15:46:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Nov 27 18:00:00 2020
    13 // Update Count     : 1
     12// Last Modified On : Wed May 3 14:43:00 2017
     13// Update Count     : 0
    1414//
    1515
     
    2222#include <string>                    // for operator<<, string
    2323#include <typeindex>                 // for type_index
    24 #include <vector>                    // for vector
    2524
    2625#include "Common/PassVisitor.h"      // for PassVisitor
     
    3837                CodeLocation *lastNode;
    3938
    40                 std::stack< CodeLocation *, std::vector< CodeLocation * > > parents;
     39                std::stack< CodeLocation * > parents;
    4140        public:
    4241                LocationPrinter(size_t printLevel) :
  • src/CodeTools/module.mk

    reef8dfb rbdfc032  
    1515###############################################################################
    1616
    17 SRC += \
    18         CodeTools/DeclStats.cc \
    19         CodeTools/DeclStats.h \
     17SRC += CodeTools/DeclStats.cc \
    2018        CodeTools/ResolvProtoDump.cc \
    21         CodeTools/ResolvProtoDump.h \
    22         CodeTools/TrackLoc.cc \
    23         CodeTools/TrackLoc.h
     19        CodeTools/TrackLoc.cc
  • src/Common/CodeLocation.h

    reef8dfb rbdfc032  
    4242        }
    4343
    44         bool startsBefore( CodeLocation const & other ) const {
    45                 if( filename < other.filename ) return true;
    46                 if( filename > other.filename ) return false;
    47 
    48                 if( first_line < other.first_line ) return true;
    49                 if( first_line > other.first_line ) return false;
    50 
    51                 if( last_line < other.last_line ) return true;
    52                 return false;
    53         }
    54 
    55         bool followedBy( CodeLocation const & other, int seperation ) const {
     44        bool followedBy( CodeLocation const & other, int seperation ) {
    5645                return (first_line + seperation == other.first_line &&
    5746                        filename == other.filename);
    5847        }
    5948
    60         bool operator==( CodeLocation const & other ) const {
     49        bool operator==( CodeLocation const & other ) {
    6150                return followedBy( other, 0 );
    6251        }
    6352
    64         bool operator!=( CodeLocation const & other ) const {
     53        bool operator!=( CodeLocation const & other ) {
    6554                return !(*this == other);
    6655        }
  • src/Common/Eval.cc

    reef8dfb rbdfc032  
    168168        if (expr) {
    169169                expr->accept(ev);
    170                 return std::make_pair(ev.core.value, ev.core.valid);
     170                return std::make_pair(ev.pass.value, ev.pass.valid);
    171171        } else {
    172172                return std::make_pair(0, false);
  • src/Common/PassVisitor.h

    reef8dfb rbdfc032  
    110110        virtual void visit( FinallyStmt * finallyStmt ) override final;
    111111        virtual void visit( const FinallyStmt * finallyStmt ) override final;
    112         virtual void visit( SuspendStmt * suspendStmt ) override final;
    113         virtual void visit( const SuspendStmt * suspendStmt ) override final;
    114112        virtual void visit( WaitForStmt * waitforStmt ) override final;
    115113        virtual void visit( const WaitForStmt * waitforStmt ) override final;
     
    278276        virtual Statement * mutate( CatchStmt * catchStmt ) override final;
    279277        virtual Statement * mutate( FinallyStmt * finallyStmt ) override final;
    280         virtual Statement * mutate( SuspendStmt * suspendStmt ) override final;
    281278        virtual Statement * mutate( WaitForStmt * waitforStmt ) override final;
    282279        virtual Declaration * mutate( WithStmt * withStmt ) override final;
     
    354351        virtual TypeSubstitution * mutate( TypeSubstitution * sub ) final;
    355352
    356         bool isInFunction() const {
    357                 return inFunction;
    358         }
    359 
    360353private:
    361354        bool inFunction = false;
    362         bool atFunctionTop = false;
    363355
    364356        template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor );
     
    531523public:
    532524        PassVisitor<pass_type> * const visitor = nullptr;
    533 
    534         bool isInFunction() const {
    535                 return visitor->isInFunction();
    536         }
    537525};
    538526
  • src/Common/PassVisitor.impl.h

    reef8dfb rbdfc032  
    532532                        indexerAddId( &func );
    533533                        maybeAccept_impl( node->type, *this );
    534                         // First remember that we are now within a function.
     534                        // function body needs to have the same scope as parameters - CompoundStmt will not enter
     535                        // a new scope if inFunction is true
    535536                        ValueGuard< bool > oldInFunction( inFunction );
    536537                        inFunction = true;
    537                         // The function body needs to have the same scope as parameters.
    538                         // A CompoundStmt will not enter a new scope if atFunctionTop is true.
    539                         ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
    540                         atFunctionTop = true;
    541538                        maybeAccept_impl( node->statements, *this );
    542539                        maybeAccept_impl( node->attributes, *this );
     
    570567                        indexerAddId( &func );
    571568                        maybeAccept_impl( node->type, *this );
    572                         // First remember that we are now within a function.
     569                        // function body needs to have the same scope as parameters - CompoundStmt will not enter
     570                        // a new scope if inFunction is true
    573571                        ValueGuard< bool > oldInFunction( inFunction );
    574572                        inFunction = true;
    575                         // The function body needs to have the same scope as parameters.
    576                         // A CompoundStmt will not enter a new scope if atFunctionTop is true.
    577                         ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
    578                         atFunctionTop = true;
    579573                        maybeAccept_impl( node->statements, *this );
    580574                        maybeAccept_impl( node->attributes, *this );
     
    607601                        indexerAddId( &func );
    608602                        maybeMutate_impl( node->type, *this );
    609                         // First remember that we are now within a function.
     603                        // function body needs to have the same scope as parameters - CompoundStmt will not enter
     604                        // a new scope if inFunction is true
    610605                        ValueGuard< bool > oldInFunction( inFunction );
    611606                        inFunction = true;
    612                         // The function body needs to have the same scope as parameters.
    613                         // A CompoundStmt will not enter a new scope if atFunctionTop is true.
    614                         ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
    615                         atFunctionTop = true;
    616607                        maybeMutate_impl( node->statements, *this );
    617608                        maybeMutate_impl( node->attributes, *this );
     
    835826        {
    836827                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
     828                maybeAccept_impl( node->parameters, *this );
    837829                maybeAccept_impl( node->base      , *this );
    838830        }
     
    857849        {
    858850                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
     851                maybeAccept_impl( node->parameters, *this );
    859852                maybeAccept_impl( node->base      , *this );
    860853        }
     
    878871        {
    879872                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
     873                maybeMutate_impl( node->parameters, *this );
    880874                maybeMutate_impl( node->base      , *this );
    881875        }
     
    901895        {
    902896                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
     897                maybeAccept_impl( node->parameters, *this );
    903898                maybeAccept_impl( node->base      , *this );
    904899        }
     
    917912        {
    918913                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
     914                maybeAccept_impl( node->parameters, *this );
    919915                maybeAccept_impl( node->base      , *this );
    920916        }
     
    933929        {
    934930                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
     931                maybeMutate_impl( node->parameters, *this );
    935932                maybeMutate_impl( node->base      , *this );
    936933        }
     
    10101007        VISIT_START( node );
    10111008        {
    1012                 // Do not enter a new scope if atFunctionTop is true, don't leave one either.
    1013                 ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
    1014                 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } );
     1009                // do not enter a new scope if inFunction is true - needs to check old state before the assignment
     1010                ValueGuard< bool > oldInFunction( inFunction );
     1011                auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeLeave(); } );
    10151012                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1016                 atFunctionTop = false;
     1013                inFunction = false;
    10171014                visitStatementList( node->kids );
    10181015        }
     
    10241021        VISIT_START( node );
    10251022        {
    1026                 // Do not enter a new scope if atFunctionTop is true, don't leave one either.
    1027                 ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
    1028                 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } );
     1023                // do not enter a new scope if inFunction is true - needs to check old state before the assignment
     1024                ValueGuard< bool > oldInFunction( inFunction );
     1025                auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeLeave(); } );
    10291026                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1030                 atFunctionTop = false;
     1027                inFunction = false;
    10311028                visitStatementList( node->kids );
    10321029        }
     
    10381035        MUTATE_START( node );
    10391036        {
    1040                 // Do not enter a new scope if atFunctionTop is true, don't leave one either.
    1041                 ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
    1042                 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } );
     1037                // do not enter a new scope if inFunction is true - needs to check old state before the assignment
     1038                ValueGuard< bool > oldInFunction( inFunction );
     1039                auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeLeave(); } );
    10431040                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1044                 atFunctionTop = false;
     1041                inFunction = false;
    10451042                mutateStatementList( node->kids );
    10461043        }
     
    15251522
    15261523//--------------------------------------------------------------------------
    1527 // SuspendStmt
    1528 template< typename pass_type >
    1529 void PassVisitor< pass_type >::visit( SuspendStmt * node ) {
    1530         VISIT_START( node );
    1531 
    1532         maybeAccept_impl( node->then  , *this );
    1533 
    1534         VISIT_END( node );
    1535 }
    1536 
    1537 template< typename pass_type >
    1538 void PassVisitor< pass_type >::visit( const SuspendStmt * node ) {
    1539         VISIT_START( node );
    1540 
    1541         maybeAccept_impl( node->then  , *this );
    1542 
    1543         VISIT_END( node );
    1544 }
    1545 
    1546 template< typename pass_type >
    1547 Statement * PassVisitor< pass_type >::mutate( SuspendStmt * node ) {
    1548         MUTATE_START( node );
    1549 
    1550         maybeMutate_impl( node->then  , *this );
    1551 
    1552         MUTATE_END( Statement, node );
    1553 }
    1554 
    1555 //--------------------------------------------------------------------------
    15561524// WaitForStmt
    15571525template< typename pass_type >
     
    33343302        VISIT_START( node );
    33353303
    3336         indexerAddUnion( node->name );
     3304        indexerAddStruct( node->name );
    33373305
    33383306        {
     
    33493317        VISIT_START( node );
    33503318
    3351         indexerAddUnion( node->name );
     3319        indexerAddStruct( node->name );
    33523320
    33533321        {
     
    33643332        MUTATE_START( node );
    33653333
    3366         indexerAddUnion( node->name );
     3334        indexerAddStruct( node->name );
    33673335
    33683336        {
  • src/Common/PassVisitor.proto.h

    reef8dfb rbdfc032  
    3838        };
    3939
    40         std::stack< cleanup_t, std::vector< cleanup_t > > cleanups;
     40        std::stack< cleanup_t > cleanups;
    4141};
    4242
  • src/Common/ScopedMap.h

    reef8dfb rbdfc032  
    9393
    9494                reference operator* () { return *it; }
    95                 pointer operator-> () const { return it.operator->(); }
     95                pointer operator-> () { return it.operator->(); }
    9696
    9797                iterator& operator++ () {
     
    249249
    250250        /// Gets the note at the given scope
    251         Note& getNote() { return scopes.back().note; }
    252         const Note& getNote() const { return scopes.back().note; }
    253251        Note& getNote( size_type i ) { return scopes[i].note; }
    254252        const Note& getNote( size_type i ) const { return scopes[i].note; }
  • src/Common/SemanticError.cc

    reef8dfb rbdfc032  
    9090void SemanticErrorException::print() {
    9191        using std::to_string;
    92 
    93         errors.sort([](const error & lhs, const error & rhs) -> bool {
    94                 if(lhs.location.startsBefore(rhs.location)) return true;
    95                 if(rhs.location.startsBefore(lhs.location)) return false;
    96 
    97                 return lhs.description < rhs.description;
    98         });
    99 
    10092        for( auto err : errors ) {
    10193                std::cerr << ErrorHelpers::bold() << err.location << ErrorHelpers::error_str() << ErrorHelpers::reset_font() << err.description << std::endl;
  • src/Common/SemanticError.h

    reef8dfb rbdfc032  
    4949struct WarningData {
    5050        const char * const name;
     51        const char * const message;
    5152        const Severity default_severity;
    52         const char * const message;
    5353};
    5454
    5555constexpr WarningData WarningFormats[] = {
    56         {"self-assign"            , Severity::Warn    , "self assignment of expression: %s"                          },
    57         {"reference-conversion"   , Severity::Warn    , "rvalue to reference conversion of rvalue: %s"               },
    58         {"qualifiers-zero_t-one_t", Severity::Warn    , "questionable use of type qualifier %s with %s"              },
    59         {"aggregate-forward-decl" , Severity::Warn    , "forward declaration of nested aggregate: %s"                },
    60         {"superfluous-decl"       , Severity::Warn    , "declaration does not allocate storage: %s"                  },
    61         {"gcc-attributes"         , Severity::Warn    , "invalid attribute: %s"                                      },
    62         {"c++-like-copy"          , Severity::Warn    , "Constructor from reference is not a valid copy constructor" },
     56        {"self-assign"            , "self assignment of expression: %s"            , Severity::Warn},
     57        {"reference-conversion"   , "rvalue to reference conversion of rvalue: %s" , Severity::Warn},
     58        {"qualifiers-zero_t-one_t", "questionable use of type qualifier %s with %s", Severity::Warn},
     59        {"aggregate-forward-decl" , "forward declaration of nested aggregate: %s"  , Severity::Warn},
     60        {"superfluous-decl"       , "declaration does not allocate storage: %s"    , Severity::Warn},
     61        {"gcc-attributes"         , "invalid attribute: %s"                        , Severity::Warn},
    6362};
    6463
     
    7069        SuperfluousDecl,
    7170        GccAttributes,
    72         CppCopy,
    7371        NUMBER_OF_WARNINGS, // This MUST be the last warning
    7472};
  • src/Common/Stats/Heap.cc

    reef8dfb rbdfc032  
    5353                const size_t passes_size = sizeof(passes) / sizeof(passes[0]);
    5454                size_t       passes_cnt = 1;
    55 
    56                 StatBlock    stacktrace_stats[100];
    57                 size_t       stacktrace_stats_count = 0;
    58                 bool         stacktrace_stats_enabled = true;
    59 
    60                 size_t       trace[1000];
    61                 const size_t stacktrace_max_depth = sizeof(trace) / sizeof(size_t);
    62                 size_t       stacktrace_depth;
    63 
    64                 size_t new_stacktrace_id(const char * const name) {
    65                         stacktrace_stats[stacktrace_stats_count].name = name;
    66                         return stacktrace_stats_count++;
    67                 }
    68 
    69                 void stacktrace_push(size_t id) {
    70                         ++stacktrace_depth;
    71                         assertf(stacktrace_depth < stacktrace_max_depth, "Stack trace too deep: increase size of array in Heap.cc");
    72                         trace[stacktrace_depth] = id;
    73                 }
    74 
    75                 void stacktrace_pop() {
    76                         assertf(stacktrace_depth > 0, "Invalid stack tracing operation: trace is empty");
    77                         --stacktrace_depth;
    78                 }
    7955
    8056                void newPass( const char * const name ) {
     
    140116                        for(size_t i = 0; i < passes_cnt; i++) {
    141117                                print(passes[i], nc, total_mallocs, total_frees, overall_peak);
    142                         }
    143 
    144                         print('-', nct);
    145                         std::cerr << std::setw(nc) << "Trace";
    146                         std::cerr << " |       Malloc Count |         Free Count |        Peak Allocs |" << std::endl;
    147 
    148                         print('-', nct);
    149                         for (size_t i = 0; i < stacktrace_stats_count; i++) {
    150                                 print(stacktrace_stats[i], nc, total_mallocs, total_frees, overall_peak);
    151118                        }
    152119                        print('-', nct);
     
    221188                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    222189                                }
    223 
    224                                 if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
    225                                         stacktrace_stats[trace[stacktrace_depth]].mallocs++;
    226                                 }
    227190                                return __malloc( size );
    228191                        }
     
    233196                                        passes[passes_cnt - 1].frees++;
    234197                                        passes[passes_cnt - 1].n_allocs--;
    235                                 }
    236                                 if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
    237                                         stacktrace_stats[trace[stacktrace_depth]].frees++;
    238198                                }
    239199                                return __free( ptr );
     
    248208                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    249209                                }
    250                                 if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
    251                                         stacktrace_stats[trace[stacktrace_depth]].mallocs++;
    252                                 }
    253210                                return __calloc( nelem, size );
    254211                        }
     
    261218                                        passes[passes_cnt - 1].frees++;
    262219                                } // if
    263                                 if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
    264                                         stacktrace_stats[trace[stacktrace_depth]].mallocs++;
    265                                         stacktrace_stats[trace[stacktrace_depth]].frees++;
    266                                 }
    267220                                return s;
    268221                        }
  • src/Common/Stats/Heap.h

    reef8dfb rbdfc032  
    2020                void newPass( const char * const name );
    2121                void print();
    22 
    23                 size_t new_stacktrace_id(const char * const name);
    24                 void stacktrace_push(size_t id);
    25                 void stacktrace_pop();
    2622        }
    2723}
  • src/Common/Stats/Stats.cc

    reef8dfb rbdfc032  
    3535        }
    3636
    37         namespace ResolveTime {
    38                 bool enabled = false;
    39         }
    40 
    4137        struct {
    4238                const char * const opt;
     
    4743                { "heap"    , Heap::enabled },
    4844                { "time"    , Time::enabled },
    49                 { "resolve" , ResolveTime::enabled },
    5045        };
    5146
  • src/Common/module.mk

    reef8dfb rbdfc032  
    1717SRC_COMMON = \
    1818      Common/Assert.cc \
    19       Common/CodeLocation.h \
    20       Common/CodeLocationTools.hpp \
    21       Common/CodeLocationTools.cpp \
    22       Common/CompilerError.h \
    23       Common/Debug.h \
    24       Common/ErrorObjects.h \
    2519      Common/Eval.cc \
    26       Common/Examine.cc \
    27       Common/Examine.h \
    28       Common/FilterCombos.h \
    29       Common/Indenter.h \
    3020      Common/PassVisitor.cc \
    31       Common/PassVisitor.h \
    32       Common/PassVisitor.impl.h \
    33       Common/PassVisitor.proto.h \
    34       Common/PersistentMap.h \
    35       Common/ScopedMap.h \
    3621      Common/SemanticError.cc \
    37       Common/SemanticError.h \
    38       Common/Stats.h \
    39       Common/Stats/Base.h \
    4022      Common/Stats/Counter.cc \
    41       Common/Stats/Counter.h \
    4223      Common/Stats/Heap.cc \
    43       Common/Stats/Heap.h \
    44       Common/Stats/ResolveTime.cc \
    45       Common/Stats/ResolveTime.h \
    4624      Common/Stats/Stats.cc \
    4725      Common/Stats/Time.cc \
    48       Common/Stats/Time.h \
    49       Common/UnimplementedError.h \
    50       Common/UniqueName.cc \
    51       Common/UniqueName.h \
    52       Common/utility.h \
    53       Common/VectorMap.h
     26      Common/UniqueName.cc
    5427
    5528SRC += $(SRC_COMMON) Common/DebugMalloc.cc
  • src/Common/utility.h

    reef8dfb rbdfc032  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 11 13:00:36 2020
    13 // Update Count     : 50
     12// Last Modified On : Wed Jul 24 14:28:19 2019
     13// Update Count     : 41
    1414//
    1515
     
    2929#include <utility>
    3030#include <vector>
    31 #include <cstring>                                                                              // memcmp
    3231
    3332#include "Common/Indenter.h"
     
    265264}
    266265
    267 // determines if pref is a prefix of str
    268 static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int start = 0 ) {
     266/// determines if `pref` is a prefix of `str`
     267static inline bool isPrefix( const std::string & str, const std::string & pref ) {
    269268        if ( pref.size() > str.size() ) return false;
    270     return 0 == memcmp( str.c_str() + start, pref.c_str(), pref.size() );
    271         // return prefix == full.substr(0, prefix.size()); // for future, requires c++17
     269        auto its = std::mismatch( pref.begin(), pref.end(), str.begin() );
     270        return its.first == pref.end();
    272271}
    273272
     
    360359        reverse_iterate_t( T & ref ) : ref(ref) {}
    361360
    362         // this does NOT work on const T!!!
    363         // typedef typename T::reverse_iterator iterator;
    364         auto begin() { return ref.rbegin(); }
    365         auto end() { return ref.rend(); }
     361        typedef typename T::reverse_iterator iterator;
     362        iterator begin() { return ref.rbegin(); }
     363        iterator end() { return ref.rend(); }
    366364};
    367365
  • src/CompilationState.cc

    reef8dfb rbdfc032  
    1414//
    1515
    16 #include "config.h"
    17 
    1816int
    1917        astp = false,
     
    2927        nopreludep = false,
    3028        genproto = false,
    31         deterministic_output = false,
    32         useNewAST = CFA_USE_NEW_AST,
    3329        nomainp = false,
    3430        parsep = false,
  • src/CompilationState.h

    reef8dfb rbdfc032  
    2828        nopreludep,
    2929        genproto,
    30         deterministic_output,
    31         useNewAST,
    3230        nomainp,
    3331        parsep,
  • src/Concurrency/Keywords.cc

    reef8dfb rbdfc032  
    1616#include "Concurrency/Keywords.h"
    1717
    18 #include <cassert>                        // for assert
    19 #include <string>                         // for string, operator==
    20 
    21 #include <iostream>
    22 
    23 #include "Common/Examine.h"               // for isMainFor
    24 #include "Common/PassVisitor.h"           // for PassVisitor
    25 #include "Common/SemanticError.h"         // for SemanticError
    26 #include "Common/utility.h"               // for deleteAll, map_range
    27 #include "CodeGen/OperatorTable.h"        // for isConstructor
    28 #include "ControlStruct/LabelGenerator.h" // for LebelGenerator
    29 #include "InitTweak/InitTweak.h"          // for getPointerBase
    30 #include "SynTree/LinkageSpec.h"          // for Cforall
    31 #include "SynTree/Constant.h"             // for Constant
    32 #include "SynTree/Declaration.h"          // for StructDecl, FunctionDecl, ObjectDecl
    33 #include "SynTree/Expression.h"           // for VariableExpr, ConstantExpr, Untype...
    34 #include "SynTree/Initializer.h"          // for SingleInit, ListInit, Initializer ...
    35 #include "SynTree/Label.h"                // for Label
    36 #include "SynTree/Statement.h"            // for CompoundStmt, DeclStmt, ExprStmt
    37 #include "SynTree/Type.h"                 // for StructInstType, Type, PointerType
    38 #include "SynTree/Visitor.h"              // for Visitor, acceptAll
    39 #include "Virtual/Tables.h"
     18#include <cassert>                 // for assert
     19#include <string>                  // for string, operator==
     20
     21#include "Common/PassVisitor.h"    // for PassVisitor
     22#include "Common/SemanticError.h"  // for SemanticError
     23#include "Common/utility.h"        // for deleteAll, map_range
     24#include "CodeGen/OperatorTable.h" // for isConstructor
     25#include "InitTweak/InitTweak.h"   // for getPointerBase
     26#include "SynTree/LinkageSpec.h"   // for Cforall
     27#include "SynTree/Constant.h"      // for Constant
     28#include "SynTree/Declaration.h"   // for StructDecl, FunctionDecl, ObjectDecl
     29#include "SynTree/Expression.h"    // for VariableExpr, ConstantExpr, Untype...
     30#include "SynTree/Initializer.h"   // for SingleInit, ListInit, Initializer ...
     31#include "SynTree/Label.h"         // for Label
     32#include "SynTree/Statement.h"     // for CompoundStmt, DeclStmt, ExprStmt
     33#include "SynTree/Type.h"          // for StructInstType, Type, PointerType
     34#include "SynTree/Visitor.h"       // for Visitor, acceptAll
    4035
    4136class Attribute;
    4237
    4338namespace Concurrency {
    44         inline static std::string getVTableName( std::string const & exception_name ) {
    45                 return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name);
    46         }
    47 
    48         // Only detects threads constructed with the keyword thread.
    49         inline static bool isThread( DeclarationWithType * decl ) {
    50                 Type * baseType = decl->get_type()->stripDeclarator();
    51                 StructInstType * instType = dynamic_cast<StructInstType *>( baseType );
    52                 if ( nullptr == instType ) { return false; }
    53                 return instType->baseStruct->is_thread();
    54         }
    55 
    5639        //=============================================================================================
    5740        // Pass declarations
     
    7053          public:
    7154
    72                 ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name,
    73                         std::string&& getter_name, std::string&& context_error, std::string&& exception_name,
    74                         bool needs_main, AggregateDecl::Aggregate cast_target ) :
    75                   type_name( type_name ), field_name( field_name ), getter_name( getter_name ),
    76                   context_error( context_error ), exception_name( exception_name ),
    77                   vtable_name( getVTableName( exception_name ) ),
    78                   needs_main( needs_main ), cast_target( cast_target ) {}
     55                ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main, AggregateDecl::Aggregate cast_target ) :
     56                  type_name( type_name ), field_name( field_name ), getter_name( getter_name ), context_error( context_error ), needs_main( needs_main ), cast_target( cast_target ) {}
    7957
    8058                virtual ~ConcurrentSueKeyword() {}
     
    8462
    8563                void handle( StructDecl * );
    86                 void addVtableForward( StructDecl * );
    8764                FunctionDecl * forwardDeclare( StructDecl * );
    8865                ObjectDecl * addField( StructDecl * );
     
    9875                const std::string getter_name;
    9976                const std::string context_error;
    100                 const std::string exception_name;
    101                 const std::string vtable_name;
    10277                bool needs_main;
    10378                AggregateDecl::Aggregate cast_target;
     
    10580                StructDecl   * type_decl = nullptr;
    10681                FunctionDecl * dtor_decl = nullptr;
    107                 StructDecl * except_decl = nullptr;
    108                 StructDecl * vtable_decl = nullptr;
    10982        };
    11083
     
    11588        //      int data;                                  int data;
    11689        //      a_struct_t more_data;                      a_struct_t more_data;
    117         //                                =>             $thread __thrd_d;
     90        //                                =>             thread_desc __thrd_d;
    11891        // };                                        };
    119         //                                           static inline $thread * get_thread( MyThread * this ) { return &this->__thrd_d; }
     92        //                                           static inline thread_desc * get_thread( MyThread * this ) { return &this->__thrd_d; }
    12093        //
    12194        class ThreadKeyword final : public ConcurrentSueKeyword {
     
    12396
    12497                ThreadKeyword() : ConcurrentSueKeyword(
    125                         "$thread",
     98                        "thread_desc",
    12699                        "__thrd",
    127100                        "get_thread",
    128101                        "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
    129                         "ThreadCancelled",
    130102                        true,
    131103                        AggregateDecl::Thread
     
    148120        //      int data;                                  int data;
    149121        //      a_struct_t more_data;                      a_struct_t more_data;
    150         //                                =>             $coroutine __cor_d;
     122        //                                =>             coroutine_desc __cor_d;
    151123        // };                                        };
    152         //                                           static inline $coroutine * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
     124        //                                           static inline coroutine_desc * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
    153125        //
    154126        class CoroutineKeyword final : public ConcurrentSueKeyword {
     
    156128
    157129                CoroutineKeyword() : ConcurrentSueKeyword(
    158                         "$coroutine",
     130                        "coroutine_desc",
    159131                        "__cor",
    160132                        "get_coroutine",
    161133                        "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
    162                         "CoroutineCancelled",
    163134                        true,
    164135                        AggregateDecl::Coroutine
     
    175146                }
    176147        };
    177 
    178 
    179148
    180149        //-----------------------------------------------------------------------------
     
    183152        //      int data;                                  int data;
    184153        //      a_struct_t more_data;                      a_struct_t more_data;
    185         //                                =>             $monitor __mon_d;
     154        //                                =>             monitor_desc __mon_d;
    186155        // };                                        };
    187         //                                           static inline $monitor * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
     156        //                                           static inline monitor_desc * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
    188157        //
    189158        class MonitorKeyword final : public ConcurrentSueKeyword {
     
    191160
    192161                MonitorKeyword() : ConcurrentSueKeyword(
    193                         "$monitor",
     162                        "monitor_desc",
    194163                        "__mon",
    195164                        "get_monitor",
    196165                        "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
    197                         "",
    198166                        false,
    199167                        AggregateDecl::Monitor
     
    212180
    213181        //-----------------------------------------------------------------------------
    214         //Handles generator type declarations :
    215         // generator MyGenerator {                   struct MyGenerator {
    216         //      int data;                                  int data;
    217         //      a_struct_t more_data;                      a_struct_t more_data;
    218         //                                =>             int __gen_next;
    219         // };                                        };
    220         //
    221         class GeneratorKeyword final : public ConcurrentSueKeyword {
    222           public:
    223 
    224                 GeneratorKeyword() : ConcurrentSueKeyword(
    225                         "$generator",
    226                         "__generator_state",
    227                         "get_generator",
    228                         "Unable to find builtin type $generator\n",
    229                         "",
    230                         true,
    231                         AggregateDecl::Generator
    232                 )
    233                 {}
    234 
    235                 virtual ~GeneratorKeyword() {}
    236 
    237                 virtual bool is_target( StructDecl * decl ) override final { return decl->is_generator(); }
    238 
    239                 static void implement( std::list< Declaration * > & translationUnit ) {
    240                         PassVisitor< GeneratorKeyword > impl;
    241                         mutateAll( translationUnit, impl );
    242                 }
    243         };
    244 
    245 
    246         //-----------------------------------------------------------------------------
    247         class SuspendKeyword final : public WithStmtsToAdd, public WithGuards {
    248         public:
    249                 SuspendKeyword() = default;
    250                 virtual ~SuspendKeyword() = default;
    251 
    252                 void  premutate( FunctionDecl * );
    253                 DeclarationWithType * postmutate( FunctionDecl * );
    254 
    255                 Statement * postmutate( SuspendStmt * );
    256 
    257                 static void implement( std::list< Declaration * > & translationUnit ) {
    258                         PassVisitor< SuspendKeyword > impl;
    259                         mutateAll( translationUnit, impl );
    260                 }
    261 
    262         private:
    263                 bool is_real_suspend( FunctionDecl * );
    264 
    265                 Statement * make_generator_suspend( SuspendStmt * );
    266                 Statement * make_coroutine_suspend( SuspendStmt * );
    267 
    268                 struct LabelPair {
    269                         Label obj;
    270                         int   idx;
    271                 };
    272 
    273                 LabelPair make_label() {
    274                         labels.push_back( gen.newLabel("generator") );
    275                         return { labels.back(), int(labels.size()) };
    276                 }
    277 
    278                 DeclarationWithType * in_generator = nullptr;
    279                 FunctionDecl * decl_suspend = nullptr;
    280                 std::vector<Label> labels;
    281                 ControlStruct::LabelGenerator & gen = *ControlStruct::LabelGenerator::getGenerator();
    282         };
    283 
    284         //-----------------------------------------------------------------------------
    285182        //Handles mutex routines definitions :
    286183        // void foo( A * mutex a, B * mutex b,  int i ) {                  void foo( A * a, B * b,  int i ) {
    287         //                                                                       $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
     184        //                                                                       monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
    288185        //                                                                       monitor_guard_t __guard = { __monitors, 2 };
    289186        //    /*Some code*/                                       =>           /*Some code*/
     
    298195                std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first );
    299196                void validate( DeclarationWithType * );
    300                 void addDtorStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
    301                 void addStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
    302                 void addThreadDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args );
     197                void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
     198                void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
    303199
    304200                static void implement( std::list< Declaration * > & translationUnit ) {
     
    311207                StructDecl* guard_decl = nullptr;
    312208                StructDecl* dtor_guard_decl = nullptr;
    313                 StructDecl* thread_guard_decl = nullptr;
    314209
    315210                static std::unique_ptr< Type > generic_func;
     
    326221        //Handles mutex routines definitions :
    327222        // void foo( A * mutex a, B * mutex b,  int i ) {                  void foo( A * a, B * b,  int i ) {
    328         //                                                                       $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
     223        //                                                                       monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
    329224        //                                                                       monitor_guard_t __guard = { __monitors, 2 };
    330225        //    /*Some code*/                                       =>           /*Some code*/
     
    356251                CoroutineKeyword        ::implement( translationUnit );
    357252                MonitorKeyword  ::implement( translationUnit );
    358                 GeneratorKeyword  ::implement( translationUnit );
    359                 SuspendKeyword    ::implement( translationUnit );
    360253        }
    361254
     
    390283                        handle( decl );
    391284                }
    392                 else if ( !except_decl && exception_name == decl->name && decl->body ) {
    393                         except_decl = decl;
    394                 }
    395                 else if ( !vtable_decl && vtable_name == decl->name && decl->body ) {
    396                         vtable_decl = decl;
    397                 }
    398                 // Might be able to get ride of is target.
    399                 assert( is_target(decl) == (cast_target == decl->kind) );
    400285                return decl;
    401286        }
    402287
    403288        DeclarationWithType * ConcurrentSueKeyword::postmutate( FunctionDecl * decl ) {
    404                 if ( type_decl && isDestructorFor( decl, type_decl ) )
    405                         dtor_decl = decl;
    406                 else if ( vtable_name.empty() )
    407                         ;
    408                 else if( !decl->has_body() )
    409                         ;
    410                 else if ( auto param = isMainFor( decl, cast_target ) ) {
    411                         // This should never trigger.
    412                         assert( vtable_decl );
    413                         // Should be safe because of isMainFor.
    414                         StructInstType * struct_type = static_cast<StructInstType *>(
    415                                 static_cast<ReferenceType *>( param->get_type() )->base );
    416                         assert( struct_type );
    417 
    418                         std::list< Expression * > poly_args = { new TypeExpr( struct_type->clone() ) };
    419                         ObjectDecl * vtable_object = Virtual::makeVtableInstance(
    420                                 vtable_decl->makeInst( poly_args ), struct_type, nullptr );
    421                         declsToAddAfter.push_back( vtable_object );
    422                         declsToAddAfter.push_back( Virtual::makeGetExceptionFunction(
    423                                 vtable_object, except_decl->makeInst( std::move( poly_args ) )
    424                         ) );
    425                 }
    426 
     289                if( !type_decl ) return decl;
     290                if( !CodeGen::isDestructor( decl->name ) ) return decl;
     291
     292                auto params = decl->type->parameters;
     293                if( params.size() != 1 ) return decl;
     294
     295                auto type = dynamic_cast<ReferenceType*>( params.front()->get_type() );
     296                if( !type ) return decl;
     297
     298                auto stype = dynamic_cast<StructInstType*>( type->base );
     299                if( !stype ) return decl;
     300                if( stype->baseStruct != type_decl ) return decl;
     301
     302                if( !dtor_decl ) dtor_decl = decl;
    427303                return decl;
    428304        }
     
    430306        Expression * ConcurrentSueKeyword::postmutate( KeywordCastExpr * cast ) {
    431307                if ( cast_target == cast->target ) {
    432                         // convert (thread &)t to ($thread &)*get_thread(t), etc.
     308                        // convert (thread &)t to (thread_desc &)*get_thread(t), etc.
    433309                        if( !type_decl ) SemanticError( cast, context_error );
    434310                        if( !dtor_decl ) SemanticError( cast, context_error );
     
    448324                if( !dtor_decl ) SemanticError( decl, context_error );
    449325
    450                 addVtableForward( decl );
    451326                FunctionDecl * func = forwardDeclare( decl );
    452327                ObjectDecl * field = addField( decl );
    453328                addRoutines( field, func );
    454         }
    455 
    456         void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) {
    457                 if ( vtable_decl ) {
    458                         std::list< Expression * > poly_args = {
    459                                 new TypeExpr( new StructInstType( noQualifiers, decl ) ),
    460                         };
    461                         declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
    462                                 vtable_decl->makeInst( poly_args ),
    463                                 except_decl->makeInst( poly_args )
    464                         ) );
    465                         declsToAddBefore.push_back( Virtual::makeVtableForward(
    466                                 vtable_decl->makeInst( move( poly_args ) ) ) );
    467                 // Its only an error if we want a vtable and don't have one.
    468                 } else if ( ! vtable_name.empty() ) {
    469                         SemanticError( decl, context_error );
    470                 }
    471329        }
    472330
     
    519377                        get_type,
    520378                        nullptr,
    521                         { new Attribute("const") },
     379                        noAttributes,
    522380                        Type::Inline
    523381                );
     
    576434                                                new CastExpr(
    577435                                                        new VariableExpr( func->get_functionType()->get_parameters().front() ),
    578                                                         func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone(),
    579                                                         false
     436                                                        func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone()
    580437                                                )
    581438                                        )
     
    589446
    590447                declsToAddAfter.push_back( get_decl );
    591         }
    592 
    593         //=============================================================================================
    594         // Suspend keyword implementation
    595         //=============================================================================================
    596         bool SuspendKeyword::is_real_suspend( FunctionDecl * func ) {
    597                 if(isMangled(func->linkage)) return false; // the real suspend isn't mangled
    598                 if(func->name != "__cfactx_suspend") return false; // the real suspend has a specific name
    599                 if(func->type->parameters.size() != 0) return false; // Too many parameters
    600                 if(func->type->returnVals.size() != 0) return false; // Too many return values
    601 
    602                 return true;
    603         }
    604 
    605         void SuspendKeyword::premutate( FunctionDecl * func ) {
    606                 GuardValue(in_generator);
    607                 in_generator = nullptr;
    608 
    609                 // Is this the real suspend?
    610                 if(is_real_suspend(func)) {
    611                         decl_suspend = decl_suspend ? decl_suspend : func;
    612                         return;
    613                 }
    614 
    615                 // Is this the main of a generator?
    616                 auto param = isMainFor( func, AggregateDecl::Aggregate::Generator );
    617                 if(!param) return;
    618 
    619                 if(func->type->returnVals.size() != 0) SemanticError(func->location, "Generator main must return void");
    620 
    621                 in_generator = param;
    622                 GuardValue(labels);
    623                 labels.clear();
    624         }
    625 
    626         DeclarationWithType * SuspendKeyword::postmutate( FunctionDecl * func ) {
    627                 if( !func->statements ) return func; // Not the actual definition, don't do anything
    628                 if( !in_generator     ) return func; // Not in a generator, don't do anything
    629                 if( labels.empty()    ) return func; // Generator has no states, nothing to do, could throw a warning
    630 
    631                 // This is a generator main, we need to add the following code to the top
    632                 // static void * __generator_labels[] = {&&s0, &&s1, ...};
    633                 // goto * __generator_labels[gen.__generator_state];
    634                 const auto & loc = func->location;
    635 
    636                 const auto first_label = gen.newLabel("generator");
    637 
    638                 // for each label add to declaration
    639                 std::list<Initializer*> inits = { new SingleInit( new LabelAddressExpr( first_label ) ) };
    640                 for(const auto & label : labels) {
    641                         inits.push_back(
    642                                 new SingleInit(
    643                                         new LabelAddressExpr( label )
    644                                 )
    645                         );
    646                 }
    647                 auto init = new ListInit(std::move(inits), noDesignators, true);
    648                 labels.clear();
    649 
    650                 // create decl
    651                 auto decl = new ObjectDecl(
    652                         "__generator_labels",
    653                         Type::StorageClasses( Type::Static ),
    654                         LinkageSpec::AutoGen,
    655                         nullptr,
    656                         new ArrayType(
    657                                 Type::Qualifiers(),
    658                                 new PointerType(
    659                                         Type::Qualifiers(),
    660                                         new VoidType( Type::Qualifiers() )
    661                                 ),
    662                                 nullptr,
    663                                 false, false
    664                         ),
    665                         init
    666                 );
    667 
    668                 // create the goto
    669                 assert(in_generator);
    670 
    671                 auto go_decl = new ObjectDecl(
    672                         "__generator_label",
    673                         noStorageClasses,
    674                         LinkageSpec::AutoGen,
    675                         nullptr,
    676                         new PointerType(
    677                                 Type::Qualifiers(),
    678                                 new VoidType( Type::Qualifiers() )
    679                         ),
    680                         new SingleInit(
    681                                 new UntypedExpr(
    682                                         new NameExpr("?[?]"),
    683                                         {
    684                                                 new NameExpr("__generator_labels"),
    685                                                 new UntypedMemberExpr(
    686                                                         new NameExpr("__generator_state"),
    687                                                         new VariableExpr( in_generator )
    688                                                 )
    689                                         }
    690                                 )
    691                         )
    692                 );
    693                 go_decl->location = loc;
    694 
    695                 auto go = new BranchStmt(
    696                         new VariableExpr( go_decl ),
    697                         BranchStmt::Goto
    698                 );
    699                 go->location = loc;
    700                 go->computedTarget->location = loc;
    701 
    702                 auto noop = new NullStmt({ first_label });
    703                 noop->location = loc;
    704 
    705                 // wrap everything in a nice compound
    706                 auto body = new CompoundStmt({
    707                         new DeclStmt( decl ),
    708                         new DeclStmt( go_decl ),
    709                         go,
    710                         noop,
    711                         func->statements
    712                 });
    713                 body->location   = loc;
    714                 func->statements = body;
    715 
    716                 return func;
    717         }
    718 
    719         Statement * SuspendKeyword::postmutate( SuspendStmt * stmt ) {
    720                 SuspendStmt::Type type = stmt->type;
    721                 if(type == SuspendStmt::None) {
    722                         // This suspend has a implicit target, find it
    723                         type = in_generator ? SuspendStmt::Generator : SuspendStmt::Coroutine;
    724                 }
    725 
    726                 // Check that the target makes sense
    727                 if(!in_generator && type == SuspendStmt::Generator) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type.");
    728 
    729                 // Act appropriately
    730                 switch(type) {
    731                         case SuspendStmt::Generator: return make_generator_suspend(stmt);
    732                         case SuspendStmt::Coroutine: return make_coroutine_suspend(stmt);
    733                         default: abort();
    734                 }
    735         }
    736 
    737         Statement * SuspendKeyword::make_generator_suspend( SuspendStmt * stmt ) {
    738                 assert(in_generator);
    739                 // Target code is :
    740                 //   gen.__generator_state = X;
    741                 //   { THEN }
    742                 //   return;
    743                 //   __gen_X:;
    744 
    745                 // Save the location and delete the old statement, we only need the location from this point on
    746                 auto loc = stmt->location;
    747 
    748                 // Build the label and get its index
    749                 auto label = make_label();
    750 
    751                 // Create the context saving statement
    752                 auto save = new ExprStmt( new UntypedExpr(
    753                         new NameExpr( "?=?" ),
    754                         {
    755                                 new UntypedMemberExpr(
    756                                         new NameExpr("__generator_state"),
    757                                         new VariableExpr( in_generator )
    758                                 ),
    759                                 new ConstantExpr(
    760                                         Constant::from_int( label.idx )
    761                                 )
    762                         }
    763                 ));
    764                 assert(save->expr);
    765                 save->location = loc;
    766                 stmtsToAddBefore.push_back( save );
    767 
    768                 // if we have a then add it here
    769                 auto then = stmt->then;
    770                 stmt->then = nullptr;
    771                 delete stmt;
    772                 if(then) stmtsToAddBefore.push_back( then );
    773 
    774                 // Create the return statement
    775                 auto ret = new ReturnStmt( nullptr );
    776                 ret->location = loc;
    777                 stmtsToAddBefore.push_back( ret );
    778 
    779                 // Create the null statement with the created label
    780                 auto noop = new NullStmt({ label.obj });
    781                 noop->location = loc;
    782 
    783                 // Return the null statement to take the place of the previous statement
    784                 return noop;
    785         }
    786 
    787         Statement * SuspendKeyword::make_coroutine_suspend( SuspendStmt * stmt ) {
    788                 if(stmt->then) SemanticError( stmt->location, "Compound statement following coroutines is not implemented.");
    789 
    790                 // Save the location and delete the old statement, we only need the location from this point on
    791                 auto loc = stmt->location;
    792                 delete stmt;
    793 
    794                 // Create the call expression
    795                 if(!decl_suspend) SemanticError( loc, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n");
    796                 auto expr = new UntypedExpr( VariableExpr::functionPointer( decl_suspend ) );
    797                 expr->location = loc;
    798 
    799                 // Change this statement into a regular expr
    800                 assert(expr);
    801                 auto nstmt = new ExprStmt( expr );
    802                 nstmt->location = loc;
    803                 return nstmt;
    804         }
    805 
     448
     449                // get_decl->fixUniqueId();
     450        }
    806451
    807452        //=============================================================================================
     
    813458                bool first = false;
    814459                std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first );
    815                 bool const isDtor = CodeGen::isDestructor( decl->name );
     460                bool isDtor = CodeGen::isDestructor( decl->name );
    816461
    817462                // Is this function relevant to monitors
     
    861506
    862507                // Instrument the body
    863                 if ( isDtor && isThread( mutexArgs.front() ) ) {
    864                         if( !thread_guard_decl ) {
    865                                 SemanticError( decl, "thread destructor requires threads to be in scope, add #include <thread.hfa>\n" );
    866                         }
    867                         addThreadDtorStatements( decl, body, mutexArgs );
    868                 }
    869                 else if ( isDtor ) {
    870                         addDtorStatements( decl, body, mutexArgs );
     508                if( isDtor ) {
     509                        addDtorStatments( decl, body, mutexArgs );
    871510                }
    872511                else {
    873                         addStatements( decl, body, mutexArgs );
     512                        addStatments( decl, body, mutexArgs );
    874513                }
    875514        }
     
    877516        void MutexKeyword::postvisit(StructDecl* decl) {
    878517
    879                 if( decl->name == "$monitor" && decl->body ) {
     518                if( decl->name == "monitor_desc" && decl->body ) {
    880519                        assert( !monitor_decl );
    881520                        monitor_decl = decl;
     
    888527                        assert( !dtor_guard_decl );
    889528                        dtor_guard_decl = decl;
    890                 }
    891                 else if( decl->name == "thread_dtor_guard_t" && decl->body ) {
    892                         assert( !thread_guard_decl );
    893                         thread_guard_decl = decl;
    894529                }
    895530        }
     
    930565        }
    931566
    932         void MutexKeyword::addDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
     567        void MutexKeyword::addDtorStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
    933568                Type * arg_type = args.front()->get_type()->clone();
    934569                arg_type->set_mutex( false );
     
    948583                        new SingleInit( new UntypedExpr(
    949584                                new NameExpr( "get_monitor" ),
    950                                 {  new CastExpr( new VariableExpr( args.front() ), arg_type, false ) }
     585                                {  new CastExpr( new VariableExpr( args.front() ), arg_type ) }
    951586                        ))
    952587                );
     
    969604                                        {
    970605                                                new SingleInit( new AddressExpr( new VariableExpr( monitors ) ) ),
    971                                                 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) ),
    972                                                 new SingleInit( new ConstantExpr( Constant::from_bool( false ) ) )
     606                                                new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) )
    973607                                        },
    974608                                        noDesignators,
     
    978612                );
    979613
    980                 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
    981                 body->push_front( new DeclStmt( monitors ) );
    982         }
    983 
    984         void MutexKeyword::addThreadDtorStatements(
    985                         FunctionDecl*, CompoundStmt * body,
    986                         const std::list<DeclarationWithType * > & args ) {
    987                 assert( args.size() == 1 );
    988                 DeclarationWithType * arg = args.front();
    989                 Type * arg_type = arg->get_type()->clone();
    990                 assert( arg_type->get_mutex() );
    991                 arg_type->set_mutex( false );
    992 
    993                 // thread_dtor_guard_t __guard = { this, intptr( 0 ) };
    994                 body->push_front(
    995                         new DeclStmt( new ObjectDecl(
    996                                 "__guard",
    997                                 noStorageClasses,
    998                                 LinkageSpec::Cforall,
    999                                 nullptr,
    1000                                 new StructInstType(
    1001                                         noQualifiers,
    1002                                         thread_guard_decl
    1003                                 ),
    1004                                 new ListInit(
    1005                                         {
    1006                                                 new SingleInit( new CastExpr( new VariableExpr( arg ), arg_type ) ),
    1007                                                 new SingleInit( new UntypedExpr(
    1008                                                         new NameExpr( "intptr" ), {
    1009                                                                 new ConstantExpr( Constant::from_int( 0 ) ),
    1010                                                         }
    1011                                                 ) ),
    1012                                         },
    1013                                         noDesignators,
    1014                                         true
    1015                                 )
    1016                         ))
    1017                 );
    1018         }
    1019 
    1020         void MutexKeyword::addStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
     614                //monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
     615                body->push_front( new DeclStmt( monitors) );
     616        }
     617
     618        void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
    1021619                ObjectDecl * monitors = new ObjectDecl(
    1022620                        "__monitors",
     
    1043641                                        return new SingleInit( new UntypedExpr(
    1044642                                                new NameExpr( "get_monitor" ),
    1045                                                 {  new CastExpr( new VariableExpr( var ), type, false ) }
     643                                                {  new CastExpr( new VariableExpr( var ), type ) }
    1046644                                        ) );
    1047645                                })
     
    1067665                                                new SingleInit( new VariableExpr( monitors ) ),
    1068666                                                new SingleInit( new ConstantExpr( Constant::from_ulong( args.size() ) ) ),
    1069                                                 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) )
     667                                                new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) )
    1070668                                        },
    1071669                                        noDesignators,
     
    1075673                );
    1076674
    1077                 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
     675                //monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
    1078676                body->push_front( new DeclStmt( monitors) );
    1079677        }
     
    1083681        //=============================================================================================
    1084682        void ThreadStarter::previsit( StructDecl * decl ) {
    1085                 if( decl->name == "$thread" && decl->body ) {
     683                if( decl->name == "thread_desc" && decl->body ) {
    1086684                        assert( !thread_decl );
    1087685                        thread_decl = decl;
     
    1129727// tab-width: 4 //
    1130728// End: //
    1131 
  • src/Concurrency/Waitfor.cc

    reef8dfb rbdfc032  
    244244                        decl_mask = decl;
    245245                }
    246                 else if( decl->name == "$monitor" ) {
     246                else if( decl->name == "monitor_desc" ) {
    247247                        assert( !decl_monitor );
    248248                        decl_monitor = decl;
     
    384384                                                                decl_monitor
    385385                                                        )
    386                                                 ),
    387                                                 false
     386                                                )
    388387                                        );
    389388
     
    409408                        new CompoundStmt({
    410409                                makeAccStatement( acceptables, index, "is_dtor", detectIsDtor( clause.target.function )                                    , indexer ),
    411                                 makeAccStatement( acceptables, index, "func"   , new CastExpr( clause.target.function, fptr_t, false )                     , indexer ),
     410                                makeAccStatement( acceptables, index, "func"   , new CastExpr( clause.target.function, fptr_t )                            , indexer ),
    412411                                makeAccStatement( acceptables, index, "data"   , new VariableExpr( monitors )                                              , indexer ),
    413412                                makeAccStatement( acceptables, index, "size"   , new ConstantExpr( Constant::from_ulong( clause.target.arguments.size() ) ), indexer ),
     
    532531                                                                decl_mask
    533532                                                        )
    534                                                 ),
    535                                                 false
     533                                                )
    536534                                        ),
    537535                                        timeout
  • src/Concurrency/module.mk

    reef8dfb rbdfc032  
    1515###############################################################################
    1616
    17 SRC += Concurrency/Keywords.cc Concurrency/Keywords.h Concurrency/Waitfor.cc Concurrency/Waitfor.h
     17SRC += Concurrency/Keywords.cc Concurrency/Waitfor.cc
    1818SRCDEMANGLE += Concurrency/Keywords.cc
    1919
  • src/ControlStruct/ExceptTranslate.cc

    reef8dfb rbdfc032  
    99// Author           : Andrew Beach
    1010// Created On       : Wed Jun 14 16:49:00 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jun 24 11:18:00 2020
    13 // Update Count     : 17
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:40:15 2019
     13// Update Count     : 12
    1414//
    1515
     
    6464        }
    6565
    66         class ThrowMutatorCore : public WithGuards {
    67                 ObjectDecl * terminate_handler_except;
    68                 enum Context { NoHandler, TerHandler, ResHandler } cur_context;
    69 
    70                 // The helper functions for code/syntree generation.
    71                 Statement * create_either_throw(
    72                         ThrowStmt * throwStmt, const char * throwFunc );
    73                 Statement * create_terminate_rethrow( ThrowStmt * throwStmt );
    74 
    75         public:
    76                 ThrowMutatorCore() :
    77                         terminate_handler_except( nullptr ),
    78                         cur_context( NoHandler )
    79                 {}
    80 
    81                 void premutate( CatchStmt *catchStmt );
    82                 Statement * postmutate( ThrowStmt *throwStmt );
    83         };
    84 
    85         // ThrowStmt Mutation Helpers
    86 
    87         Statement * ThrowMutatorCore::create_either_throw(
    88                         ThrowStmt * throwStmt, const char * throwFunc ) {
    89                 // `throwFunc`( `throwStmt->get_name()` );
    90                 UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) );
    91                 call->get_args().push_back( throwStmt->get_expr() );
    92                 throwStmt->set_expr( nullptr );
    93                 delete throwStmt;
    94                 return new ExprStmt( call );
    95         }
    96 
    97         Statement * ThrowMutatorCore::create_terminate_rethrow(
    98                         ThrowStmt *throwStmt ) {
    99                 // { `terminate_handler_except` = 0p; __rethrow_terminate(); }
    100                 assert( nullptr == throwStmt->get_expr() );
    101                 assert( terminate_handler_except );
    102 
    103                 CompoundStmt * result = new CompoundStmt();
    104                 result->labels =  throwStmt->labels;
    105                 result->push_back( new ExprStmt( UntypedExpr::createAssign(
    106                         nameOf( terminate_handler_except ),
    107                         new ConstantExpr( Constant::null(
    108                                 terminate_handler_except->get_type()->clone()
    109                                 ) )
    110                         ) ) );
    111                 result->push_back( new ExprStmt(
    112                         new UntypedExpr( new NameExpr( "__cfaehm_rethrow_terminate" ) )
    113                         ) );
    114                 delete throwStmt;
    115                 return result;
    116         }
    117 
    118         // Visiting/Mutating Functions
    119 
    120         void ThrowMutatorCore::premutate( CatchStmt *catchStmt ) {
    121                 // Validate the statement's form.
    122                 ObjectDecl * decl = dynamic_cast<ObjectDecl *>( catchStmt->get_decl() );
    123                 // Also checking the type would be nice.
    124                 if ( !decl || !dynamic_cast<PointerType *>( decl->type ) ) {
    125                         std::string kind = (CatchStmt::Terminate == catchStmt->kind) ? "catch" : "catchResume";
    126                         SemanticError( catchStmt->location, kind + " must have pointer to an exception type" );
    127                 }
    128 
    129                 // Track the handler context.
    130                 GuardValue( cur_context );
    131                 if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
    132                         cur_context = TerHandler;
    133 
    134                         GuardValue( terminate_handler_except );
    135                         terminate_handler_except = decl;
    136                 } else {
    137                         cur_context = ResHandler;
    138                 }
    139         }
    140 
    141         Statement * ThrowMutatorCore::postmutate( ThrowStmt *throwStmt ) {
    142                 // Ignoring throwStmt->get_target() for now.
    143                 if ( ThrowStmt::Terminate == throwStmt->get_kind() ) {
    144                         if ( throwStmt->get_expr() ) {
    145                                 return create_either_throw( throwStmt, "$throw" );
    146                         } else if ( TerHandler == cur_context ) {
    147                                 return create_terminate_rethrow( throwStmt );
    148                         } else {
    149                                 abort("Invalid throw in %s at %i\n",
    150                                         throwStmt->location.filename.c_str(),
    151                                         throwStmt->location.first_line);
    152                         }
    153                 } else {
    154                         if ( throwStmt->get_expr() ) {
    155                                 return create_either_throw( throwStmt, "$throwResume" );
    156                         } else if ( ResHandler == cur_context ) {
    157                                 // This has to be handled later.
    158                                 return throwStmt;
    159                         } else {
    160                                 abort("Invalid throwResume in %s at %i\n",
    161                                         throwStmt->location.filename.c_str(),
    162                                         throwStmt->location.first_line);
    163                         }
    164                 }
    165         }
    166 
    167         class TryMutatorCore {
     66        class ExceptionMutatorCore : public WithGuards {
     67                enum Context { NoHandler, TerHandler, ResHandler };
     68
     69                // Also need to handle goto, break & continue.
     70                // They need to be cut off in a ResHandler, until we enter another
     71                // loop, switch or the goto stays within the function.
     72
     73                Context cur_context;
     74
     75                // The current (innermost) termination handler exception declaration.
     76                ObjectDecl * handler_except_decl;
     77
    16878                // The built in types used in translation.
    16979                StructDecl * except_decl;
     
    17282
    17383                // The many helper functions for code/syntree generation.
     84                Statement * create_given_throw(
     85                        const char * throwFunc, ThrowStmt * throwStmt );
     86                Statement * create_terminate_throw( ThrowStmt * throwStmt );
     87                Statement * create_terminate_rethrow( ThrowStmt * throwStmt );
     88                Statement * create_resume_throw( ThrowStmt * throwStmt );
     89                Statement * create_resume_rethrow( ThrowStmt * throwStmt );
    17490                CompoundStmt * take_try_block( TryStmt * tryStmt );
    17591                FunctionDecl * create_try_wrapper( CompoundStmt * body );
     
    185101                FunctionDecl * create_finally_wrapper( TryStmt * tryStmt );
    186102                ObjectDecl * create_finally_hook( FunctionDecl * finally_wrapper );
    187                 Statement * create_resume_rethrow( ThrowStmt * throwStmt );
    188103
    189104                // Types used in translation, make sure to use clone.
     
    206121
    207122        public:
    208                 TryMutatorCore() :
     123                ExceptionMutatorCore() :
     124                        cur_context( NoHandler ),
     125                        handler_except_decl( nullptr ),
    209126                        except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr ),
    210127                        try_func_t( noQualifiers, false ),
     
    215132                {}
    216133
     134                void premutate( CatchStmt *catchStmt );
    217135                void premutate( StructDecl *structDecl );
     136                Statement * postmutate( ThrowStmt *throwStmt );
    218137                Statement * postmutate( TryStmt *tryStmt );
    219                 Statement * postmutate( ThrowStmt *throwStmt );
    220138        };
    221139
    222         void TryMutatorCore::init_func_types() {
     140        void ExceptionMutatorCore::init_func_types() {
    223141                assert( except_decl );
    224142
     
    278196        }
    279197
     198        // ThrowStmt Mutation Helpers
     199
     200        Statement * ExceptionMutatorCore::create_given_throw(
     201                        const char * throwFunc, ThrowStmt * throwStmt ) {
     202                // `throwFunc`( `throwStmt->get_name` );
     203                UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) );
     204                call->get_args().push_back( throwStmt->get_expr() );
     205                throwStmt->set_expr( nullptr );
     206                delete throwStmt;
     207                return new ExprStmt( call );
     208        }
     209
     210        Statement * ExceptionMutatorCore::create_terminate_throw(
     211                        ThrowStmt *throwStmt ) {
     212                // __throw_terminate( `throwStmt->get_name()` ); }
     213                return create_given_throw( "__cfaabi_ehm__throw_terminate", throwStmt );
     214        }
     215
     216        Statement * ExceptionMutatorCore::create_terminate_rethrow(
     217                        ThrowStmt *throwStmt ) {
     218                // { `handler_except_decl` = NULL; __rethrow_terminate(); }
     219                assert( nullptr == throwStmt->get_expr() );
     220                assert( handler_except_decl );
     221
     222                CompoundStmt * result = new CompoundStmt();
     223                result->labels =  throwStmt->labels;
     224                result->push_back( new ExprStmt( UntypedExpr::createAssign(
     225                        nameOf( handler_except_decl ),
     226                        new ConstantExpr( Constant::null(
     227                                new PointerType(
     228                                        noQualifiers,
     229                                        handler_except_decl->get_type()->clone()
     230                                        )
     231                                ) )
     232                        ) ) );
     233                result->push_back( new ExprStmt(
     234                        new UntypedExpr( new NameExpr( "__cfaabi_ehm__rethrow_terminate" ) )
     235                        ) );
     236                delete throwStmt;
     237                return result;
     238        }
     239
     240        Statement * ExceptionMutatorCore::create_resume_throw(
     241                        ThrowStmt *throwStmt ) {
     242                // __throw_resume( `throwStmt->get_name` );
     243                return create_given_throw( "__cfaabi_ehm__throw_resume", throwStmt );
     244        }
     245
     246        Statement * ExceptionMutatorCore::create_resume_rethrow(
     247                        ThrowStmt *throwStmt ) {
     248                // return false;
     249                Statement * result = new ReturnStmt(
     250                        new ConstantExpr( Constant::from_bool( false ) )
     251                        );
     252                result->labels = throwStmt->labels;
     253                delete throwStmt;
     254                return result;
     255        }
     256
    280257        // TryStmt Mutation Helpers
    281258
    282         CompoundStmt * TryMutatorCore::take_try_block( TryStmt *tryStmt ) {
     259        CompoundStmt * ExceptionMutatorCore::take_try_block( TryStmt *tryStmt ) {
    283260                CompoundStmt * block = tryStmt->get_block();
    284261                tryStmt->set_block( nullptr );
     
    286263        }
    287264
    288         FunctionDecl * TryMutatorCore::create_try_wrapper(
     265        FunctionDecl * ExceptionMutatorCore::create_try_wrapper(
    289266                        CompoundStmt *body ) {
    290267
     
    293270        }
    294271
    295         FunctionDecl * TryMutatorCore::create_terminate_catch(
     272        FunctionDecl * ExceptionMutatorCore::create_terminate_catch(
    296273                        CatchList &handlers ) {
    297274                std::list<CaseStmt *> handler_wrappers;
     
    332309                        local_except->get_attributes().push_back( new Attribute(
    333310                                "cleanup",
    334                                 { new NameExpr( "__cfaehm_cleanup_terminate" ) }
     311                                { new NameExpr( "__cfaabi_ehm__cleanup_terminate" ) }
    335312                                ) );
    336313
     
    373350        // Create a single check from a moddified handler.
    374351        // except_obj is referenced, modded_handler will be freed.
    375         CompoundStmt * TryMutatorCore::create_single_matcher(
     352        CompoundStmt * ExceptionMutatorCore::create_single_matcher(
    376353                        DeclarationWithType * except_obj, CatchStmt * modded_handler ) {
    377354                // {
     
    411388        }
    412389
    413         FunctionDecl * TryMutatorCore::create_terminate_match(
     390        FunctionDecl * ExceptionMutatorCore::create_terminate_match(
    414391                        CatchList &handlers ) {
    415392                // int match(exception * except) {
     
    448425        }
    449426
    450         CompoundStmt * TryMutatorCore::create_terminate_caller(
     427        CompoundStmt * ExceptionMutatorCore::create_terminate_caller(
    451428                        FunctionDecl * try_wrapper,
    452429                        FunctionDecl * terminate_catch,
    453430                        FunctionDecl * terminate_match ) {
    454                 // { __cfaehm_try_terminate(`try`, `catch`, `match`); }
     431                // { __cfaabi_ehm__try_terminate(`try`, `catch`, `match`); }
    455432
    456433                UntypedExpr * caller = new UntypedExpr( new NameExpr(
    457                         "__cfaehm_try_terminate" ) );
     434                        "__cfaabi_ehm__try_terminate" ) );
    458435                std::list<Expression *>& args = caller->get_args();
    459436                args.push_back( nameOf( try_wrapper ) );
     
    466443        }
    467444
    468         FunctionDecl * TryMutatorCore::create_resume_handler(
     445        FunctionDecl * ExceptionMutatorCore::create_resume_handler(
    469446                        CatchList &handlers ) {
    470447                // bool handle(exception * except) {
     
    503480        }
    504481
    505         CompoundStmt * TryMutatorCore::create_resume_wrapper(
     482        CompoundStmt * ExceptionMutatorCore::create_resume_wrapper(
    506483                        Statement * wraps,
    507484                        FunctionDecl * resume_handler ) {
     
    509486
    510487                // struct __try_resume_node __resume_node
    511                 //      __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
     488                //      __attribute__((cleanup( __cfaabi_ehm__try_resume_cleanup )));
    512489                // ** unwinding of the stack here could cause problems **
    513490                // ** however I don't think that can happen currently **
    514                 // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
     491                // __cfaabi_ehm__try_resume_setup( &__resume_node, resume_handler );
    515492
    516493                std::list< Attribute * > attributes;
     
    518495                        std::list< Expression * > attr_params;
    519496                        attr_params.push_back( new NameExpr(
    520                                 "__cfaehm_try_resume_cleanup" ) );
     497                                "__cfaabi_ehm__try_resume_cleanup" ) );
    521498                        attributes.push_back( new Attribute( "cleanup", attr_params ) );
    522499                }
     
    537514
    538515                UntypedExpr *setup = new UntypedExpr( new NameExpr(
    539                         "__cfaehm_try_resume_setup" ) );
     516                        "__cfaabi_ehm__try_resume_setup" ) );
    540517                setup->get_args().push_back( new AddressExpr( nameOf( obj ) ) );
    541518                setup->get_args().push_back( nameOf( resume_handler ) );
     
    547524        }
    548525
    549         FunctionDecl * TryMutatorCore::create_finally_wrapper(
     526        FunctionDecl * ExceptionMutatorCore::create_finally_wrapper(
    550527                        TryStmt * tryStmt ) {
    551                 // void finally() { `finally->block` }
     528                // void finally() { <finally code> }
    552529                FinallyStmt * finally = tryStmt->get_finally();
    553530                CompoundStmt * body = finally->get_block();
     
    560537        }
    561538
    562         ObjectDecl * TryMutatorCore::create_finally_hook(
     539        ObjectDecl * ExceptionMutatorCore::create_finally_hook(
    563540                        FunctionDecl * finally_wrapper ) {
    564                 // struct __cfaehm_cleanup_hook __finally_hook
    565                 //      __attribute__((cleanup( `finally_wrapper` )));
     541                // struct __cfaabi_ehm__cleanup_hook __finally_hook
     542                //      __attribute__((cleanup( finally_wrapper )));
    566543
    567544                // Make Cleanup Attribute.
     
    587564        }
    588565
    589         Statement * TryMutatorCore::create_resume_rethrow( ThrowStmt *throwStmt ) {
    590                 // return false;
    591                 Statement * result = new ReturnStmt(
    592                         new ConstantExpr( Constant::from_bool( false ) )
    593                         );
    594                 result->labels = throwStmt->labels;
    595                 delete throwStmt;
    596                 return result;
    597         }
    598 
    599566        // Visiting/Mutating Functions
    600         void TryMutatorCore::premutate( StructDecl *structDecl ) {
     567        void ExceptionMutatorCore::premutate( CatchStmt *catchStmt ) {
     568                // Validate the Statement's form.
     569                ObjectDecl * decl =
     570                        dynamic_cast<ObjectDecl *>( catchStmt->get_decl() );
     571                if ( decl && true /* check decl->get_type() */ ) {
     572                        // Pass.
     573                } else if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
     574                        SemanticError(catchStmt->location, "catch must have exception type");
     575                } else {
     576                        SemanticError(catchStmt->location, "catchResume must have exception type");
     577                }
     578
     579                // Track the handler context.
     580                GuardValue( cur_context );
     581                if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
     582                        cur_context = TerHandler;
     583
     584                        GuardValue( handler_except_decl );
     585                        handler_except_decl = decl;
     586                } else {
     587                        cur_context = ResHandler;
     588                }
     589        }
     590
     591        void ExceptionMutatorCore::premutate( StructDecl *structDecl ) {
    601592                if ( !structDecl->has_body() ) {
    602593                        // Skip children?
    603594                        return;
    604                 } else if ( structDecl->get_name() == "__cfaehm_base_exception_t" ) {
     595                } else if ( structDecl->get_name() == "__cfaabi_ehm__base_exception_t" ) {
    605596                        assert( nullptr == except_decl );
    606597                        except_decl = structDecl;
    607598                        init_func_types();
    608                 } else if ( structDecl->get_name() == "__cfaehm_try_resume_node" ) {
     599                } else if ( structDecl->get_name() == "__cfaabi_ehm__try_resume_node" ) {
    609600                        assert( nullptr == node_decl );
    610601                        node_decl = structDecl;
    611                 } else if ( structDecl->get_name() == "__cfaehm_cleanup_hook" ) {
     602                } else if ( structDecl->get_name() == "__cfaabi_ehm__cleanup_hook" ) {
    612603                        assert( nullptr == hook_decl );
    613604                        hook_decl = structDecl;
    614605                }
    615         }
    616 
    617         Statement * TryMutatorCore::postmutate( TryStmt *tryStmt ) {
     606                // Later we might get the exception type as well.
     607        }
     608
     609        Statement * ExceptionMutatorCore::postmutate( ThrowStmt *throwStmt ) {
     610                assert( except_decl );
     611
     612                // Ignoring throwStmt->get_target() for now.
     613                if ( ThrowStmt::Terminate == throwStmt->get_kind() ) {
     614                        if ( throwStmt->get_expr() ) {
     615                                return create_terminate_throw( throwStmt );
     616                        } else if ( TerHandler == cur_context ) {
     617                                return create_terminate_rethrow( throwStmt );
     618                        } else {
     619                                abort("Invalid throw in %s at %i\n",
     620                                        throwStmt->location.filename.c_str(),
     621                                        throwStmt->location.first_line);
     622                        }
     623                } else {
     624                        if ( throwStmt->get_expr() ) {
     625                                return create_resume_throw( throwStmt );
     626                        } else if ( ResHandler == cur_context ) {
     627                                return create_resume_rethrow( throwStmt );
     628                        } else {
     629                                abort("Invalid throwResume in %s at %i\n",
     630                                        throwStmt->location.filename.c_str(),
     631                                        throwStmt->location.first_line);
     632                        }
     633                }
     634        }
     635
     636        Statement * ExceptionMutatorCore::postmutate( TryStmt *tryStmt ) {
    618637                assert( except_decl );
    619638                assert( node_decl );
     
    669688        }
    670689
    671         Statement * TryMutatorCore::postmutate( ThrowStmt *throwStmt ) {
    672                 // Only valid `throwResume;` statements should remain. (2/3 checks)
    673                 assert( ThrowStmt::Resume == throwStmt->kind && ! throwStmt->expr );
    674                 return create_resume_rethrow( throwStmt );
    675         }
    676 
    677         void translateThrows( std::list< Declaration *> & translationUnit ) {
    678                 PassVisitor<ThrowMutatorCore> translator;
     690        void translateEHM( std::list< Declaration *> & translationUnit ) {
     691                PassVisitor<ExceptionMutatorCore> translator;
    679692                mutateAll( translationUnit, translator );
    680693        }
    681 
    682         void translateTries( std::list< Declaration *> & translationUnit ) {
    683                 PassVisitor<TryMutatorCore> translator;
    684                 mutateAll( translationUnit, translator );
    685         }
    686694}
  • src/ControlStruct/ExceptTranslate.h

    reef8dfb rbdfc032  
    99// Author           : Andrew Beach
    1010// Created On       : Tus Jun 06 10:13:00 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tus May 19 11:47:00 2020
    13 // Update Count     : 5
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat Jul 22 09:19:23 2017
     13// Update Count     : 4
    1414//
    1515
     
    2121
    2222namespace ControlStruct {
    23         void translateThrows( std::list< Declaration *> & translationUnit );
    24         /* Replaces all throw & throwResume statements with function calls.
    25          * These still need to be resolved, so call this before the reslover.
    26          */
    27 
    28         void translateTries( std::list< Declaration *> & translationUnit );
    29         /* Replaces all try blocks (and their many clauses) with function definitions and calls.
    30          * This uses the exception built-ins to produce typed output and should take place after
    31          * the resolver. It also produces virtual casts and should happen before they are expanded.
    32          */
     23        void translateEHM( std::list< Declaration *> & translationUnit );
     24        // Converts exception handling structures into their underlying C code.  Translation does use the exception
     25        // handling header, make sure it is visible wherever translation occurs.
    3326}
    3427
  • src/ControlStruct/Mutate.cc

    reef8dfb rbdfc032  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:22:07 2020
    13 // Update Count     : 10
     12// Last Modified On : Thu Aug  4 11:39:08 2016
     13// Update Count     : 9
    1414//
    1515
     
    3737                mutateAll( translationUnit, formut );
    3838        }
    39 } // namespace ControlStruct
     39} // namespace CodeGen
    4040
    4141// Local Variables: //
  • src/ControlStruct/module.mk

    reef8dfb rbdfc032  
    1717SRC_CONTROLSTRUCT = \
    1818        ControlStruct/ForExprMutator.cc \
    19         ControlStruct/ForExprMutator.h \
    2019        ControlStruct/LabelFixer.cc \
    21         ControlStruct/LabelFixer.h \
    2220        ControlStruct/LabelGenerator.cc \
    23         ControlStruct/LabelGenerator.h \
    2421        ControlStruct/MLEMutator.cc \
    25         ControlStruct/MLEMutator.h \
    26         ControlStruct/Mutate.cc \
    27         ControlStruct/Mutate.h
     22        ControlStruct/Mutate.cc
    2823
    29 SRC += $(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc ControlStruct/ExceptTranslate.h
     24SRC += $(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc
    3025SRCDEMANGLE += $(SRC_CONTROLSTRUCT)
    3126
  • src/GenPoly/GenPoly.cc

    reef8dfb rbdfc032  
    4646                }
    4747
    48                 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env) {
    49                         for (auto &param : params) {
    50                                 auto paramType = param.strict_as<ast::TypeExpr>();
    51                                 if (isPolyType(paramType->type, env)) return true;
    52                         }
    53                         return false;
    54                 }
    55 
    5648                /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present
    5749                bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
     
    6456                }
    6557
    66                 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap & tyVars, const ast::TypeSubstitution * env) {
    67                         for (auto &param : params) {
    68                                 auto paramType = param.strict_as<ast::TypeExpr>();
    69                                 if (isPolyType(paramType->type, tyVars, env)) return true;
    70                         }
    71                         return false;
    72                 }
    73 
    7458                /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present
    7559                bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
     
    10892                        Type *newType = env->lookup( typeInst->get_name() );
    10993                        if ( newType ) return newType;
    110                 }
    111                 return type;
    112         }
    113 
    114         const ast::Type * replaceTypeInst(const ast::Type * type, const ast::TypeSubstitution * env) {
    115                 if (!env) return type;
    116                 if (auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) {
    117                         auto newType = env->lookup(typeInst);
    118                         if (newType) return newType;
    11994                }
    12095                return type;
     
    136111        }
    137112
    138         const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env) {
    139                 type = replaceTypeInst( type, env );
    140 
    141                 if ( dynamic_cast< const ast::TypeInstType * >( type ) ) {
    142                         return type;
    143                 } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
    144                         return isPolyType( arrayType->base, env );
    145                 } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) {
    146                         if ( hasPolyParams( structType->params, env ) ) return type;
    147                 } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) {
    148                         if ( hasPolyParams( unionType->params, env ) ) return type;
    149                 }
    150                 return 0;
    151         }
    152 
    153113        Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    154114                type = replaceTypeInst( type, env );
     
    166126                }
    167127                return 0;
    168         }
    169 
    170         const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env) {
    171                 type = replaceTypeInst( type, env );
    172 
    173                 if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
    174                         return tyVars.find(typeInst->typeString()) != tyVars.end() ? type : nullptr;
    175                 } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
    176                         return isPolyType( arrayType->base, env );
    177                 } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) {
    178                         if ( hasPolyParams( structType->params, env ) ) return type;
    179                 } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) {
    180                         if ( hasPolyParams( unionType->params, env ) ) return type;
    181                 }
    182                 return nullptr;
    183128        }
    184129
     
    504449        }
    505450
    506         namespace {
    507                 // temporary hack to avoid re-implementing anything related to TyVarMap
    508                 // does this work? these two structs have identical definitions.
    509                 inline TypeDecl::Data convData(const ast::TypeDecl::Data & data) {
    510                         return *reinterpret_cast<const TypeDecl::Data *>(&data);
    511                 }
    512         }
    513 
    514451        bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {
    515452                // is parameter is not polymorphic, don't need to box
     
    522459        }
    523460
    524         bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env) {
    525                 // is parameter is not polymorphic, don't need to box
    526                 if ( ! isPolyType( param, exprTyVars ) ) return false;
    527                 ast::ptr<ast::Type> newType = arg;
    528                 if ( env ) env->apply( newType );
    529                 // if the argument's type is polymorphic, we don't need to box again!
    530                 return ! isPolyType( newType );
    531         }
    532 
    533461        bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {
    534462                FunctionType * function = getFunctionType( appExpr->function->result );
     
    539467        }
    540468
    541         bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env) {
    542                 const ast::FunctionType * function = getFunctionType(appExpr->func->result);
    543                 assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->func->result ).c_str() );
    544                 TyVarMap exprTyVars(TypeDecl::Data{});
    545                 makeTyVarMap(function, exprTyVars);
    546                 return needsBoxing(param, arg, exprTyVars, env);
    547 
    548         }
    549 
    550469        void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {
    551470                tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } );
    552         }
    553 
    554         void addToTyVarMap( const ast::TypeInstType * tyVar, TyVarMap & tyVarMap) {
    555                 tyVarMap.insert(tyVar->typeString(), convData(ast::TypeDecl::Data{tyVar->base}));
    556471        }
    557472
     
    563478                if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) {
    564479                        makeTyVarMap( pointer->get_base(), tyVarMap );
    565                 }
    566         }
    567 
    568         void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap) {
    569                 if (auto ptype = dynamic_cast<const ast::FunctionType *>(type)) {
    570                         for (auto & tyVar : ptype->forall) {
    571                                 assert (tyVar);
    572                                 addToTyVarMap(tyVar, tyVarMap);
    573                         }
    574                 }
    575                 if (auto pointer = dynamic_cast<const ast::PointerType *>(type)) {
    576                         makeTyVarMap(pointer->base, tyVarMap);
    577480                }
    578481        }
  • src/GenPoly/GenPoly.h

    reef8dfb rbdfc032  
    2626
    2727namespace GenPoly {
     28        typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
    2829
    29         typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
    3030        /// Replaces a TypeInstType by its referrent in the environment, if applicable
    3131        Type* replaceTypeInst( Type* type, const TypeSubstitution* env );
     
    3333        /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided
    3434        Type *isPolyType( Type *type, const TypeSubstitution *env = 0 );
    35         const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr);
    3635
    3736        /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
    3837        Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    39         const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env = nullptr);
    4038
    4139        /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided
     
    8684        /// true if arg requires boxing given exprTyVars
    8785        bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );
    88         bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env);
    8986
    9087        /// true if arg requires boxing in the call to appExpr
    9188        bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );
    92         bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env);
    9389
    9490        /// Adds the type variable `tyVar` to `tyVarMap`
     
    9793        /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
    9894        void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
    99         void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap);
    10095
    10196        /// Prints type variable map
  • src/GenPoly/InstantiateGeneric.cc

    reef8dfb rbdfc032  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu Aug 04 18:33:00 2016
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jul 16 10:17:00 2020
    13 // Update Count     : 2
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Thu Aug 04 18:33:00 2016
     13// Update Count     : 1
    1414//
    1515#include "InstantiateGeneric.h"
     
    172172                InstantiationMap< AggregateDecl, AggregateDecl > instantiations;
    173173                /// Set of types which are dtype-only generic (and therefore have static layout)
    174                 std::set<AggregateDecl *> dtypeStatics;
     174                ScopedSet< AggregateDecl* > dtypeStatics;
    175175                /// Namer for concrete types
    176176                UniqueName typeNamer;
     
    297297        }
    298298
    299         template< typename AggrInst >
    300         static AggrInst * asForward( AggrInst * decl ) {
    301                 if ( !decl->body ) {
    302                         return nullptr;
    303                 }
    304                 decl = decl->clone();
    305                 decl->body = false;
    306                 deleteAll( decl->members );
    307                 decl->members.clear();
    308                 return decl;
    309         }
    310 
    311299        void GenericInstantiator::stripDtypeParams( AggregateDecl *base, std::list< TypeDecl* >& baseParams, const std::list< TypeExpr* >& typeSubs ) {
    312300                substituteMembers( base->get_members(), baseParams, typeSubs );
     
    385373                                concDecl->set_body( inst->get_baseStruct()->has_body() );
    386374                                substituteMembers( inst->get_baseStruct()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() );
    387                                 // Forward declare before recursion. (TODO: Only when needed, #199.)
    388                                 insert( inst, typeSubs, concDecl );
    389                                 if ( StructDecl *forwardDecl = asForward( concDecl ) ) {
    390                                         declsToAddBefore.push_back( forwardDecl );
    391                                 }
     375                                insert( inst, typeSubs, concDecl ); // must insert before recursion
    392376                                concDecl->acceptMutator( *visitor ); // recursively instantiate members
    393377                                declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first
     
    439423                                concDecl->set_body( inst->get_baseUnion()->has_body() );
    440424                                substituteMembers( inst->get_baseUnion()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() );
    441                                 // Forward declare before recursion. (TODO: Only when needed, #199.)
    442                                 insert( inst, typeSubs, concDecl );
    443                                 if ( UnionDecl *forwardDecl = asForward( concDecl ) ) {
    444                                         declsToAddBefore.push_back( forwardDecl );
    445                                 }
     425                                insert( inst, typeSubs, concDecl ); // must insert before recursion
    446426                                concDecl->acceptMutator( *visitor ); // recursively instantiate members
    447427                                declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first
     
    505485        void GenericInstantiator::beginScope() {
    506486                instantiations.beginScope();
     487                dtypeStatics.beginScope();
    507488        }
    508489
    509490        void GenericInstantiator::endScope() {
    510491                instantiations.endScope();
     492                dtypeStatics.endScope();
    511493        }
    512494
  • src/GenPoly/Specialize.cc

    reef8dfb rbdfc032  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Jul  2 17:42:00 2020
    13 // Update Count     : 33
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:40:49 2019
     13// Update Count     : 32
    1414//
    1515
     
    4242
    4343namespace GenPoly {
    44         struct Specialize final : public WithConstTypeSubstitution,
    45                         public WithDeclsToAdd, public WithVisitorRef<Specialize> {
     44        struct Specialize final : public WithConstTypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> {
    4645                Expression * postmutate( ApplicationExpr *applicationExpr );
    4746                Expression * postmutate( CastExpr *castExpr );
     
    218217                thunkFunc->get_attributes().push_back( new Attribute( "unused" ) );
    219218
    220                 // Thunks at the global level must be static to avoid collisions between files.
    221                 // (Conversly thunks inside a function must be unique and not static.)
    222                 thunkFunc->storageClasses.is_static = !isInFunction();
    223 
    224219                // thread thunk parameters into call to actual function, naming thunk parameters as we go
    225220                UniqueName paramNamer( paramPrefix );
     
    253248                } // if
    254249
    255                 // Handle any specializations that may still be present.
    256                 {
    257                         std::string oldParamPrefix = paramPrefix;
    258                         paramPrefix += "p";
    259                         std::list< Declaration * > oldDecls;
    260                         oldDecls.splice( oldDecls.end(), declsToAddBefore );
    261 
    262                         appExpr->acceptMutator( *visitor );
    263                         // Write recursive specializations into the thunk body.
    264                         for ( Declaration * decl : declsToAddBefore ) {
    265                                 thunkFunc->statements->kids.push_back( new DeclStmt( decl ) );
    266                         }
    267 
    268                         declsToAddBefore = std::move( oldDecls );
    269                         paramPrefix = oldParamPrefix;
    270                 }
     250                // handle any specializations that may still be present
     251                std::string oldParamPrefix = paramPrefix;
     252                paramPrefix += "p";
     253                // save stmtsToAddBefore in oldStmts
     254                std::list< Statement* > oldStmts;
     255                oldStmts.splice( oldStmts.end(), stmtsToAddBefore );
     256                appExpr->acceptMutator( *visitor );
     257                paramPrefix = oldParamPrefix;
     258                // write any statements added for recursive specializations into the thunk body
     259                thunkFunc->statements->kids.splice( thunkFunc->statements->kids.end(), stmtsToAddBefore );
     260                // restore oldStmts into stmtsToAddBefore
     261                stmtsToAddBefore.splice( stmtsToAddBefore.end(), oldStmts );
    271262
    272263                // add return (or valueless expression) to the thunk
     
    279270                thunkFunc->statements->kids.push_back( appStmt );
    280271
    281                 // Add the thunk definition (converted to DeclStmt if appproprate).
    282                 declsToAddBefore.push_back( thunkFunc );
     272                // add thunk definition to queue of statements to add
     273                stmtsToAddBefore.push_back( new DeclStmt( thunkFunc ) );
    283274                // return address of thunk function as replacement expression
    284275                return new AddressExpr( new VariableExpr( thunkFunc ) );
  • src/GenPoly/module.mk

    reef8dfb rbdfc032  
    1616
    1717SRC += GenPoly/Box.cc \
    18        GenPoly/Box.h \
    19        GenPoly/ErasableScopedMap.h \
     18       GenPoly/GenPoly.cc \
     19       GenPoly/ScrubTyVars.cc \
     20       GenPoly/Lvalue.cc \
     21       GenPoly/Specialize.cc \
    2022       GenPoly/FindFunction.cc \
    21        GenPoly/FindFunction.h \
    22        GenPoly/GenPoly.cc \
    23        GenPoly/GenPoly.h \
    24        GenPoly/InstantiateGeneric.cc \
    25        GenPoly/InstantiateGeneric.h \
    26        GenPoly/Lvalue.cc \
    27        GenPoly/Lvalue.h \
    28        GenPoly/ScopedSet.h \
    29        GenPoly/ScrubTyVars.cc \
    30        GenPoly/ScrubTyVars.h \
    31        GenPoly/Specialize.cc \
    32        GenPoly/Specialize.h
     23       GenPoly/InstantiateGeneric.cc
    3324
    34 SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/GenPoly.h GenPoly/Lvalue.cc GenPoly/Lvalue.h
     25SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/Lvalue.cc
    3526
  • src/InitTweak/FixGlobalInit.cc

    reef8dfb rbdfc032  
    3434#include "SynTree/Visitor.h"       // for acceptAll, Visitor
    3535
    36 #include "AST/Expr.hpp"
    37 #include "AST/Node.hpp"
    38 #include "AST/Pass.hpp"
    39 
    4036namespace InitTweak {
    4137        class GlobalFixer : public WithShortCircuiting {
     
    5450                FunctionDecl * initFunction;
    5551                FunctionDecl * destroyFunction;
    56         };
    57 
    58         class GlobalFixer_new : public ast::WithShortCircuiting {
    59         public:
    60                 void previsit (const ast::ObjectDecl *);
    61                 void previsit (const ast::FunctionDecl *) { visit_children = false; }
    62                 void previsit (const ast::StructDecl *) { visit_children = false; }
    63                 void previsit (const ast::UnionDecl *) { visit_children = false; }
    64                 void previsit (const ast::EnumDecl *) { visit_children = false; }
    65                 void previsit (const ast::TraitDecl *) { visit_children = false; }
    66                 void previsit (const ast::TypeDecl *) { visit_children = false; }
    67 
    68                 std::list< ast::ptr<ast::Stmt> > initStmts;
    69                 std::list< ast::ptr<ast::Stmt> > destroyStmts;
    7052        };
    7153
     
    10991        }
    11092
    111         void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) {
    112                 ast::Pass<GlobalFixer_new> fixer;
    113                 accept_all(translationUnit, fixer);
    114 
    115                 if ( !fixer.core.initStmts.empty() ) {
    116                         std::vector<ast::ptr<ast::Expr>> ctorParams;
    117                         if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int({}, 200));
    118                         auto initFunction = new ast::FunctionDecl({}, "__global_init__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.initStmts)),
    119                                 ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("constructor", std::move(ctorParams))});
    120 
    121                         translationUnit.decls.emplace_back( initFunction );
    122                 } // if
    123 
    124                 if ( !fixer.core.destroyStmts.empty() ) {
    125                         std::vector<ast::ptr<ast::Expr>> dtorParams;
    126                         if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int({}, 200));
    127                         auto destroyFunction = new ast::FunctionDecl({}, "__global_destroy__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.destroyStmts)),
    128                                 ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("destructor", std::move(dtorParams))});
    129 
    130                         translationUnit.decls.emplace_back(destroyFunction);
    131                 } // if
    132         }
    133 
    13493        void GlobalFixer::previsit( ObjectDecl *objDecl ) {
    13594                std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids();
     
    153112                        } // if
    154113                        if ( Statement * ctor = ctorInit->ctor ) {
    155                                 addDataSectonAttribute( objDecl );
    156114                                initStatements.push_back( ctor );
    157115                                objDecl->init = nullptr;
     
    165123                        } // if
    166124                        delete ctorInit;
    167                 } // if
    168         }
    169 
    170         void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) {
    171                 auto mutDecl = mutate(objDecl);
    172                 assertf(mutDecl == objDecl, "Global object decl must be unique");
    173                 if ( auto ctorInit = objDecl->init.as<ast::ConstructorInit>() ) {
    174                         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
    175                         assert( ! ctorInit->ctor || ! ctorInit->init );
    176 
    177                         const ast::Stmt * dtor = ctorInit->dtor;
    178                         if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
    179                                 // don't need to call intrinsic dtor, because it does nothing, but
    180                                 // non-intrinsic dtors must be called
    181                                 destroyStmts.push_front( dtor );
    182                                 // ctorInit->dtor = nullptr;
    183                         } // if
    184                         if ( const ast::Stmt * ctor = ctorInit->ctor ) {
    185                                 addDataSectionAttribute(mutDecl);
    186                                 initStmts.push_back( ctor );
    187                                 mutDecl->init = nullptr;
    188                                 // ctorInit->ctor = nullptr;
    189                         } else if ( const ast::Init * init = ctorInit->init ) {
    190                                 mutDecl->init = init;
    191                                 // ctorInit->init = nullptr;
    192                         } else {
    193                                 // no constructor and no initializer, which is okay
    194                                 mutDecl->init = nullptr;
    195                         } // if
    196                         // delete ctorInit;
    197125                } // if
    198126        }
  • src/InitTweak/FixGlobalInit.h

    reef8dfb rbdfc032  
    1919#include <string>  // for string
    2020
    21 #include <AST/Fwd.hpp>
    22 
    23 
    2421class Declaration;
    2522
     
    2926        /// function is for library code.
    3027        void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary );
    31         void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary );
    3228} // namespace
    3329
  • src/InitTweak/FixInit.cc

    reef8dfb rbdfc032  
    1010// Created On       : Wed Jan 13 16:29:30 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 04:17:07 2020
    13 // Update Count     : 82
     12// Last Modified On : Fri Dec 13 23:41:27 2019
     13// Update Count     : 77
    1414//
    1515#include "FixInit.h"
     
    219219                };
    220220
    221                 struct SplitExpressions : public WithShortCircuiting, /*public WithTypeSubstitution, */public WithStmtsToAdd {
     221                struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution, public WithStmtsToAdd {
    222222                        /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places.
    223223                        static void split( std::list< Declaration * > &translationUnit );
     
    745745                }
    746746
    747                 // to prevent warnings ('_unq0' may be used uninitialized in this function),
     747                // to prevent warnings (ā€˜_unq0’ may be used uninitialized in this function),
    748748                // insert an appropriate zero initializer for UniqueExpr temporaries.
    749749                Initializer * makeInit( Type * t ) {
     
    802802                                if ( Statement * ctor = ctorInit->get_ctor() ) {
    803803                                        if ( objDecl->get_storageClasses().is_static ) {
    804 
    805                                                 // The ojbect needs to go in the data section, regardless of dtor complexity below.
    806                                                 // The attribute works, and is meant to apply, both for leaving the static local alone,
    807                                                 // and for hoisting it out as a static global.
    808                                                 addDataSectonAttribute( objDecl );
    809 
    810804                                                // originally wanted to take advantage of gcc nested functions, but
    811805                                                // we get memory errors with this approach. To remedy this, the static
  • src/InitTweak/FixInit.h

    reef8dfb rbdfc032  
    1010// Created On       : Wed Jan 13 16:29:30 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 07:54:50 2020
    13 // Update Count     : 8
     12// Last Modified On : Sat Jul 22 09:31:06 2017
     13// Update Count     : 6
    1414//
    1515
     
    2020
    2121class Declaration;
    22 namespace ast {
    23         struct TranslationUnit;
    24 }
    2522
    2623namespace InitTweak {
    27         /// replace constructor initializers with expression statements and unwrap basic C-style initializers
     24  /// replace constructor initializers with expression statements
     25  /// and unwrap basic C-style initializers
    2826        void fix( std::list< Declaration * > & translationUnit, bool inLibrary );
    29 
    30         void fix( ast::TranslationUnit & translationUnit, bool inLibrary);
    3127} // namespace
    3228
  • src/InitTweak/GenInit.cc

    reef8dfb rbdfc032  
    2626#include "AST/Node.hpp"
    2727#include "AST/Stmt.hpp"
    28 #include "CompilationState.h"
    2928#include "CodeGen/OperatorTable.h"
    3029#include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
     
    122121        };
    123122
    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 
    145123        void genInit( std::list< Declaration * > & translationUnit ) {
    146                 if (!useNewAST) {
    147                         HoistArrayDimension::hoistArrayDimension( translationUnit );
    148                 }
    149                 else {
    150                         HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );
    151                 }
    152124                fixReturnStatements( translationUnit );
    153 
    154                 if (!useNewAST) {
    155                         CtorDtor::generateCtorDtor( translationUnit );
    156                 }
     125                HoistArrayDimension::hoistArrayDimension( translationUnit );
     126                CtorDtor::generateCtorDtor( translationUnit );
    157127        }
    158128
     
    226196                        arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
    227197                        // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
    228                         // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
    229                         // still try to detect constant expressions
    230198                        if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
    231199
     
    242210
    243211        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 * ) {
    292212                GuardValue( inFunction );
    293213                inFunction = true;
     
    325245        }
    326246
    327         // why is this not just on FunctionDecl?
    328247        void ManagedTypes::handleDWT( DeclarationWithType * dwt ) {
    329248                // if this function is a user-defined constructor or destructor, mark down the type as "managed"
     
    356275        void ManagedTypes::endScope() { managedTypes.endScope(); }
    357276
    358         bool ManagedTypes_new::isManaged( const ast::Type * type ) const {
    359                 // references are never constructed
    360                 if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false;
    361                 if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) {
    362                         // tuple is also managed if any of its components are managed
    363                         for (auto & component : tupleType->types) {
    364                                 if (isManaged(component)) return true;
    365                         }
    366                 }
    367                 // need to clear and reset qualifiers when determining if a type is managed
    368                 // ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
    369                 auto tmp = shallowCopy(type);
    370                 tmp->qualifiers = {};
    371                 // delete tmp at return
    372                 ast::ptr<ast::Type> guard = tmp;
    373                 // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
    374                 return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp );
    375         }
    376 
    377         bool ManagedTypes_new::isManaged( const ast::ObjectDecl * objDecl ) const {
    378                 const ast::Type * type = objDecl->type;
    379                 while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
    380                         // must always construct VLAs with an initializer, since this is an error in C
    381                         if ( at->isVarLen && objDecl->init ) return true;
    382                         type = at->base;
    383                 }
    384                 return isManaged( type );
    385         }
    386 
    387         void ManagedTypes_new::handleDWT( const ast::DeclWithType * dwt ) {
    388                 // if this function is a user-defined constructor or destructor, mark down the type as "managed"
    389                 if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) {
    390                         auto & params = GenPoly::getFunctionType( dwt->get_type())->params;
    391                         assert( ! params.empty() );
    392                         // Type * type = InitTweak::getPointerBase( params.front() );
    393                         // assert( type );
    394                         managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
    395                 }
    396         }
    397 
    398         void ManagedTypes_new::handleStruct( const ast::StructDecl * aggregateDecl ) {
    399                 // don't construct members, but need to take note if there is a managed member,
    400                 // because that means that this type is also managed
    401                 for ( auto & member : aggregateDecl->members ) {
    402                         if ( auto field = member.as<ast::ObjectDecl>() ) {
    403                                 if ( isManaged( field ) ) {
    404                                         // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
    405                                         // polymorphic constructors make generic types managed types
    406                                         ast::StructInstType inst( aggregateDecl );
    407                                         managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
    408                                         break;
    409                                 }
    410                         }
    411                 }
    412         }
    413 
    414         void ManagedTypes_new::beginScope() { managedTypes.beginScope(); }
    415         void ManagedTypes_new::endScope() { managedTypes.endScope(); }
    416 
    417277        ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) {
    418278                // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
     
    423283                assert( stmts.size() <= 1 );
    424284                return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr;
    425 
    426         }
    427 
    428         ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
    429                 assertf(objDecl, "genCtorDtor passed null objDecl");
    430                 InitExpander_new srcParam(arg);
    431                 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
    432285        }
    433286
     
    510363        // constructable object
    511364        InitExpander_new srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
    512         ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl);
    513365       
    514366        ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall(
    515                 srcParam, dstParam, loc, "?{}", objDecl );
     367                srcParam, new ast::VariableExpr{ loc, objDecl }, loc, "?{}", objDecl );
    516368        ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall(
    517                 nullParam, dstParam, loc, "^?{}", objDecl,
     369                nullParam, new ast::VariableExpr{ loc, objDecl }, loc, "^?{}", objDecl,
    518370                SymTab::LoopBackward );
    519371       
  • src/InitTweak/GenInit.h

    reef8dfb rbdfc032  
    3333        /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
    3434        ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr );
    35         ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr);
    3635
    3736        /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
     
    5251                GenPoly::ScopedSet< std::string > managedTypes;
    5352        };
    54 
    55         class ManagedTypes_new {
    56         public:
    57                 bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed
    58                 bool isManaged( const ast::Type * type ) const; // determine if type is managed
    59 
    60                 void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor
    61                 void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed
    62 
    63                 void beginScope();
    64                 void endScope();
    65         private:
    66                 GenPoly::ScopedSet< std::string > managedTypes;
    67         };
    6853} // namespace
    6954
  • src/InitTweak/InitTweak.cc

    reef8dfb rbdfc032  
    8787                };
    8888
    89                 struct HasDesignations_new : public ast::WithShortCircuiting {
    90                         bool result = false;
    91 
    92                         void previsit( const ast::Node * ) {
    93                                 // short circuit if we already know there are designations
    94                                 if ( result ) visit_children = false;
    95                         }
    96 
    97                         void previsit( const ast::Designation * des ) {
    98                                 // short circuit if we already know there are designations
    99                                 if ( result ) visit_children = false;
    100                                 else if ( ! des->designators.empty() ) {
    101                                         result = true;
    102                                         visit_children = false;
    103                                 }
    104                         }
    105                 };
    106 
    107                 struct InitDepthChecker_new : public ast::WithGuards {
    108                         bool result = true;
    109                         const ast::Type * type;
    110                         int curDepth = 0, maxDepth = 0;
    111                         InitDepthChecker_new( const ast::Type * type ) : type( type ) {
    112                                 const ast::Type * t = type;
    113                                 while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) {
    114                                         maxDepth++;
    115                                         t = at->base;
    116                                 }
    117                                 maxDepth++;
    118                         }
    119                         void previsit( ListInit * ) {
    120                                 curDepth++;
    121                                 GuardAction( [this]() { curDepth--; } );
    122                                 if ( curDepth > maxDepth ) result = false;
    123                         }
    124                 };
    125 
    12689                struct InitFlattener_old : public WithShortCircuiting {
    12790                        void previsit( SingleInit * singleInit ) {
     
    161124        }
    162125
    163         bool isDesignated( const ast::Init * init ) {
    164                 ast::Pass<HasDesignations_new> finder;
    165                 maybe_accept( init, finder );
    166                 return finder.core.result;
    167         }
    168 
    169         bool checkInitDepth( const ast::ObjectDecl * objDecl ) {
    170                 ast::Pass<InitDepthChecker_new> checker( objDecl->type );
    171                 maybe_accept( objDecl->init.get(), checker );
    172                 return checker.core.result;
    173         }
    174 
    175126std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) {
    176127        ast::Pass< InitFlattener_new > flattener;
    177128        maybe_accept( init, flattener );
    178         return std::move( flattener.core.argList );
     129        return std::move( flattener.pass.argList );
    179130}
    180131
     
    407358                        if ( auto listInit = dynamic_cast< const ast::ListInit * >( init ) ) {
    408359                                for ( const ast::Init * init : *listInit ) {
    409                                         buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
     360                                        buildCallExpr( callExpr, index, dimension, init, out );
    410361                                }
    411362                        } else {
    412                                 buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
     363                                buildCallExpr( callExpr, index, dimension, init, out );
    413364                        }
    414365                } else {
     
    547498        }
    548499
    549         const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
    550                 assertf( func, "getParamThis: nullptr ftype" );
    551                 auto & params = func->params;
    552                 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str());
    553                 return params.front().strict_as<ast::ObjectDecl>();
    554         }
    555 
    556500        bool tryConstruct( DeclarationWithType * dwt ) {
    557501                ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );
     
    567511        }
    568512
    569         bool tryConstruct( const ast::DeclWithType * dwt ) {
    570                 auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt );
    571                 if ( ! objDecl ) return false;
    572                 return (objDecl->init == nullptr ||
    573                                 ( objDecl->init != nullptr && objDecl->init->maybeConstructed ))
    574                         && ! objDecl->storage.is_extern
    575                         && isConstructable( objDecl->type );
    576         }
    577 
    578         bool isConstructable( const ast::Type * type ) {
    579                 return ! dynamic_cast< const ast::VarArgsType * >( type ) && ! dynamic_cast< const ast::ReferenceType * >( type )
    580                 && ! dynamic_cast< const ast::FunctionType * >( type ) && ! Tuples::isTtype( type );
    581         }
    582 
    583513        struct CallFinder_old {
    584514                CallFinder_old( const std::list< std::string > & names ) : names( names ) {}
     
    606536
    607537        struct CallFinder_new final {
    608                 std::vector< const ast::Expr * > matches;
     538                std::vector< ast::ptr< ast::Expr > > matches;
    609539                const std::vector< std::string > names;
    610540
     
    628558        }
    629559
    630         std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
     560        std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt ) {
    631561                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
    632562                maybe_accept( stmt, finder );
    633                 return std::move( finder.core.matches );
     563                return std::move( finder.pass.matches );
    634564        }
    635565
     
    766696                template <typename Predicate>
    767697                bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
    768                         std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt );
     698                        std::vector< ast::ptr< ast::Expr > > callExprs = collectCtorDtorCalls( stmt );
    769699                        return std::all_of( callExprs.begin(), callExprs.end(), pred );
    770700                }
     
    1009939        }
    1010940
    1011         // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards
    1012         // following passes may accidentally resolve this expression if returned as untyped...
    1013         ast::Expr * createBitwiseAssignment (const ast::Expr * dst, const ast::Expr * src) {
    1014                 static ast::ptr<ast::FunctionDecl> assign = nullptr;
    1015                 if (!assign) {
    1016                         auto td = new ast::TypeDecl({}, "T", {}, nullptr, ast::TypeDecl::Dtype, true);
    1017                         assign = new ast::FunctionDecl({}, "?=?", {},
    1018                         { new ast::ObjectDecl({}, "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))),
    1019                           new ast::ObjectDecl({}, "_src", new ast::TypeInstType("T", td))},
    1020                         { new ast::ObjectDecl({}, "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic);
    1021                 }
    1022                 if (dst->result.as<ast::ReferenceType>()) {
    1023                         for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {
    1024                                 dst = new ast::AddressExpr(dst);
    1025                         }
    1026                 }
    1027                 else {
    1028                         dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {}));
    1029                 }
    1030                 if (src->result.as<ast::ReferenceType>()) {
    1031                         for (int depth = src->result->referenceDepth(); depth > 0; depth--) {
    1032                                 src = new ast::AddressExpr(src);
    1033                         }
    1034                 }
    1035                 return new ast::ApplicationExpr(dst->location, ast::VariableExpr::functionPointer(dst->location, assign), {dst, src});
    1036         }
    1037 
    1038941        struct ConstExprChecker : public WithShortCircuiting {
    1039942                // most expressions are not const expr
     
    1076979        };
    1077980
    1078         struct ConstExprChecker_new : public ast::WithShortCircuiting {
    1079                 // most expressions are not const expr
    1080                 void previsit( const ast::Expr * ) { result = false; visit_children = false; }
    1081 
    1082                 void previsit( const ast::AddressExpr *addressExpr ) {
    1083                         visit_children = false;
    1084                         const ast::Expr * arg = addressExpr->arg;
    1085 
    1086                         // address of a variable or member expression is constexpr
    1087                         if ( ! dynamic_cast< const ast::NameExpr * >( arg )
    1088                         && ! dynamic_cast< const ast::VariableExpr * >( arg )
    1089                         && ! dynamic_cast< const ast::MemberExpr * >( arg )
    1090                         && ! dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false;
    1091                 }
    1092 
    1093                 // these expressions may be const expr, depending on their children
    1094                 void previsit( const ast::SizeofExpr * ) {}
    1095                 void previsit( const ast::AlignofExpr * ) {}
    1096                 void previsit( const ast::UntypedOffsetofExpr * ) {}
    1097                 void previsit( const ast::OffsetofExpr * ) {}
    1098                 void previsit( const ast::OffsetPackExpr * ) {}
    1099                 void previsit( const ast::CommaExpr * ) {}
    1100                 void previsit( const ast::LogicalExpr * ) {}
    1101                 void previsit( const ast::ConditionalExpr * ) {}
    1102                 void previsit( const ast::CastExpr * ) {}
    1103                 void previsit( const ast::ConstantExpr * ) {}
    1104 
    1105                 void previsit( const ast::VariableExpr * varExpr ) {
    1106                         visit_children = false;
    1107 
    1108                         if ( auto inst = varExpr->result.as<ast::EnumInstType>() ) {
    1109                                 long long int value;
    1110                                 if ( inst->base->valueOf( varExpr->var, value ) ) {
    1111                                         // enumerators are const expr
    1112                                         return;
    1113                                 }
    1114                         }
    1115                         result = false;
    1116                 }
    1117 
    1118                 bool result = true;
    1119         };
    1120 
    1121981        bool isConstExpr( Expression * expr ) {
    1122982                if ( expr ) {
     
    1138998        }
    1139999
    1140         bool isConstExpr( const ast::Expr * expr ) {
    1141                 if ( expr ) {
    1142                         ast::Pass<ConstExprChecker_new> checker;
    1143                         expr->accept( checker );
    1144                         return checker.core.result;
    1145                 }
    1146                 return true;
    1147         }
    1148 
    1149         bool isConstExpr( const ast::Init * init ) {
    1150                 if ( init ) {
    1151                         ast::Pass<ConstExprChecker_new> checker;
    1152                         init->accept( checker );
    1153                         return checker.core.result;
    1154                 } // if
    1155                 // for all intents and purposes, no initializer means const expr
    1156                 return true;
    1157         }
    1158 
    11591000        bool isConstructor( const std::string & str ) { return str == "?{}"; }
    11601001        bool isDestructor( const std::string & str ) { return str == "^?{}"; }
     
    11851026                if ( ftype->params.size() != 2 ) return false;
    11861027
    1187                 const ast::Type * t1 = getPointerBase( ftype->params.front() );
     1028                const ast::Type * t1 = getPointerBase( ftype->params.front()->get_type() );
    11881029                if ( ! t1 ) return false;
    1189                 const ast::Type * t2 = ftype->params.back();
     1030                const ast::Type * t2 = ftype->params.back()->get_type();
    11901031
    11911032                return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, ast::SymbolTable{} );
     
    12141055                return isCopyFunction( decl, "?{}" );
    12151056        }
    1216 
    1217         void addDataSectonAttribute( ObjectDecl * objDecl ) {
    1218                 Type *strLitT = new PointerType( Type::Qualifiers( ),
    1219                         new BasicType( Type::Qualifiers( ), BasicType::Char ) );
    1220                 std::list< Expression * > attr_params;
    1221                 attr_params.push_back(
    1222                         new ConstantExpr( Constant( strLitT, "\".data#\"", std::nullopt ) ) );
    1223                 objDecl->attributes.push_back(new Attribute("section", attr_params));
    1224         }
    1225 
    1226         void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
    1227                 auto strLitT = new ast::PointerType(new ast::BasicType(ast::BasicType::Char));
    1228                 objDecl->attributes.push_back(new ast::Attribute("section", {new ast::ConstantExpr(objDecl->location, strLitT, "\".data#\"", std::nullopt)}));
    1229         }
    1230 
    12311057}
  • src/InitTweak/InitTweak.h

    reef8dfb rbdfc032  
    3838        /// returns the first parameter of a constructor/destructor/assignment function
    3939        ObjectDecl * getParamThis( FunctionType * ftype );
    40         const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
    4140
    4241        /// generate a bitwise assignment operation.
    4342        ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );
    44 
    45         ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
    4643
    4744        /// transform Initializer into an argument list that can be passed to a call expression
     
    5148        /// True if the resolver should try to construct dwt
    5249        bool tryConstruct( DeclarationWithType * dwt );
    53         bool tryConstruct( const ast::DeclWithType * dwt );
    5450
    5551        /// True if the type can have a user-defined constructor
    5652        bool isConstructable( Type * t );
    57         bool isConstructable( const ast::Type * t );
    5853
    5954        /// True if the Initializer contains designations
    6055        bool isDesignated( Initializer * init );
    61         bool isDesignated( const ast::Init * init );
    6256
    6357        /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its
    6458        /// type, where the depth of its type is the number of nested ArrayTypes + 1
    6559        bool checkInitDepth( ObjectDecl * objDecl );
    66         bool checkInitDepth( const ast::ObjectDecl * objDecl );
    6760
    6861        /// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr)
     
    8679        /// get all Ctor/Dtor call expressions from a Statement
    8780        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
    88         std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
     81        std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt );
    8982
    9083        /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
     
    109102        bool isConstExpr( Expression * expr );
    110103        bool isConstExpr( Initializer * init );
    111 
    112         bool isConstExpr( const ast::Expr * expr );
    113         bool isConstExpr( const ast::Init * init );
    114 
    115         /// Modifies objDecl to have:
    116         ///    __attribute__((section (".data#")))
    117         /// which makes gcc put the declared variable in the data section,
    118         /// which is helpful for global constants on newer gcc versions,
    119         /// so that CFA's generated initialization won't segfault when writing it via a const cast.
    120         /// The trailing # is an injected assembly comment, to suppress the "a" in
    121         ///    .section .data,"a"
    122         ///    .section .data#,"a"
    123         /// to avoid assembler warning "ignoring changed section attributes for .data"
    124         void addDataSectonAttribute( ObjectDecl * objDecl );
    125 
    126         void addDataSectionAttribute( ast::ObjectDecl * objDecl );
    127104
    128105        class InitExpander_old {
  • src/InitTweak/module.mk

    reef8dfb rbdfc032  
    1515###############################################################################
    1616
    17 SRC += \
     17SRC += InitTweak/GenInit.cc \
     18        InitTweak/FixInit.cc \
    1819        InitTweak/FixGlobalInit.cc \
    19         InitTweak/FixGlobalInit.h \
    20         InitTweak/FixInit.cc \
    21         InitTweak/FixInit.h \
    22         InitTweak/GenInit.cc \
    23         InitTweak/GenInit.h \
    24         InitTweak/InitTweak.cc \
    25         InitTweak/InitTweak.h \
    26         InitTweak/FixInitNew.cpp
     20        InitTweak/InitTweak.cc
    2721
    28 SRCDEMANGLE += \
    29         InitTweak/GenInit.cc \
    30         InitTweak/GenInit.h \
    31         InitTweak/InitTweak.cc \
    32         InitTweak/InitTweak.h
     22SRCDEMANGLE += InitTweak/GenInit.cc \
     23        InitTweak/InitTweak.cc
    3324
  • src/MakeLibCfa.cc

    reef8dfb rbdfc032  
    1010// Created On       : Sat May 16 10:33:33 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:49:49 2020
    13 // Update Count     : 45
     12// Last Modified On : Fri Dec 13 23:41:40 2019
     13// Update Count     : 42
    1414//
    1515
     
    9696
    9797                        FunctionDecl *funcDecl = origFuncDecl->clone();
    98                         const CodeGen::OperatorInfo * opInfo;
    99                         opInfo = CodeGen::operatorLookup( funcDecl->get_name() );
    100                         assert( opInfo );
     98                        CodeGen::OperatorInfo opInfo;
     99                        bool lookResult = CodeGen::operatorLookup( funcDecl->get_name(), opInfo );
     100                        assert( lookResult );
    101101                        assert( ! funcDecl->get_statements() );
    102102                        // build a recursive call - this is okay, as the call will actually be codegen'd using operator syntax
     
    120120
    121121                        Statement * stmt = nullptr;
    122                         switch ( opInfo->type ) {
     122                        switch ( opInfo.type ) {
    123123                          case CodeGen::OT_INDEX:
    124124                          case CodeGen::OT_CALL:
  • src/Makefile.am

    reef8dfb rbdfc032  
    2020
    2121SRC = main.cc \
    22       CompilationState.cc \
    23       CompilationState.h \
    2422      MakeLibCfa.cc \
    25         MakeLibCfa.h
     23      CompilationState.cc
    2624
    2725SRCDEMANGLE = CompilationState.cc
     
    6866___driver_cfa_cpp_SOURCES = $(SRC)
    6967___driver_cfa_cpp_LDADD = -ldl $(LIBPROFILER) $(LIBTCMALLOC)
    70 EXTRA_DIST = include/cassert include/optional BasicTypes-gen.cc
    7168
    7269AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O3 -g -std=c++14 $(TCMALLOCFLAG)
  • src/Parser/DeclarationNode.cc

    reef8dfb rbdfc032  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Oct  8 08:03:38 2020
    13 // Update Count     : 1135
     12// Last Modified On : Mon Dec 16 15:32:22 2019
     13// Update Count     : 1133
    1414//
    1515
     
    10161016                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
    10171017                                dwt->location = cur->location;
    1018                                 *out++ = dwt;
     1018                                * out++ = dwt;
    10191019                        } else if ( StructDecl * agg = dynamic_cast< StructDecl * >( decl ) ) {
    10201020                                // e.g., int foo(struct S) {}
     
    10221022                                auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
    10231023                                obj->location = cur->location;
    1024                                 *out++ = obj;
     1024                                * out++ = obj;
    10251025                                delete agg;
    10261026                        } else if ( UnionDecl * agg = dynamic_cast< UnionDecl * >( decl ) ) {
     
    10291029                                auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
    10301030                                obj->location = cur->location;
    1031                                 *out++ = obj;
     1031                                * out++ = obj;
    10321032                        } else if ( EnumDecl * agg = dynamic_cast< EnumDecl * >( decl ) ) {
    10331033                                // e.g., int foo(enum E) {}
     
    10351035                                auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
    10361036                                obj->location = cur->location;
    1037                                 *out++ = obj;
     1037                                * out++ = obj;
    10381038                        } // if
    10391039                } catch( SemanticErrorException & e ) {
     
    11151115        // SUE's cannot have function specifiers, either
    11161116        //
    1117         //    inline _Noreturn struct S { ... };                // disallowed
    1118         //    inline _Noreturn enum   E { ... };                // disallowed
     1117        //    inlne _Noreturn struct S { ... };         // disallowed
     1118        //    inlne _Noreturn enum   E { ... };         // disallowed
    11191119        if ( funcSpecs.any() ) {
    11201120                SemanticError( this, "invalid function specifier for " );
  • src/Parser/ExpressionNode.cc

    reef8dfb rbdfc032  
    1010// Created On       : Sat May 16 13:17:07 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 20 14:01:46 2020
    13 // Update Count     : 1076
     12// Last Modified On : Wed Dec 18 21:14:58 2019
     13// Update Count     : 981
    1414//
    1515
     
    6565
    6666void lnthSuffix( string & str, int & type, int & ltype ) {
    67         // 'u' can appear before or after length suffix
    6867        string::size_type posn = str.find_last_of( "lL" );
    6968
    7069        if ( posn == string::npos ) return;                                     // no suffix
    71         size_t end = str.length() - 1;
    72         if ( posn == end ) { type = 3; return; }                        // no length after 'l' => long
    73        
     70        if ( posn == str.length() - 1 ) { type = 3; return; } // no length => long
     71
    7472        string::size_type next = posn + 1;                                      // advance to length
    7573        if ( str[next] == '3' ) {                                                       // 32
     
    8684                } // if
    8785        } // if
    88 
    89         char fix = '\0';
    90         if ( str[end] == 'u' || str[end] == 'U' ) fix = str[end]; // ends with 'uU' ?
    91         str.erase( posn );                                                                      // remove length suffix and possibly uU
    92         if ( type == 5 ) {                                                                      // L128 does not need uU
    93                 end = str.length() - 1;
    94                 if ( str[end] == 'u' || str[end] == 'U' ) str.erase( end ); // ends with 'uU' ? remove
    95         } else if ( fix != '\0' ) str += fix;                           // put 'uU' back if removed
     86        // remove "lL" for these cases because it may not imply long
     87        str.erase( posn );                                                                      // remove length
    9688} // lnthSuffix
    9789
     
    116108} // valueToType
    117109
    118 static void scanbin( string & str, unsigned long long int & v ) {
    119         v = 0;
    120         size_t last = str.length() - 1;                                         // last subscript of constant
    121         for ( unsigned int i = 2;; ) {                                          // ignore prefix
    122                 if ( str[i] == '1' ) v |= 1;
    123                 i += 1;
    124           if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
    125                 v <<= 1;
    126         } // for
    127 } // scanbin
    128 
    129110Expression * build_constantInteger( string & str ) {
    130111        static const BasicType::Kind kind[2][6] = {
    131112                // short (h) must be before char (hh) because shorter type has the longer suffix
    132                 { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, /* BasicType::SignedInt128 */ BasicType::LongLongSignedInt, },
    133                 { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, /* BasicType::UnsignedInt128 */ BasicType::LongLongUnsignedInt, },
     113                { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, BasicType::SignedInt128, },
     114                { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::UnsignedInt128, },
    134115        };
    135116
     
    139120        }; // lnthsInt
    140121
    141         string str2( "0x0" );
    142         unsigned long long int v, v2 = 0;                                       // converted integral value
    143         Expression * ret, * ret2;
     122        unsigned long long int v;                                                       // converted integral value
     123        size_t last = str.length() - 1;                                         // last subscript of constant
     124        Expression * ret;
     125        //string fred( str );
    144126
    145127        int type = -1;                                                                          // 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128
     
    157139        } // if
    158140
    159         string::size_type posn;
    160 
    161         // 'u' can appear before or after length suffix
    162         if ( str.find_last_of( "uU" ) != string::npos ) Unsigned = true;
    163 
    164         if ( isdigit( str[str.length() - 1] ) ) {                       // no suffix ?
    165                 lnthSuffix( str, type, ltype );                                 // could have length suffix
    166         } else {
    167                 // At least one digit in integer constant, so safe to backup while looking for suffix.
    168 
    169                 posn = str.find_last_of( "pP" );                                // pointer value
    170                 if ( posn != string::npos ) { ltype = 5; str.erase( posn, 1 ); goto FINI; }
    171 
    172                 posn = str.find_last_of( "zZ" );                                // size_t
    173                 if ( posn != string::npos ) { Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 ); goto FINI; }
    174 
    175                 posn = str.rfind( "hh" );                                               // char
    176                 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
    177 
    178                 posn = str.rfind( "HH" );                                               // char
    179                 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
    180 
    181                 posn = str.find_last_of( "hH" );                                // short
    182                 if ( posn != string::npos ) { type = 0; str.erase( posn, 1 ); goto FINI; }
    183 
    184                 posn = str.find_last_of( "nN" );                                // int (natural number)
    185                 if ( posn != string::npos ) { type = 2; str.erase( posn, 1 ); goto FINI; }
    186 
    187                 if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) { type = 4; goto FINI; }
    188 
    189                 lnthSuffix( str, type, ltype );                                 // must be after check for "ll"
    190           FINI: ;
    191         } // if
    192 
    193141        // Cannot be just "0"/"1"; sscanf stops at the suffix, if any; value goes over the wall => always generate
    194142
    195 #if ! defined(__SIZEOF_INT128__)
    196         if ( type == 5 ) SemanticError( yylloc, "int128 constant is not supported on this target " + str );
    197 #endif // ! __SIZEOF_INT128__
    198        
    199143        if ( str[0] == '0' ) {                                                          // radix character ?
    200144                dec = false;
    201145                if ( checkX( str[1] ) ) {                                               // hex constant ?
    202                         if ( type < 5 ) {                                                       // not L128 ?
    203                                 sscanf( (char *)str.c_str(), "%llx", &v );
    204 #if defined(__SIZEOF_INT128__)
    205                         } else {                                                                        // hex int128 constant
    206                                 unsigned int len = str.length();
    207                                 if ( len > (2 + 16 + 16) ) SemanticError( yylloc, "128-bit hexadecimal constant to large " + str );
    208                           if ( len <= (2 + 16) ) goto FHEX1;            // hex digits < 2^64
    209                                 str2 = "0x" + str.substr( len - 16 );
    210                                 sscanf( (char *)str2.c_str(), "%llx", &v2 );
    211                                 str = str.substr( 0, len - 16 );
    212                           FHEX1: ;
    213                                 sscanf( (char *)str.c_str(), "%llx", &v );
    214 #endif // __SIZEOF_INT128__
    215                         } // if
     146                        sscanf( (char *)str.c_str(), "%llx", &v );
    216147                        //printf( "%llx %llu\n", v, v );
    217148                } else if ( checkB( str[1] ) ) {                                // binary constant ?
    218 #if defined(__SIZEOF_INT128__)
    219                         unsigned int len = str.length();
    220                         if ( type == 5 && len > 2 + 64 ) {
    221                                 if ( len > 2 + 64 + 64 ) SemanticError( yylloc, "128-bit binary constant to large " + str );
    222                                 str2 = "0b" + str.substr( len - 64 );
    223                                 str = str.substr( 0, len - 64 );
    224                                 scanbin( str2, v2 );
    225                         } // if
    226 #endif // __SIZEOF_INT128__
    227                         scanbin( str, v );
     149                        v = 0;                                                                          // compute value
     150                        for ( unsigned int i = 2;; ) {                          // ignore prefix
     151                                if ( str[i] == '1' ) v |= 1;
     152                                i += 1;
     153                          if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
     154                                v <<= 1;
     155                        } // for
    228156                        //printf( "%#llx %llu\n", v, v );
    229157                } else {                                                                                // octal constant
    230                         if ( type < 5 ) {                                                       // not L128 ?
    231                                 sscanf( (char *)str.c_str(), "%llo", &v );
    232 #if defined(__SIZEOF_INT128__)
    233                         } else {                                                                        // octal int128 constant
    234                                 unsigned int len = str.length();
    235                                 if ( len > 1 + 43 || (len == 1 + 43 && str[0] > '3') ) SemanticError( yylloc, "128-bit octal constant to large " + str );
    236                                 char buf[32];
    237                                 if ( len <= 1 + 21 ) {                                  // value < 21 octal digitis
    238                                         sscanf( (char *)str.c_str(), "%llo", &v );
    239                                 } else {
    240                                         sscanf( &str[len - 21], "%llo", &v );
    241                                         __int128 val = v;                                       // accumulate bits
    242                                         str[len - 21] ='\0';                            // shorten string
    243                                         sscanf( &str[len == 43 ? 1 : 0], "%llo", &v );
    244                                         val |= (__int128)v << 63;                       // store bits
    245                                         if ( len == 1 + 43 ) {                          // most significant 2 bits ?
    246                                                 str[2] = '\0';                                  // shorten string
    247                                                 sscanf( &str[1], "%llo", &v );  // process most significant 2 bits
    248                                                 val |= (__int128)v << 126;              // store bits
    249                                         } // if
    250                                         v = val >> 64; v2 = (uint64_t)val;      // replace octal constant with 2 hex constants
    251                                         sprintf( buf, "%#llx", v2 );
    252                                         str2 = buf;
    253                                 } // if
    254                                 sprintf( buf, "%#llx", v );
    255                                 str = buf;
    256 #endif // __SIZEOF_INT128__
    257                         } // if
     158                        sscanf( (char *)str.c_str(), "%llo", &v );
    258159                        //printf( "%#llo %llu\n", v, v );
    259160                } // if
    260161        } else {                                                                                        // decimal constant ?
    261                 if ( type < 5 ) {                                                               // not L128 ?
    262                         sscanf( (char *)str.c_str(), "%llu", &v );
    263 #if defined(__SIZEOF_INT128__)
    264                 } else {                                                                                // decimal int128 constant
    265                         #define P10_UINT64 10'000'000'000'000'000'000ULL // 19 zeroes
    266                         unsigned int len = str.length();
    267                         if ( str.length() == 39 && str > (Unsigned ? "340282366920938463463374607431768211455" : "170141183460469231731687303715884105727") )
    268                                 SemanticError( yylloc, "128-bit decimal constant to large " + str );
    269                         char buf[32];
    270                         if ( len <= 19 ) {                                                      // value < 19 decimal digitis
    271                                 sscanf( (char *)str.c_str(), "%llu", &v );
    272                         } else {
    273                                 sscanf( &str[len - 19], "%llu", &v );
    274                                 __int128 val = v;                                               // accumulate bits
    275                                 str[len - 19] ='\0';                                    // shorten string
    276                                 sscanf( &str[len == 39 ? 1 : 0], "%llu", &v );
    277                                 val += (__int128)v * (__int128)P10_UINT64; // store bits
    278                                 if ( len == 39 ) {                                              // most significant 2 bits ?
    279                                         str[1] = '\0';                                          // shorten string
    280                                         sscanf( &str[0], "%llu", &v );          // process most significant 2 bits
    281                                         val += (__int128)v * (__int128)P10_UINT64 * (__int128)P10_UINT64; // store bits
    282                                 } // if
    283                                 v = val >> 64; v2 = (uint64_t)val;              // replace decimal constant with 2 hex constants
    284                                 sprintf( buf, "%#llx", v2 );
    285                                 str2 = buf;
    286                         } // if
    287                         sprintf( buf, "%#llx", v );
    288                         str = buf;
    289 #endif // __SIZEOF_INT128__
    290                 } // if
     162                sscanf( (char *)str.c_str(), "%llu", &v );
    291163                //printf( "%llu\n", v );
    292164        } // if
    293165
    294         if ( type == -1 ) {                                                                     // no suffix => determine type from value size
    295                 valueToType( v, dec, type, Unsigned );
    296         } // if
    297         /* printf( "%s %llo %s %llo\n", str.c_str(), v, str2.c_str(), v2 ); */
     166        string::size_type posn;
     167
     168        if ( isdigit( str[last] ) ) {                                           // no suffix ?
     169                lnthSuffix( str, type, ltype );                                 // could have length suffix
     170                if ( type == -1 ) {                                                             // no suffix
     171                        valueToType( v, dec, type, Unsigned );
     172                } // if
     173        } else {
     174                // At least one digit in integer constant, so safe to backup while looking for suffix.
     175
     176                posn = str.find_last_of( "pP" );
     177                if ( posn != string::npos ) { valueToType( v, dec, type, Unsigned ); ltype = 5; str.erase( posn, 1 ); goto FINI; }
     178
     179                posn = str.find_last_of( "zZ" );
     180                if ( posn != string::npos ) { Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 ); goto FINI; }
     181
     182                // 'u' can appear before or after length suffix
     183                if ( str.find_last_of( "uU" ) != string::npos ) Unsigned = true;
     184
     185                posn = str.rfind( "hh" );
     186                if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
     187
     188                posn = str.rfind( "HH" );
     189                if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
     190
     191                posn = str.find_last_of( "hH" );
     192                if ( posn != string::npos ) { type = 0; str.erase( posn, 1 ); goto FINI; }
     193
     194                posn = str.find_last_of( "nN" );
     195                if ( posn != string::npos ) { type = 2; str.erase( posn, 1 ); goto FINI; }
     196
     197                if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) { type = 4; goto FINI; }
     198
     199                lnthSuffix( str, type, ltype );                                 // must be after check for "ll"
     200                if ( type == -1 ) {                                                             // only 'u' suffix ?
     201                        valueToType( v, dec, type, Unsigned );
     202                } // if
     203          FINI: ;
     204        } // if
    298205
    299206        //if ( !( 0 <= type && type <= 6 ) ) { printf( "%s %lu %d %s\n", fred.c_str(), fred.length(), type, str.c_str() ); }
     
    307214        } else if ( ltype != -1 ) {                                                     // explicit length ?
    308215                if ( ltype == 6 ) {                                                             // int128, (int128)constant
    309 //                      ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false );
    310                         ret2 = new ConstantExpr( Constant( new BasicType( noQualifiers, BasicType::LongLongSignedInt ), str2, v2 ) );
    311                         ret = build_compoundLiteral( DeclarationNode::newBasicType( DeclarationNode::Int128 )->addType( DeclarationNode::newSignedNess( DeclarationNode::Unsigned ) ),
    312                                                                                  new InitializerNode( (InitializerNode *)(new InitializerNode( new ExpressionNode( v2 == 0 ? ret2 : ret ) ))->set_last( new InitializerNode( new ExpressionNode( v2 == 0 ? ret : ret2 ) ) ), true ) );
     216                        ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false );
    313217                } else {                                                                                // explicit length, (length_type)constant
    314218                        ret = new CastExpr( ret, new TypeInstType( Type::Qualifiers(), lnthsInt[Unsigned][ltype], false ), false );
     
    438342                if ( str[1] == '8' ) goto Default;                              // utf-8 characters => array of char
    439343                // lookup type of associated typedef
    440                 strtype = new TypeInstType( Type::Qualifiers( ), "char16_t", false );
     344                strtype = new TypeInstType( Type::Qualifiers( Type::Const ), "char16_t", false );
    441345                break;
    442346          case 'U':
    443                 strtype = new TypeInstType( Type::Qualifiers( ), "char32_t", false );
     347                strtype = new TypeInstType( Type::Qualifiers( Type::Const ), "char32_t", false );
    444348                break;
    445349          case 'L':
    446                 strtype = new TypeInstType( Type::Qualifiers( ), "wchar_t", false );
     350                strtype = new TypeInstType( Type::Qualifiers( Type::Const ), "wchar_t", false );
    447351                break;
    448352          Default:                                                                                      // char default string type
    449353          default:
    450                 strtype = new BasicType( Type::Qualifiers( ), BasicType::Char );
     354                strtype = new BasicType( Type::Qualifiers( Type::Const ), BasicType::Char );
    451355        } // switch
    452356        ArrayType * at = new ArrayType( noQualifiers, strtype,
  • src/Parser/ParseNode.h

    reef8dfb rbdfc032  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Oct 24 03:53:54 2020
    13 // Update Count     : 895
     12// Last Modified On : Mon Dec 16 07:46:01 2019
     13// Update Count     : 888
    1414//
    1515
     
    3737class Attribute;
    3838class Declaration;
    39 struct DeclarationNode;
     39class DeclarationNode;
    4040class DeclarationWithType;
    4141class ExpressionNode;
    4242class Initializer;
    43 struct StatementNode;
     43class StatementNode;
    4444
    4545//##############################################################################
     
    8686class InitializerNode : public ParseNode {
    8787  public:
    88         InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr );
     88        InitializerNode( ExpressionNode *, bool aggrp = false,  ExpressionNode * des = nullptr );
    8989        InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr );
    9090        InitializerNode( bool isDelete );
     
    205205struct TypeData;
    206206
    207 struct DeclarationNode : public ParseNode {
     207class DeclarationNode : public ParseNode {
     208  public:
    208209        // These enumerations must harmonize with their names in DeclarationNode.cc.
    209210        enum BasicType { Void, Bool, Char, Int, Int128,
     
    303304        bool get_inLine() const { return inLine; }
    304305        DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
    305 
     306  public:
    306307        DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }
    307308
     
    359360//##############################################################################
    360361
    361 struct StatementNode final : public ParseNode {
     362class StatementNode final : public ParseNode {
     363  public:
    362364        StatementNode() { stmt = nullptr; }
    363365        StatementNode( Statement * stmt ) : stmt( stmt ) {}
     
    380382                os << stmt.get() << std::endl;
    381383        }
    382 
     384  private:
    383385        std::unique_ptr<Statement> stmt;
    384386}; // StatementNode
     
    424426Statement * build_finally( StatementNode * stmt );
    425427Statement * build_compound( StatementNode * first );
    426 StatementNode * maybe_build_compound( StatementNode * first );
    427428Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
    428429Statement * build_directive( std::string * directive );
    429 SuspendStmt * build_suspend( StatementNode *, SuspendStmt::Type = SuspendStmt::None);
    430430WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when );
    431431WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when, WaitForStmt * existing );
     
    449449                                * out++ = result;
    450450                        } else {
    451                                 SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );
     451                                assertf(false, "buildList unknown type");
    452452                        } // if
    453453                } catch( SemanticErrorException & e ) {
  • src/Parser/ParserTypes.h

    reef8dfb rbdfc032  
    1010// Created On       : Sat Sep 22 08:58:10 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 11:04:40 2020
    13 // Update Count     : 351
     12// Last Modified On : Sat Jul 22 09:33:28 2017
     13// Update Count     : 350
    1414//
    1515
     
    2727// current location in the input
    2828extern int yylineno;
    29 extern char * yyfilename;
     29extern char *yyfilename;
    3030
    3131struct Location {
    32     char * file;
     32    char *file;
    3333    int line;
    3434}; // Location
    3535
    3636struct Token {
    37     std::string * str;                                                                  // must be pointer as used in union
     37    std::string *str;                                                                   // must be pointer as used in union
    3838    Location loc;
    3939
  • src/Parser/StatementNode.cc

    reef8dfb rbdfc032  
    1010// Created On       : Sat May 16 14:59:41 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Oct 24 04:20:55 2020
    13 // Update Count     : 383
     12// Last Modified On : Sat Aug  4 09:39:25 2018
     13// Update Count     : 363
    1414//
    1515
     
    249249} // build_finally
    250250
    251 SuspendStmt * build_suspend( StatementNode * then, SuspendStmt::Type type ) {
    252         auto node = new SuspendStmt();
    253 
    254         node->type = type;
    255 
    256         std::list< Statement * > stmts;
    257         buildMoveList< Statement, StatementNode >( then, stmts );
    258         if(!stmts.empty()) {
    259                 assert( stmts.size() == 1 );
    260                 node->then = dynamic_cast< CompoundStmt * >( stmts.front() );
    261         }
    262 
    263         return node;
    264 }
    265 
    266251WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) {
    267252        auto node = new WaitForStmt();
     
    345330} // build_compound
    346331
    347 // A single statement in a control structure is always converted to a compound statement so subsequent generated code
    348 // can be placed within this compound statement. Otherwise, code generation has to constantly check for a single
    349 // statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a
    350 // conical form for code generation.
    351 StatementNode * maybe_build_compound( StatementNode * first ) {
    352         // Optimization: if the control-structure statement is a compound statement, do not wrap it.
    353         // e.g., if (...) {...} do not wrap the existing compound statement.
    354         if ( ! dynamic_cast<CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
    355                 CompoundStmt * cs = new CompoundStmt();
    356                 buildMoveList( first, cs->get_kids() );
    357                 return new StatementNode( cs );
    358         } // if
    359         return first;
    360 } // maybe_build_compound
    361 
    362332Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    363333        std::list< Expression * > out, in;
  • src/Parser/TypeData.cc

    reef8dfb rbdfc032  
    769769          case AggregateDecl::Struct:
    770770          case AggregateDecl::Coroutine:
    771           case AggregateDecl::Generator:
    772771          case AggregateDecl::Monitor:
    773772          case AggregateDecl::Thread:
     
    900899                ret = new TypeDecl( name, scs, typebuild( td->base ), TypeDecl::Dtype, true );
    901900        } // if
     901        buildList( td->symbolic.params, ret->get_parameters() );
    902902        buildList( td->symbolic.assertions, ret->get_assertions() );
    903903        ret->base->attributes.splice( ret->base->attributes.end(), attributes );
  • src/Parser/TypedefTable.cc

    reef8dfb rbdfc032  
    1010// Created On       : Sat May 16 15:20:13 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 08:06:36 2020
    13 // Update Count     : 259
     12// Last Modified On : Wed Jul 25 15:32:35 2018
     13// Update Count     : 258
    1414//
    1515
     
    4747} // TypedefTable::~TypedefTable
    4848
    49 bool TypedefTable::exists( const string & identifier ) const {
     49bool TypedefTable::exists( const string & identifier ) {
    5050        return kindTable.find( identifier ) != kindTable.end();
    5151} // TypedefTable::exists
    5252
    53 bool TypedefTable::existsCurr( const string & identifier ) const {
     53bool TypedefTable::existsCurr( const string & identifier ) {
    5454        return kindTable.findAt( kindTable.currentScope() - 1, identifier ) != kindTable.end();
    5555} // TypedefTable::exists
  • src/Parser/TypedefTable.h

    reef8dfb rbdfc032  
    1010// Created On       : Sat May 16 15:24:36 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 08:06:37 2020
    13 // Update Count     : 117
     12// Last Modified On : Wed Jul 25 15:33:55 2018
     13// Update Count     : 114
    1414//
    1515
     
    3030        ~TypedefTable();
    3131
    32         bool exists( const std::string & identifier ) const;
    33         bool existsCurr( const std::string & identifier ) const;
     32        bool exists( const std::string & identifier );
     33        bool existsCurr( const std::string & identifier );
    3434        int isKind( const std::string & identifier ) const;
    3535        void makeTypedef( const std::string & name, int kind = TYPEDEFname );
  • src/Parser/lex.ll

    reef8dfb rbdfc032  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Tue Oct  6 18:15:41 2020
    13  * Update Count     : 743
     12 * Last Modified On : Sat Feb  1 07:16:44 2020
     13 * Update Count     : 724
    1414 */
    1515
     
    4343#include "TypedefTable.h"
    4444
    45 string * build_postfix_name( string * name );
    46 
    4745char *yyfilename;
    4846string *strtext;                                                                                // accumulate parts of character and string constant value
     
    6260#define IDENTIFIER_RETURN()     RETURN_VAL( typedefTable.isKind( yytext ) )
    6361
    64 #ifdef HAVE_KEYWORDS_FLOATXX                                                    // GCC >= 7 => keyword, otherwise typedef
     62#ifdef HAVE_KEYWORDS_FLOATXX                                                            // GCC >= 7 => keyword, otherwise typedef
    6563#define FLOATXX(v) KEYWORD_RETURN(v);
    6664#else
    67 #define FLOATXX(v) IDENTIFIER_RETURN();
     65#define FLOATXX(v) IDENTIFIER_RETURN(); 
    6866#endif // HAVE_KEYWORDS_FLOATXX
    6967
     
    292290__restrict__    { KEYWORD_RETURN(RESTRICT); }                   // GCC
    293291return                  { KEYWORD_RETURN(RETURN); }
    294  /* resume                      { KEYWORD_RETURN(RESUME); }                             // CFA */
     292        /* resume                       { KEYWORD_RETURN(RESUME); }                             // CFA */
    295293short                   { KEYWORD_RETURN(SHORT); }
    296294signed                  { KEYWORD_RETURN(SIGNED); }
     
    301299_Static_assert  { KEYWORD_RETURN(STATICASSERT); }               // C11
    302300struct                  { KEYWORD_RETURN(STRUCT); }
    303 suspend                 { KEYWORD_RETURN(SUSPEND); }                    // CFA
     301        /* suspend                      { KEYWORD_RETURN(SUSPEND); }                    // CFA */
    304302switch                  { KEYWORD_RETURN(SWITCH); }
    305303thread                  { KEYWORD_RETURN(THREAD); }                             // C11
     
    332330                                /* identifier */
    333331{identifier}    { IDENTIFIER_RETURN(); }
    334 "``"{identifier} {                                                                              // CFA
    335         yytext[yyleng] = '\0'; yytext += 2;                                     // SKULLDUGGERY: remove backquotes (ok to shorten?)
     332"``"{identifier}"``" {                                                                  // CFA
     333        yytext[yyleng - 2] = '\0'; yytext += 2;                         // SKULLDUGGERY: remove backquotes (ok to shorten?)
    336334        IDENTIFIER_RETURN();
    337335}
     
    434432"?"({op_unary_pre_post}|"()"|"[?]"|"{}") { IDENTIFIER_RETURN(); }
    435433"^?{}"                  { IDENTIFIER_RETURN(); }
    436 "?`"{identifier} {                                                                              // postfix operator
    437         yylval.tok.str = new string( &yytext[2] );                      // remove ?`
    438         yylval.tok.str = build_postfix_name( yylval.tok.str ); // add prefix
    439         RETURN_LOCN( typedefTable.isKind( *yylval.tok.str ) );
    440 }
     434"?`"{identifier} { IDENTIFIER_RETURN(); }                               // postfix operator
    441435"?"{op_binary_over}"?"  { IDENTIFIER_RETURN(); }                // binary
    442436        /*
  • src/Parser/module.mk

    reef8dfb rbdfc032  
    1717BUILT_SOURCES = Parser/parser.hh
    1818
    19 AM_YFLAGS = -d -t -v -Wno-yacc
     19AM_YFLAGS = -d -t -v
    2020
    2121SRC += \
     
    2323       Parser/ExpressionNode.cc \
    2424       Parser/InitializerNode.cc \
    25        Parser/lex.ll \
    2625       Parser/ParseNode.cc \
    27        Parser/ParseNode.h \
    28        Parser/parser.yy \
    29        Parser/ParserTypes.h \
    30        Parser/parserutility.cc \
    31        Parser/parserutility.h \
    3226       Parser/StatementNode.cc \
    3327       Parser/TypeData.cc \
    34        Parser/TypeData.h \
    3528       Parser/TypedefTable.cc \
    36        Parser/TypedefTable.h
     29       Parser/lex.ll \
     30       Parser/parser.yy \
     31       Parser/parserutility.cc
    3732
    3833MOSTLYCLEANFILES += Parser/lex.cc Parser/parser.cc Parser/parser.hh Parser/parser.output
  • src/Parser/parser.yy

    reef8dfb rbdfc032  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Oct 24 08:21:14 2020
    13 // Update Count     : 4624
     12// Last Modified On : Sat Feb  1 10:04:40 2020
     13// Update Count     : 4440
    1414//
    1515
     
    166166} // rebindForall
    167167
    168 string * build_postfix_name( string * name ) {
    169         *name = string("__postfix_func_") + *name;
    170         return name;
     168NameExpr * build_postfix_name( const string * name ) {
     169        NameExpr * new_name = build_varref( new string( "?`" + *name ) );
     170        delete name;
     171        return new_name;
    171172} // build_postfix_name
    172173
     
    204205                        return forCtrl( type, new string( identifier->name ), start, compop, comp, inc );
    205206                } else {
    206                         SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr;
     207                        SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed" ); return nullptr;
    207208                } // if
    208209        } else {
    209                 SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr;
     210                SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed" ); return nullptr;
    210211        } // if
    211212} // forCtrl
     
    278279%token OTYPE FTYPE DTYPE TTYPE TRAIT                                    // CFA
    279280%token SIZEOF OFFSETOF
    280 // %token RESUME                                                                                        // CFA
    281 %token SUSPEND                                                                                  // CFA
     281// %token SUSPEND RESUME                                                                        // CFA
    282282%token ATTRIBUTE EXTENSION                                                              // GCC
    283283%token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN
     
    329329%type<en> conditional_expression                constant_expression                     assignment_expression           assignment_expression_opt
    330330%type<en> comma_expression                              comma_expression_opt
    331 %type<en> argument_expression_list_opt  argument_expression                     default_initialize_opt
     331%type<en> argument_expression_list              argument_expression                     default_initialize_opt
    332332%type<ifctl> if_control_expression
    333333%type<fctl> for_control_expression              for_control_expression_list
     
    370370%type<decl> assertion assertion_list assertion_list_opt
    371371
    372 %type<en> bit_subrange_size_opt bit_subrange_size
     372%type<en>   bit_subrange_size_opt bit_subrange_size
    373373
    374374%type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type
     
    624624                // equivalent to the old x[i,j].
    625625                { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); }
    626         | postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call
     626        | postfix_expression '{' argument_expression_list '}' // CFA, constructor call
    627627                {
    628628                        Token fn;
     
    630630                        $$ = new ExpressionNode( new ConstructorExpr( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) );
    631631                }
    632         | postfix_expression '(' argument_expression_list_opt ')'
     632        | postfix_expression '(' argument_expression_list ')'
    633633                { $$ = new ExpressionNode( build_func( $1, $3 ) ); }
    634634        | postfix_expression '`' identifier                                     // CFA, postfix call
    635                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
     635                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $3 ) ), $1 ) ); }
    636636        | constant '`' identifier                                                       // CFA, postfix call
    637                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
     637                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $3 ) ), $1 ) ); }
    638638        | string_literal '`' identifier                                         // CFA, postfix call
    639                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), new ExpressionNode( $1 ) ) ); }
     639                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $3 ) ), new ExpressionNode( $1 ) ) ); }
    640640        | postfix_expression '.' identifier
    641641                { $$ = new ExpressionNode( build_fieldSel( $1, build_varref( $3 ) ) ); }
     
    662662        | '(' type_no_function ')' '@' '{' initializer_list_opt comma_opt '}' // CFA, explicit C compound-literal
    663663                { $$ = new ExpressionNode( build_compoundLiteral( $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); }
    664         | '^' primary_expression '{' argument_expression_list_opt '}' // CFA, destructor call
     664        | '^' primary_expression '{' argument_expression_list '}' // CFA, destructor call
    665665                {
    666666                        Token fn;
     
    670670        ;
    671671
    672 argument_expression_list_opt:
     672argument_expression_list:
    673673        // empty
    674674                { $$ = nullptr; }
    675675        | argument_expression
    676         | argument_expression_list_opt ',' argument_expression
     676        | argument_expression_list ',' argument_expression
    677677                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
    678678        ;
     
    793793        | '(' aggregate_control '&' ')' cast_expression         // CFA
    794794                { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
     795                // VIRTUAL cannot be opt because of look ahead issues
    795796        | '(' VIRTUAL ')' cast_expression                                       // CFA
    796797                { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild< Expression >( $4 ), maybeMoveBuildType( nullptr ) ) ); }
     
    918919        conditional_expression
    919920        | unary_expression assignment_operator assignment_expression
    920                 {
    921 //                      if ( $2 == OperKinds::AtAssn ) {
    922 //                              SemanticError( yylloc, "C @= assignment is currently unimplemented." ); $$ = nullptr;
    923 //                      } else {
    924                                 $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) );
    925 //                      } // if
    926                 }
     921                { $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) ); }
    927922        | unary_expression '=' '{' initializer_list_opt comma_opt '}'
    928923                { SemanticError( yylloc, "Initializer assignment is currently unimplemented." ); $$ = nullptr; }
     
    965960
    966961tuple_expression_list:
    967         assignment_expression
    968         | '@'                                                                                           // CFA
    969                 { SemanticError( yylloc, "Eliding tuple element with '@' is currently unimplemented." ); $$ = nullptr; }
    970         | tuple_expression_list ',' assignment_expression
     962        assignment_expression_opt
     963        | tuple_expression_list ',' assignment_expression_opt
    971964                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
    972         | tuple_expression_list ',' '@'
    973                 { SemanticError( yylloc, "Eliding tuple element with '@' is currently unimplemented." ); $$ = nullptr; }
    974965        ;
    975966
     
    10801071        IF '(' if_control_expression ')' statement                      %prec THEN
    10811072                // explicitly deal with the shift/reduce conflict on if/else
    1082                 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), nullptr ) ); }
     1073                { $$ = new StatementNode( build_if( $3, $5, nullptr ) ); }
    10831074        | IF '(' if_control_expression ')' statement ELSE statement
    1084                 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); }
     1075                { $$ = new StatementNode( build_if( $3, $5, $7 ) ); }
    10851076        ;
    10861077
     
    11301121
    11311122case_clause:                                                                                    // CFA
    1132         case_label_list statement                                       { $$ = $1->append_last_case( maybe_build_compound( $2 ) ); }
     1123        case_label_list statement                                       { $$ = $1->append_last_case( new StatementNode( build_compound( $2 ) ) ); }
    11331124        ;
    11341125
     
    11481139iteration_statement:
    11491140        WHILE '(' push if_control_expression ')' statement pop
    1150                 { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); }
     1141                { $$ = new StatementNode( build_while( $4, $6 ) ); }
    11511142        | WHILE '(' ')' statement                                                       // CFA => while ( 1 )
    1152                 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
     1143                { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), $4 ) ); }
    11531144        | DO statement WHILE '(' comma_expression ')' ';'
    1154                 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
     1145                { $$ = new StatementNode( build_do_while( $5, $2 ) ); }
    11551146        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    1156                 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
     1147                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), $2 ) ); }
    11571148        | FOR '(' push for_control_expression_list ')' statement pop
    1158                 { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); }
     1149                { $$ = new StatementNode( build_for( $4, $6 ) ); }
    11591150        | FOR '(' ')' statement                                                         // CFA => for ( ;; )
    1160                 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
     1151                { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), $4 ) ); }
    11611152        ;
    11621153
     
    11951186                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    11961187                                                OperKinds::LThan, $1->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1197         | '=' comma_expression                                                          // CFA
     1188        | '=' comma_expression                                                                  // CFA
    11981189                { $$ = forCtrl( $2, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    11991190                                                OperKinds::LEThan, $2->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
     
    12021193        | comma_expression inclexcl comma_expression '~' comma_expression // CFA
    12031194                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, $5 ); }
    1204         | comma_expression ';'                                                          // CFA
    1205                 { $$ = forCtrl( new ExpressionNode( build_constantInteger( *new string( "0u" ) ) ), $1, nullptr, OperKinds::LThan, nullptr, nullptr ); }
    12061195        | comma_expression ';' comma_expression                         // CFA
    12071196                { $$ = forCtrl( $3, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    12081197                                                OperKinds::LThan, $3->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1209         | comma_expression ';' '=' comma_expression                     // CFA
     1198        | comma_expression ';' '=' comma_expression                             // CFA
    12101199                { $$ = forCtrl( $4, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    12111200                                                OperKinds::LEThan, $4->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
     
    12711260        | RETURN '{' initializer_list_opt comma_opt '}' ';'
    12721261                { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; }
    1273         | SUSPEND ';'
    1274                 { $$ = new StatementNode( build_suspend( nullptr ) ); }
    1275         | SUSPEND compound_statement
    1276                 { $$ = new StatementNode( build_suspend( $2 ) ); }
    1277         | SUSPEND COROUTINE ';'
    1278                 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Coroutine ) ); }
    1279         | SUSPEND COROUTINE compound_statement
    1280                 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Coroutine ) ); }
    1281         | SUSPEND GENERATOR ';'
    1282                 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Generator ) ); }
    1283         | SUSPEND GENERATOR compound_statement
    1284                 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Generator ) ); }
     1262        // | SUSPEND ';'
     1263        //      { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
     1264        // | SUSPEND compound_statement ';'
     1265        //      { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
    12851266        | THROW assignment_expression_opt ';'                           // handles rethrow
    12861267                { $$ = new StatementNode( build_throw( $2 ) ); }
     
    13051286// If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so change syntax to "with mutex".
    13061287mutex_statement:
    1307         MUTEX '(' argument_expression_list_opt ')' statement
     1288        MUTEX '(' argument_expression_list ')' statement
    13081289                { SemanticError( yylloc, "Mutex statement is currently unimplemented." ); $$ = nullptr; }
    13091290        ;
     
    13221303        WAITFOR '(' cast_expression ')'
    13231304                { $$ = $3; }
    1324 //      | WAITFOR '(' cast_expression ',' argument_expression_list_opt ')'
     1305//      | WAITFOR '(' cast_expression ',' argument_expression_list ')'
    13251306//              { $$ = (ExpressionNode *)$3->set_last( $5 ); }
    1326         | WAITFOR '(' cast_expression_list ':' argument_expression_list_opt ')'
     1307        | WAITFOR '(' cast_expression_list ':' argument_expression_list ')'
    13271308                { $$ = (ExpressionNode *)($3->set_last( $5 )); }
    13281309        ;
     
    13311312        cast_expression
    13321313        | cast_expression_list ',' cast_expression
    1333                 // { $$ = (ExpressionNode *)($1->set_last( $3 )); }
    1334                 { SemanticError( yylloc, "List of mutex member is currently unimplemented." ); $$ = nullptr; }
     1314                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
    13351315        ;
    13361316
     
    13411321waitfor_clause:
    13421322        when_clause_opt waitfor statement                                       %prec THEN
    1343                 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1 ); }
     1323                { $$ = build_waitfor( $2, $3, $1 ); }
    13441324        | when_clause_opt waitfor statement WOR waitfor_clause
    1345                 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1, $5 ); }
     1325                { $$ = build_waitfor( $2, $3, $1, $5 ); }
    13461326        | when_clause_opt timeout statement                                     %prec THEN
    1347                 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1 ); }
     1327                { $$ = build_waitfor_timeout( $2, $3, $1 ); }
    13481328        | when_clause_opt ELSE statement
    1349                 { $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); }
     1329                { $$ = build_waitfor_timeout( nullptr, $3, $1 ); }
    13501330                // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    13511331        | when_clause_opt timeout statement WOR ELSE statement
    13521332                { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    13531333        | when_clause_opt timeout statement WOR when_clause ELSE statement
    1354                 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1, maybe_build_compound( $7 ), $5 ); }
     1334                { $$ = build_waitfor_timeout( $2, $3, $1, $7, $5 ); }
    13551335        ;
    13561336
     
    16101590                // type_specifier can resolve to just TYPEDEFname (e.g., typedef int T; int f( T );). Therefore this must be
    16111591                // flattened to allow lookahead to the '(' without having to reduce identifier_or_type_name.
    1612         cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
     1592        cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')'
    16131593                // To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator).
    1614                 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 )->addQualifiers( $8 ); }
    1615         | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
    1616                 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 )->addQualifiers( $8 ); }
     1594                { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); }
     1595        | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')'
     1596                { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); }
    16171597        ;
    16181598
     
    16751655
    16761656typedef_expression:
    1677                 // deprecated GCC, naming expression type: typedef name = exp; gives a name to the type of an expression
     1657                // GCC, naming expression type: typedef name = exp; gives a name to the type of an expression
    16781658        TYPEDEF identifier '=' assignment_expression
    16791659                {
    1680                         SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
     1660                        // $$ = DeclarationNode::newName( 0 );                  // unimplemented
     1661                        SemanticError( yylloc, "Typedef expression is currently unimplemented." ); $$ = nullptr;
    16811662                }
    16821663        | typedef_expression pop ',' push identifier '=' assignment_expression
    16831664                {
    1684                         SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
    1685                 }
    1686         ;
     1665                        // $$ = DeclarationNode::newName( 0 );                  // unimplemented
     1666                        SemanticError( yylloc, "Typedef expression is currently unimplemented." ); $$ = nullptr;
     1667                }
     1668        ;
     1669
     1670//c_declaration:
     1671//      declaring_list pop ';'
     1672//      | typedef_declaration pop ';'
     1673//      | typedef_expression pop ';'                                            // GCC, naming expression type
     1674//      | sue_declaration_specifier pop ';'
     1675//      ;
     1676//
     1677//declaring_list:
     1678//              // A semantic check is required to ensure asm_name only appears on declarations with implicit or explicit static
     1679//              // storage-class
     1680//       declarator asm_name_opt initializer_opt
     1681//              {
     1682//                      typedefTable.addToEnclosingScope( IDENTIFIER );
     1683//                      $$ = ( $2->addType( $1 ))->addAsmName( $3 )->addInitializer( $4 );
     1684//              }
     1685//      | declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt
     1686//              {
     1687//                      typedefTable.addToEnclosingScope( IDENTIFIER );
     1688//                      $$ = $1->appendList( $1->cloneBaseType( $4->addAsmName( $5 )->addInitializer( $6 ) ) );
     1689//              }
     1690//      ;
    16871691
    16881692c_declaration:
     
    16901694                { $$ = distAttr( $1, $2 ); }
    16911695        | typedef_declaration
    1692         | typedef_expression                                                            // deprecated GCC, naming expression type
     1696        | typedef_expression                                                            // GCC, naming expression type
    16931697        | sue_declaration_specifier
    16941698        ;
     
    20692073                { yyy = true; $$ = AggregateDecl::Union; }
    20702074        | EXCEPTION                                                                                     // CFA
    2071                 // { yyy = true; $$ = AggregateDecl::Exception; }
    2072                 { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2075                { yyy = true; $$ = AggregateDecl::Exception; }
    20732076        ;
    20742077
    20752078aggregate_control:                                                                              // CFA
    2076         MONITOR
    2077                 { yyy = true; $$ = AggregateDecl::Monitor; }
    2078         | MUTEX STRUCT
    2079                 { yyy = true; $$ = AggregateDecl::Monitor; }
    2080         | GENERATOR
    2081                 { yyy = true; $$ = AggregateDecl::Generator; }
    2082         | MUTEX GENERATOR
    2083                 { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2079        GENERATOR
     2080                { yyy = true; $$ = AggregateDecl::Coroutine; }
    20842081        | COROUTINE
    20852082                { yyy = true; $$ = AggregateDecl::Coroutine; }
    2086         | MUTEX COROUTINE
    2087                 { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2083        | MONITOR
     2084                { yyy = true; $$ = AggregateDecl::Monitor; }
    20882085        | THREAD
    20892086                { yyy = true; $$ = AggregateDecl::Thread; }
    2090         | MUTEX THREAD
    2091                 { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    20922087        ;
    20932088
     
    24122407// Overloading: function, data, and operator identifiers may be overloaded.
    24132408//
    2414 // Type declarations: "otype" is used to generate new types for declaring objects. Similarly, "dtype" is used for object
     2409// Type declarations: "type" is used to generate new types for declaring objects. Similarly, "dtype" is used for object
    24152410//     and incomplete types, and "ftype" is used for function types. Type declarations with initializers provide
    24162411//     definitions of new types. Type declarations with storage class "extern" provide opaque types.
     
    24412436        type_class identifier_or_type_name
    24422437                { typedefTable.addToScope( *$2, TYPEDEFname, "9" ); }
    2443         type_initializer_opt assertion_list_opt
     2438          type_initializer_opt assertion_list_opt
    24442439                { $$ = DeclarationNode::newTypeParam( $1, $2 )->addTypeInitializer( $4 )->addAssertions( $5 ); }
    24452440        | type_specifier identifier_parameter_declarator
     
    24682463        assertion
    24692464        | assertion_list assertion
    2470                 { $$ = $1->appendList( $2 ); }
     2465                { $$ = $1 ? $1->appendList( $2 ) : $2; }
    24712466        ;
    24722467
     
    27552750        | attr_name
    27562751                { $$ = DeclarationNode::newAttribute( $1 ); }
    2757         | attr_name '(' argument_expression_list_opt ')'
     2752        | attr_name '(' argument_expression_list ')'
    27582753                { $$ = DeclarationNode::newAttribute( $1, $3 ); }
    27592754        ;
  • src/ResolvExpr/AdjustExprType.cc

    reef8dfb rbdfc032  
    100100
    101101namespace {
    102         class AdjustExprType_new final : public ast::WithShortCircuiting {
     102        struct AdjustExprType_new final : public ast::WithShortCircuiting {
     103                const ast::TypeEnvironment & tenv;
    103104                const ast::SymbolTable & symtab;
    104         public:
    105                 const ast::TypeEnvironment & tenv;
    106105
    107106                AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
    108                 : symtab( syms ), tenv( e ) {}
     107                : tenv( e ), symtab( syms ) {}
    109108
    110                 void previsit( const ast::VoidType * ) { visit_children = false; }
    111                 void previsit( const ast::BasicType * ) { visit_children = false; }
    112                 void previsit( const ast::PointerType * ) { visit_children = false; }
    113                 void previsit( const ast::ArrayType * ) { visit_children = false; }
    114                 void previsit( const ast::FunctionType * ) { visit_children = false; }
    115                 void previsit( const ast::StructInstType * ) { visit_children = false; }
    116                 void previsit( const ast::UnionInstType * ) { visit_children = false; }
    117                 void previsit( const ast::EnumInstType * ) { visit_children = false; }
    118                 void previsit( const ast::TraitInstType * ) { visit_children = false; }
    119                 void previsit( const ast::TypeInstType * ) { visit_children = false; }
    120                 void previsit( const ast::TupleType * ) { visit_children = false; }
    121                 void previsit( const ast::VarArgsType * ) { visit_children = false; }
    122                 void previsit( const ast::ZeroType * ) { visit_children = false; }
    123                 void previsit( const ast::OneType * ) { visit_children = false; }
     109                void premutate( const ast::VoidType * ) { visit_children = false; }
     110                void premutate( const ast::BasicType * ) { visit_children = false; }
     111                void premutate( const ast::PointerType * ) { visit_children = false; }
     112                void premutate( const ast::ArrayType * ) { visit_children = false; }
     113                void premutate( const ast::FunctionType * ) { visit_children = false; }
     114                void premutate( const ast::StructInstType * ) { visit_children = false; }
     115                void premutate( const ast::UnionInstType * ) { visit_children = false; }
     116                void premutate( const ast::EnumInstType * ) { visit_children = false; }
     117                void premutate( const ast::TraitInstType * ) { visit_children = false; }
     118                void premutate( const ast::TypeInstType * ) { visit_children = false; }
     119                void premutate( const ast::TupleType * ) { visit_children = false; }
     120                void premutate( const ast::VarArgsType * ) { visit_children = false; }
     121                void premutate( const ast::ZeroType * ) { visit_children = false; }
     122                void premutate( const ast::OneType * ) { visit_children = false; }
    124123
    125                 const ast::Type * postvisit( const ast::ArrayType * at ) {
     124                const ast::Type * postmutate( const ast::ArrayType * at ) {
    126125                        return new ast::PointerType{ at->base, at->qualifiers };
    127126                }
    128127
    129                 const ast::Type * postvisit( const ast::FunctionType * ft ) {
     128                const ast::Type * postmutate( const ast::FunctionType * ft ) {
    130129                        return new ast::PointerType{ ft };
    131130                }
    132131
    133                 const ast::Type * postvisit( const ast::TypeInstType * inst ) {
     132                const ast::Type * postmutate( const ast::TypeInstType * inst ) {
    134133                        // replace known function-type-variables with pointer-to-function
    135                         if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) {
     134                        if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
    136135                                if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
    137136                                        return new ast::PointerType{ inst };
  • src/ResolvExpr/AlternativeFinder.cc

    reef8dfb rbdfc032  
    131131
    132132        void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt ) {
    133                 std::vector<std::string> sorted;
    134                 sorted.reserve(list.size());
    135                 for(const auto & c : list) {
    136                         std::stringstream ss;
    137                         c.print( ss, indentAmt );
    138                         sorted.push_back(ss.str());
    139                 }
    140 
    141                 std::sort(sorted.begin(), sorted.end());
    142 
    143                 for ( const auto & s : sorted ) {
    144                         os << s << std::endl;
     133                Indenter indent = { indentAmt };
     134                for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
     135                        i->print( os, indent );
     136                        os << std::endl;
    145137                }
    146138        }
     
    259251                        SemanticError( expr, "No reasonable alternatives for expression " );
    260252                }
    261                 if ( mode.prune ) {
     253                if ( mode.satisfyAssns || mode.prune ) {
    262254                        // trim candidates just to those where the assertions resolve
    263255                        // - necessary pre-requisite to pruning
     
    12241216                        unify( castExpr->result, alt.expr->result, alt.env, needAssertions,
    12251217                                haveAssertions, openVars, indexer );
    1226                         Cost thisCost =
    1227                                 castExpr->isGenerated
    1228                                 ? conversionCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(),   indexer, alt.env )
    1229                                 : castCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(), indexer, alt.env );
     1218                        Cost thisCost = castCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(),
     1219                                indexer, alt.env );
    12301220                        PRINT(
    12311221                                std::cerr << "working on cast with result: " << castExpr->result << std::endl;
     
    13021292
    13031293                try {
    1304                         // Attempt 1 : turn (thread&)X into ($thread&)X.__thrd
     1294                        // Attempt 1 : turn (thread&)X into (thread_desc&)X.__thrd
    13051295                        // Clone is purely for memory management
    13061296                        std::unique_ptr<Expression> tech1 { new UntypedMemberExpr(new NameExpr(castExpr->concrete_target.field), castExpr->arg->clone()) };
     
    13131303                } catch(SemanticErrorException & ) {}
    13141304
    1315                 // Fallback : turn (thread&)X into ($thread&)get_thread(X)
     1305                // Fallback : turn (thread&)X into (thread_desc&)get_thread(X)
    13161306                std::unique_ptr<Expression> fallback { UntypedExpr::createDeref( new UntypedExpr(new NameExpr(castExpr->concrete_target.getter), { castExpr->arg->clone() })) };
    13171307                // don't prune here, since it's guaranteed all alternatives will have the same type
     
    17081698
    17091699                                // unification run for side-effects
    1710                                 bool canUnify = unify( toType, alt.expr->result, newEnv, need, have, openVars, indexer );
    1711                                 (void) canUnify;
     1700                                unify( toType, alt.expr->result, newEnv, need, have, openVars, indexer );
    17121701                                // xxx - do some inspecting on this line... why isn't result bound to initAlt.type?
    17131702
    1714                                 Cost thisCost = computeConversionCost( alt.expr->result, toType, alt.expr->get_lvalue(),
     1703                                Cost thisCost = castCost( alt.expr->result, toType, alt.expr->get_lvalue(),
    17151704                                        indexer, newEnv );
    1716 
    1717                                 PRINT(
    1718                                         Cost legacyCost = castCost( alt.expr->result, toType, alt.expr->get_lvalue(),
    1719                                                 indexer, newEnv );
    1720                                         std::cerr << "Considering initialization:";
    1721                                         std::cerr << std::endl << "  FROM: "; alt.expr->result->print(std::cerr);
    1722                                         std::cerr << std::endl << "  TO: ";   toType          ->print(std::cerr);
    1723                                         std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
    1724                                         std::cerr << std::endl << "  Legacy cost " << legacyCost;
    1725                                         std::cerr << std::endl << "  New cost " << thisCost;
    1726                                         std::cerr << std::endl;
    1727                                 )
    1728 
    17291705                                if ( thisCost != Cost::infinity ) {
    17301706                                        // count one safe conversion for each value that is thrown away
  • src/ResolvExpr/Candidate.cpp

    reef8dfb rbdfc032  
    4141
    4242void print( std::ostream & os, const CandidateList & cands, Indenter indent ) {
    43         std::vector<std::string> sorted;
    44         sorted.reserve(cands.size());
    45         for(const auto & c : cands) {
    46                 std::stringstream ss;
    47                 print( ss, *c, indent );
    48                 sorted.push_back(ss.str());
    49         }
    50 
    51         std::sort(sorted.begin(), sorted.end());
    52 
    53         for ( const auto & s : sorted ) {
    54                 os << s << std::endl;
     43        for ( const CandidateRef & cand : cands ) {
     44                print( os, *cand, indent );
     45                os << std::endl;
    5546        }
    5647}
  • src/ResolvExpr/Candidate.hpp

    reef8dfb rbdfc032  
    5151
    5252        Candidate( const ast::Expr * x, const ast::TypeEnvironment & e )
    53         : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {
    54                 assert(x->result);
    55         }
     53        : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {}
    5654
    5755        Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero )
    5856        : expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ),
    59           need( o.need ) {
    60                 assert(x->result);
    61         }
     57          need( o.need ) {}
    6258
    6359        Candidate(
    64                 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o,
     60                const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 
    6561                const ast::AssertionSet & n, const Cost & c, const Cost & cvt = Cost::zero )
    66         : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {
    67                 assert(x->result);
    68         }
     62        : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {}
    6963
    7064        Candidate(
     
    7266                ast::AssertionSet && n, const Cost & c, const Cost & cvt = Cost::zero )
    7367        : expr( x ), cost( c ), cvtCost( cvt ), env( std::move( e ) ), open( std::move( o ) ),
    74           need( n.begin(), n.end() ) {
    75                 assert(x->result);
    76         }
     68          need( n.begin(), n.end() ) {}
    7769};
    7870
  • src/ResolvExpr/CandidateFinder.cpp

    reef8dfb rbdfc032  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed Jun 5 14:30:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct  1 14:55:00 2019
    13 // Update Count     : 2
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Wed Jun 5 14:30:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    4343#include "SymTab/Validate.h"      // for validateType
    4444#include "Tuples/Tuples.h"        // for handleTupleAssignment
    45 #include "InitTweak/InitTweak.h"  // for getPointerBase
    46 
    47 #include "Common/Stats/Counter.h"
    4845
    4946#define PRINT( text ) if ( resolvep ) { text }
     
    5754                return new ast::CastExpr{ expr, expr->result->stripReferences() };
    5855        }
    59 
     56       
    6057        return expr;
    6158}
     
    6461UniqueId globalResnSlot = 0;
    6562
    66 Cost computeConversionCost(
    67         const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
    68         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     63Cost computeConversionCost( 
     64        const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,
     65        const ast::TypeEnvironment & env
    6966) {
    7067        PRINT(
     
    7774                std::cerr << std::endl;
    7875        )
    79         Cost convCost = conversionCost( argType, paramType, argIsLvalue, symtab, env );
     76        Cost convCost = conversionCost( argType, paramType, symtab, env );
    8077        PRINT(
    8178                std::cerr << std::endl << "cost is " << convCost << std::endl;
     
    110107
    111108        /// Computes conversion cost for a given expression to a given type
    112         const ast::Expr * computeExpressionConversionCost(
    113                 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
     109        const ast::Expr * computeExpressionConversionCost( 
     110                const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 
    114111        ) {
    115                 Cost convCost = computeConversionCost(
    116                                 arg->result, paramType, arg->get_lvalue(), symtab, env );
     112                Cost convCost = computeConversionCost( arg->result, paramType, symtab, env );
    117113                outCost += convCost;
    118114
    119                 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
    120                 // conversion. Ignore poly cost for now, since this requires resolution of the cast to
     115                // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 
     116                // conversion. Ignore poly cost for now, since this requires resolution of the cast to 
    121117                // infer parameters and this does not currently work for the reason stated below
    122118                Cost tmpCost = convCost;
     
    127123                        return new ast::CastExpr{ arg, newType };
    128124
    129                         // xxx - *should* be able to resolve this cast, but at the moment pointers are not
    130                         // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
     125                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not 
     126                        // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 
    131127                        // once this is fixed it should be possible to resolve the cast.
    132                         // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
    133                         // but it shouldn't be because this makes the conversion from DT* to DT* since
     128                        // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 
     129                        // but it shouldn't be because this makes the conversion from DT* to DT* since 
    134130                        // commontype(zero_t, DT*) is DT*, rather than nothing
    135131
    136132                        // CandidateFinder finder{ symtab, env };
    137133                        // finder.find( arg, ResolvMode::withAdjustment() );
    138                         // assertf( finder.candidates.size() > 0,
     134                        // assertf( finder.candidates.size() > 0, 
    139135                        //      "Somehow castable expression failed to find alternatives." );
    140                         // assertf( finder.candidates.size() == 1,
     136                        // assertf( finder.candidates.size() == 1, 
    141137                        //      "Somehow got multiple alternatives for known cast expression." );
    142138                        // return finder.candidates.front()->expr;
     
    147143
    148144        /// Computes conversion cost for a given candidate
    149         Cost computeApplicationConversionCost(
    150                 CandidateRef cand, const ast::SymbolTable & symtab
     145        Cost computeApplicationConversionCost( 
     146                CandidateRef cand, const ast::SymbolTable & symtab 
    151147        ) {
    152148                auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
     
    171167                                if ( function->isVarArgs ) {
    172168                                        convCost.incUnsafe();
    173                                         PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
     169                                        PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 
    174170                                                << convCost << std::endl; ; )
    175171                                        // convert reference-typed expressions into value-typed expressions
    176                                         cand->expr = ast::mutate_field_index(
    177                                                 appExpr, &ast::ApplicationExpr::args, i,
     172                                        cand->expr = ast::mutate_field_index( 
     173                                                appExpr, &ast::ApplicationExpr::args, i, 
    178174                                                referenceToRvalueConversion( args[i], convCost ) );
    179175                                        continue;
     
    184180                                // Default arguments should be free - don't include conversion cost.
    185181                                // Unwrap them here because they are not relevant to the rest of the system
    186                                 cand->expr = ast::mutate_field_index(
     182                                cand->expr = ast::mutate_field_index( 
    187183                                        appExpr, &ast::ApplicationExpr::args, i, def->expr );
    188184                                ++param;
     
    191187
    192188                        // mark conversion cost and also specialization cost of param type
    193                         // const ast::Type * paramType = (*param)->get_type();
    194                         cand->expr = ast::mutate_field_index(
    195                                 appExpr, &ast::ApplicationExpr::args, i,
    196                                 computeExpressionConversionCost(
    197                                         args[i], *param, symtab, cand->env, convCost ) );
    198                         convCost.decSpec( specCost( *param ) );
     189                        const ast::Type * paramType = (*param)->get_type();
     190                        cand->expr = ast::mutate_field_index( 
     191                                appExpr, &ast::ApplicationExpr::args, i, 
     192                                computeExpressionConversionCost( 
     193                                        args[i], paramType, symtab, cand->env, convCost ) );
     194                        convCost.decSpec( specCost( paramType ) );
    199195                        ++param;  // can't be in for-loop update because of the continue
    200196                }
     
    202198                if ( param != params.end() ) return Cost::infinity;
    203199
    204                 // specialization cost of return types can't be accounted for directly, it disables
     200                // specialization cost of return types can't be accounted for directly, it disables 
    205201                // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
    206202                //
     
    212208                // mark type variable and specialization cost of forall clause
    213209                convCost.incVar( function->forall.size() );
    214                 convCost.decSpec( function->assertions.size() );
     210                for ( const ast::TypeDecl * td : function->forall ) {
     211                        convCost.decSpec( td->assertions.size() );
     212                }
    215213
    216214                return convCost;
    217215        }
    218216
    219         void makeUnifiableVars(
    220                 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
    221                 ast::AssertionSet & need
     217        void makeUnifiableVars( 
     218                const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars,
     219                ast::AssertionSet & need 
    222220        ) {
    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;
     221                for ( const ast::TypeDecl * tyvar : type->forall ) {
     222                        unifiableVars[ tyvar->name ] = ast::TypeDecl::Data{ tyvar };
     223                        for ( const ast::DeclWithType * assn : tyvar->assertions ) {
     224                                need[ assn ].isUsed = true;
     225                        }
    228226                }
    229227        }
     
    256254
    257255                ArgPack()
    258                 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
     256                : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 
    259257                  tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    260 
     258               
     259                ArgPack(
     260                        const ast::TypeEnvironment & env, const ast::AssertionSet & need,
     261                        const ast::AssertionSet & have, const ast::OpenVarSet & open )
     262                : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
     263                  open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
     264               
    261265                ArgPack(
    262                         const ast::TypeEnvironment & env, const ast::AssertionSet & need,
    263                         const ast::AssertionSet & have, const ast::OpenVarSet & open )
    264                 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
    265                   open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    266 
    267                 ArgPack(
    268                         std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
    269                         ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
    270                         unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
     266                        std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
     267                        ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
     268                        unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
    271269                        unsigned nextExpl = 0, unsigned explAlt = 0 )
    272270                : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ),
    273271                  have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
    274272                  nextExpl( nextExpl ), explAlt( explAlt ) {}
    275 
     273               
    276274                ArgPack(
    277                         const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
     275                        const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 
    278276                        ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
    279                 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ),
    280                   need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ),
     277                : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 
     278                  need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 
    281279                  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
    282 
     280               
    283281                /// true if this pack is in the middle of an exploded argument
    284282                bool hasExpl() const { return nextExpl > 0; }
     
    288286                        return args[ nextArg-1 ][ explAlt ];
    289287                }
    290 
     288               
    291289                /// Ends a tuple expression, consolidating the appropriate args
    292290                void endTuple( const std::vector< ArgPack > & packs ) {
     
    309307
    310308        /// Instantiates an argument to match a parameter, returns false if no matching results left
    311         bool instantiateArgument(
    312                 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
    313                 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
    314                 unsigned nTuples = 0
     309        bool instantiateArgument( 
     310                const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 
     311                std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 
     312                unsigned nTuples = 0 
    315313        ) {
    316314                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
     
    320318                                // xxx - dropping initializer changes behaviour from previous, but seems correct
    321319                                // ^^^ need to handle the case where a tuple has a default argument
    322                                 if ( ! instantiateArgument(
     320                                if ( ! instantiateArgument( 
    323321                                        type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
    324322                                nTuples = 0;
     
    331329                } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
    332330                        // paramType is a ttype, consumes all remaining arguments
    333 
     331                       
    334332                        // completed tuples; will be spliced to end of results to finish
    335333                        std::vector< ArgPack > finalResults{};
     
    344342                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
    345343                                        unsigned nextArg = results[i].nextArg;
    346 
     344                                       
    347345                                        // use next element of exploded tuple if present
    348346                                        if ( results[i].hasExpl() ) {
     
    354352                                                results.emplace_back(
    355353                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    356                                                         copy( results[i].need ), copy( results[i].have ),
     354                                                        copy( results[i].need ), copy( results[i].have ), 
    357355                                                        copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
    358356                                                        results[i].explAlt );
     
    372370                                                        // push empty tuple expression
    373371                                                        newResult.parent = i;
    374                                                         newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
     372                                                        std::vector< ast::ptr< ast::Expr > > emptyList;
     373                                                        newResult.expr =
     374                                                                new ast::TupleExpr{ CodeLocation{}, move( emptyList ) };
    375375                                                        argType = newResult.expr->result;
    376376                                                } else {
     
    400400
    401401                                                // check unification for ttype before adding to final
    402                                                 if (
    403                                                         unify(
     402                                                if ( 
     403                                                        unify( 
    404404                                                                ttype, argType, newResult.env, newResult.need, newResult.have,
    405                                                                 newResult.open, symtab )
     405                                                                newResult.open, symtab ) 
    406406                                                ) {
    407407                                                        finalResults.emplace_back( move( newResult ) );
     
    424424                                                if ( expl.exprs.empty() ) {
    425425                                                        results.emplace_back(
    426                                                                 results[i], move( env ), copy( results[i].need ),
     426                                                                results[i], move( env ), copy( results[i].need ), 
    427427                                                                copy( results[i].have ), move( open ), nextArg + 1, expl.cost );
    428 
     428                                                       
    429429                                                        continue;
    430430                                                }
     
    432432                                                // add new result
    433433                                                results.emplace_back(
    434                                                         i, expl.exprs.front(), move( env ), copy( results[i].need ),
    435                                                         copy( results[i].have ), move( open ), nextArg + 1, nTuples,
     434                                                        i, expl.exprs.front(), move( env ), copy( results[i].need ), 
     435                                                        copy( results[i].have ), move( open ), nextArg + 1, nTuples, 
    436436                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    437437                                        }
     
    479479
    480480                                        results.emplace_back(
    481                                                 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg,
     481                                                i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 
    482482                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
    483483                                }
     
    495495                                        if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
    496496                                                results.emplace_back(
    497                                                         i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ),
     497                                                        i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 
    498498                                                        move( need ), move( have ), move( open ), nextArg, nTuples );
    499499                                        }
     
    517517                                if ( expl.exprs.empty() ) {
    518518                                        results.emplace_back(
    519                                                 results[i], move( env ), move( need ), move( have ), move( open ),
     519                                                results[i], move( env ), move( need ), move( have ), move( open ), 
    520520                                                nextArg + 1, expl.cost );
    521 
     521                                       
    522522                                        continue;
    523523                                }
     
    539539                                        // add new result
    540540                                        results.emplace_back(
    541                                                 i, expr, move( env ), move( need ), move( have ), move( open ),
     541                                                i, expr, move( env ), move( need ), move( have ), move( open ), 
    542542                                                nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    543543                                }
     
    548548                genStart = genEnd;
    549549
    550                 return genEnd != results.size();  // were any new results added?
     550                return genEnd != results.size();
    551551        }
    552552
    553553        /// Generate a cast expression from `arg` to `toType`
    554         const ast::Expr * restructureCast(
     554        const ast::Expr * restructureCast( 
    555555                ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
    556556        ) {
    557                 if (
    558                         arg->result->size() > 1
    559                         && ! toType->isVoid()
    560                         && ! dynamic_cast< const ast::ReferenceType * >( toType )
     557                if ( 
     558                        arg->result->size() > 1 
     559                        && ! toType->isVoid() 
     560                        && ! dynamic_cast< const ast::ReferenceType * >( toType ) 
    561561                ) {
    562                         // Argument is a tuple and the target type is neither void nor a reference. Cast each
    563                         // member of the tuple to its corresponding target type, producing the tuple of those
    564                         // cast expressions. If there are more components of the tuple than components in the
    565                         // target type, then excess components do not come out in the result expression (but
     562                        // Argument is a tuple and the target type is neither void nor a reference. Cast each 
     563                        // member of the tuple to its corresponding target type, producing the tuple of those 
     564                        // cast expressions. If there are more components of the tuple than components in the 
     565                        // target type, then excess components do not come out in the result expression (but 
    566566                        // UniqueExpr ensures that the side effects will still be produced)
    567567                        if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    568                                 // expressions which may contain side effects require a single unique instance of
     568                                // expressions which may contain side effects require a single unique instance of 
    569569                                // the expression
    570570                                arg = new ast::UniqueExpr{ arg->location, arg };
     
    574574                                // cast each component
    575575                                ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
    576                                 components.emplace_back(
     576                                components.emplace_back( 
    577577                                        restructureCast( idx, toType->getComponent( i ), isGenerated ) );
    578578                        }
     
    594594
    595595        /// Actually visits expressions to find their candidate interpretations
    596         class Finder final : public ast::WithShortCircuiting {
     596        struct Finder final : public ast::WithShortCircuiting {
     597                CandidateFinder & selfFinder;
    597598                const ast::SymbolTable & symtab;
    598         public:
    599                 static size_t traceId;
    600                 CandidateFinder & selfFinder;
    601599                CandidateList & candidates;
    602600                const ast::TypeEnvironment & tenv;
    603601                ast::ptr< ast::Type > & targetType;
    604602
    605                 enum Errors {
    606                         NotFound,
    607                         NoMatch,
    608                         ArgsToFew,
    609                         ArgsToMany,
    610                         RetsToFew,
    611                         RetsToMany,
    612                         NoReason
    613                 };
    614 
    615                 struct {
    616                         Errors code = NotFound;
    617                 } reason;
    618 
    619603                Finder( CandidateFinder & f )
    620                 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ),
     604                : selfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),
    621605                  targetType( f.targetType ) {}
    622 
     606               
    623607                void previsit( const ast::Node * ) { visit_children = false; }
    624608
     
    627611                void addCandidate( Args &&... args ) {
    628612                        candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
    629                         reason.code = NoReason;
    630613                }
    631614
     
    656639
    657640                /// Completes a function candidate with arguments located
    658                 void validateFunctionCandidate(
    659                         const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
    660                         CandidateList & out
     641                void validateFunctionCandidate( 
     642                        const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 
     643                        CandidateList & out 
    661644                ) {
    662                         ast::ApplicationExpr * appExpr =
     645                        ast::ApplicationExpr * appExpr = 
    663646                                new ast::ApplicationExpr{ func->expr->location, func->expr };
    664647                        // sum cost and accumulate arguments
     
    674657                        appExpr->args = move( vargs );
    675658                        // build and validate new candidate
    676                         auto newCand =
     659                        auto newCand = 
    677660                                std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
    678661                        PRINT(
     
    686669                /// Builds a list of candidates for a function, storing them in out
    687670                void makeFunctionCandidates(
    688                         const CandidateRef & func, const ast::FunctionType * funcType,
     671                        const CandidateRef & func, const ast::FunctionType * funcType, 
    689672                        const ExplodedArgs_new & args, CandidateList & out
    690673                ) {
     
    693676                        ast::TypeEnvironment funcEnv{ func->env };
    694677                        makeUnifiableVars( funcType, funcOpen, funcNeed );
    695                         // add all type variables as open variables now so that those not used in the
    696                         // parameter list are still considered open
     678                        // add all type variables as open variables now so that those not used in the parameter
     679                        // list are still considered open
    697680                        funcEnv.add( funcType->forall );
    698681
    699682                        if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {
    700683                                // attempt to narrow based on expected target type
    701                                 const ast::Type * returnType = funcType->returns.front();
    702                                 if ( ! unify(
    703                                         returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
     684                                const ast::Type * returnType = funcType->returns.front()->get_type();
     685                                if ( ! unify( 
     686                                        returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 
    704687                                ) {
    705688                                        // unification failed, do not pursue this candidate
     
    713696                        std::size_t genStart = 0;
    714697
    715                         // xxx - how to handle default arg after change to ftype representation?
    716                         if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {
    717                                 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {
    718                                         // function may have default args only if directly calling by name
    719                                         // must use types on candidate however, due to RenameVars substitution
    720                                         auto nParams = funcType->params.size();
    721 
    722                                         for (size_t i=0; i<nParams; ++i) {
    723                                                 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
    724                                                 if (!instantiateArgument(
    725                                                         funcType->params[i], obj->init, args, results, genStart, symtab)) return;
    726                                         }
    727                                         goto endMatch;
    728                                 }
    729                         }
    730                         for ( const auto & param : funcType->params ) {
    731                                 // Try adding the arguments corresponding to the current parameter to the existing
     698                        for ( const ast::DeclWithType * param : funcType->params ) {
     699                                auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param );
     700                                // Try adding the arguments corresponding to the current parameter to the existing
    732701                                // matches
    733                                 // no default args for indirect calls
    734                                 if ( ! instantiateArgument(
    735                                         param, nullptr, args, results, genStart, symtab ) ) return;
    736                         }
    737 
    738                         endMatch:
     702                                if ( ! instantiateArgument(
     703                                        obj->type, obj->init, args, results, genStart, symtab ) ) return;
     704                        }
     705
    739706                        if ( funcType->isVarArgs ) {
    740707                                // append any unused arguments to vararg pack
     
    783750                                                        if ( expl.exprs.empty() ) {
    784751                                                                results.emplace_back(
    785                                                                         results[i], move( env ), copy( results[i].need ),
    786                                                                         copy( results[i].have ), move( open ), nextArg + 1,
     752                                                                        results[i], move( env ), copy( results[i].need ), 
     753                                                                        copy( results[i].have ), move( open ), nextArg + 1, 
    787754                                                                        expl.cost );
    788755
     
    793760                                                        results.emplace_back(
    794761                                                                i, expl.exprs.front(), move( env ), copy( results[i].need ),
    795                                                                 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost,
     762                                                                copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 
    796763                                                                expl.exprs.size() == 1 ? 0 : 1, j );
    797764                                                }
     
    813780                /// Adds implicit struct-conversions to the alternative list
    814781                void addAnonConversions( const CandidateRef & cand ) {
    815                         // adds anonymous member interpretations whenever an aggregate value type is seen.
    816                         // it's okay for the aggregate expression to have reference type -- cast it to the
     782                        // adds anonymous member interpretations whenever an aggregate value type is seen. 
     783                        // it's okay for the aggregate expression to have reference type -- cast it to the 
    817784                        // base type to treat the aggregate as the referenced value
    818785                        ast::ptr< ast::Expr > aggrExpr( cand->expr );
    819786                        ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
    820787                        cand->env.apply( aggrType );
    821 
     788                       
    822789                        if ( aggrType.as< ast::ReferenceType >() ) {
    823790                                aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
     
    832799
    833800                /// Adds aggregate member interpretations
    834                 void addAggMembers(
    835                         const ast::BaseInstType * aggrInst, const ast::Expr * expr,
    836                         const Candidate & cand, const Cost & addedCost, const std::string & name
     801                void addAggMembers( 
     802                        const ast::ReferenceToType * aggrInst, const ast::Expr * expr,
     803                        const Candidate & cand, const Cost & addedCost, const std::string & name 
    837804                ) {
    838805                        for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
    839806                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
    840                                 CandidateRef newCand = std::make_shared<Candidate>(
     807                                CandidateRef newCand = std::make_shared<Candidate>( 
    841808                                        cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
    842                                 // add anonymous member interpretations whenever an aggregate value type is seen
     809                                // add anonymous member interpretations whenever an aggregate value type is seen 
    843810                                // as a member expression
    844811                                addAnonConversions( newCand );
     
    848815
    849816                /// Adds tuple member interpretations
    850                 void addTupleMembers(
    851                         const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
    852                         const Cost & addedCost, const ast::Expr * member
     817                void addTupleMembers( 
     818                        const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 
     819                        const Cost & addedCost, const ast::Expr * member 
    853820                ) {
    854821                        if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
    855                                 // get the value of the constant expression as an int, must be between 0 and the
     822                                // get the value of the constant expression as an int, must be between 0 and the 
    856823                                // length of the tuple to have meaning
    857824                                long long val = constantExpr->intValue();
    858825                                if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
    859826                                        addCandidate(
    860                                                 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
     827                                                cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 
    861828                                                addedCost );
    862829                                }
     
    865832
    866833                void postvisit( const ast::UntypedExpr * untypedExpr ) {
    867                         std::vector< CandidateFinder > argCandidates =
     834                        CandidateFinder funcFinder{ symtab, tenv };
     835                        funcFinder.find( untypedExpr->func, ResolvMode::withAdjustment() );
     836                        // short-circuit if no candidates
     837                        if ( funcFinder.candidates.empty() ) return;
     838
     839                        std::vector< CandidateFinder > argCandidates =
    868840                                selfFinder.findSubExprs( untypedExpr->args );
    869 
     841                       
    870842                        // take care of possible tuple assignments
    871843                        // if not tuple assignment, handled as normal function call
    872844                        Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
    873 
    874                         CandidateFinder funcFinder{ symtab, tenv };
    875                         if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
    876                                 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    877                                 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
    878                                         assertf(!argCandidates.empty(), "special function call without argument");
    879                                         for (auto & firstArgCand: argCandidates[0]) {
    880                                                 ast::ptr<ast::Type> argType = firstArgCand->expr->result;
    881                                                 firstArgCand->env.apply(argType);
    882                                                 // strip references
    883                                                 // xxx - is this correct?
    884                                                 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;
    885 
    886                                                 // convert 1-tuple to plain type
    887                                                 if (auto tuple = argType.as<ast::TupleType>()) {
    888                                                         if (tuple->size() == 1) {
    889                                                                 argType = tuple->types[0];
    890                                                         }
    891                                                 }
    892                                                
    893                                                 // if argType is an unbound type parameter, all special functions need to be searched.
    894                                                 if (isUnboundType(argType)) {
    895                                                         funcFinder.otypeKeys.clear();
    896                                                         break;
    897                                                 }
    898 
    899                                                 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);
    900                                                 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
    901                                         }
    902                                 }
    903                         }
    904                         // if candidates are already produced, do not fail
    905                         // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
    906                         // 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 );
    913                         // short-circuit if no candidates
    914                         // if ( funcFinder.candidates.empty() ) return;
    915 
    916                         reason.code = NoMatch;
    917845
    918846                        // find function operators
     
    949877                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    950878                                                        CandidateRef newFunc{ new Candidate{ *func } };
    951                                                         newFunc->expr =
     879                                                        newFunc->expr = 
    952880                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    953881                                                        makeFunctionCandidates( newFunc, function, argExpansions, found );
    954882                                                }
    955                                         } else if (
    956                                                 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
     883                                        } else if ( 
     884                                                auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 
    957885                                        ) {
    958                                                 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
     886                                                if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
    959887                                                        if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    960888                                                                CandidateRef newFunc{ new Candidate{ *func } };
    961                                                                 newFunc->expr =
     889                                                                newFunc->expr = 
    962890                                                                        referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    963891                                                                makeFunctionCandidates( newFunc, function, argExpansions, found );
     
    973901                                std::vector< ExplodedArg > funcE;
    974902                                funcE.reserve( funcFinder.candidates.size() );
    975                                 for ( const CandidateRef & func : funcFinder ) {
     903                                for ( const CandidateRef & func : funcFinder ) { 
    976904                                        funcE.emplace_back( *func, symtab );
    977905                                }
     
    985913                                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    986914                                                                CandidateRef newOp{ new Candidate{ *op} };
    987                                                                 newOp->expr =
     915                                                                newOp->expr = 
    988916                                                                        referenceToRvalueConversion( newOp->expr, newOp->cost );
    989917                                                                makeFunctionCandidates( newOp, function, argExpansions, found );
     
    994922                        }
    995923
    996                         // Implement SFINAE; resolution errors are only errors if there aren't any non-error
     924                        // Implement SFINAE; resolution errors are only errors if there aren't any non-error 
    997925                        // candidates
    998926                        if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
     
    1006934                                        auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    1007935                                        auto function = pointer->base.strict_as< ast::FunctionType >();
    1008 
     936                                       
    1009937                                        std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
    1010938                                        std::cerr << "parameters are:" << std::endl;
     
    1029957                        promoteCvtCost( winners );
    1030958
    1031                         // function may return a struct/union value, in which case we need to add candidates
    1032                         // for implicit conversions to each of the anonymous members, which must happen after
     959                        // function may return a struct/union value, in which case we need to add candidates 
     960                        // for implicit conversions to each of the anonymous members, which must happen after 
    1033961                        // `findMinCost`, since anon conversions are never the cheapest
    1034962                        for ( const CandidateRef & c : winners ) {
     
    1038966
    1039967                        if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
    1040                                 // If resolution is unsuccessful with a target type, try again without, since it
     968                                // If resolution is unsuccessful with a target type, try again without, since it 
    1041969                                // will sometimes succeed when it wouldn't with a target type binding.
    1042970                                // For example:
     
    1055983                /// true if expression is an lvalue
    1056984                static bool isLvalue( const ast::Expr * x ) {
    1057                         return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
     985                        return x->result && ( x->result->is_lvalue() || x->result.as< ast::ReferenceType >() );
    1058986                }
    1059987
     
    1061989                        CandidateFinder finder{ symtab, tenv };
    1062990                        finder.find( addressExpr->arg );
    1063 
    1064                         if( finder.candidates.empty() ) return;
    1065 
    1066                         reason.code = NoMatch;
    1067 
    1068991                        for ( CandidateRef & r : finder.candidates ) {
    1069992                                if ( ! isLvalue( r->expr ) ) continue;
     
    10801003                        assert( toType );
    10811004                        toType = resolveTypeof( toType, symtab );
    1082                         // toType = SymTab::validateType( castExpr->location, toType, symtab );
     1005                        toType = SymTab::validateType( castExpr->location, toType, symtab );
    10831006                        toType = adjustExprType( toType, tenv, symtab );
    10841007
    10851008                        CandidateFinder finder{ symtab, tenv, toType };
    10861009                        finder.find( castExpr->arg, ResolvMode::withAdjustment() );
    1087 
    1088                         if( !finder.candidates.empty() ) reason.code = NoMatch;
    10891010
    10901011                        CandidateList matches;
     
    10951016                                cand->env.extractOpenVars( open );
    10961017
    1097                                 // It is possible that a cast can throw away some values in a multiply-valued
    1098                                 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
    1099                                 // subexpression results that are cast directly. The candidate is invalid if it
     1018                                // It is possible that a cast can throw away some values in a multiply-valued 
     1019                                // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 
     1020                                // subexpression results that are cast directly. The candidate is invalid if it 
    11001021                                // has fewer results than there are types to cast to.
    11011022                                int discardedValues = cand->expr->result->size() - toType->size();
     
    11041025                                // unification run for side-effects
    11051026                                unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
    1106                                 Cost thisCost =
    1107                                         (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
    1108                             ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
    1109                             : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
    1110 
     1027                                Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env );
    11111028                                PRINT(
    11121029                                        std::cerr << "working on cast with result: " << toType << std::endl;
     
    11201037                                        // count one safe conversion for each value that is thrown away
    11211038                                        thisCost.incSafe( discardedValues );
    1122                                         CandidateRef newCand = std::make_shared<Candidate>(
    1123                                                 restructureCast( cand->expr, toType, castExpr->isGenerated ),
    1124                                                 copy( cand->env ), move( open ), move( need ), cand->cost,
     1039                                        CandidateRef newCand = std::make_shared<Candidate>( 
     1040                                                restructureCast( cand->expr, toType, castExpr->isGenerated ), 
     1041                                                copy( cand->env ), move( open ), move( need ), cand->cost, 
    11251042                                                cand->cost + thisCost );
    11261043                                        inferParameters( newCand, matches );
     
    11401057                        finder.find( castExpr->arg, ResolvMode::withoutPrune() );
    11411058                        for ( CandidateRef & r : finder.candidates ) {
    1142                                 addCandidate(
    1143                                         *r,
     1059                                addCandidate( 
     1060                                        *r, 
    11441061                                        new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
    11451062                        }
    1146                 }
    1147 
    1148                 void postvisit( const ast::KeywordCastExpr * castExpr ) {
    1149                         const auto & loc = castExpr->location;
    1150                         assertf( castExpr->result, "Cast target should have been set in Validate." );
    1151                         auto ref = castExpr->result.strict_as<ast::ReferenceType>();
    1152                         auto inst = ref->base.strict_as<ast::StructInstType>();
    1153                         auto target = inst->base.get();
    1154 
    1155                         CandidateFinder finder{ symtab, tenv };
    1156 
    1157                         auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
    1158                                 for(auto & cand : found) {
    1159                                         const ast::Type * expr = cand->expr->result.get();
    1160                                         if(expect_ref) {
    1161                                                 auto res = dynamic_cast<const ast::ReferenceType*>(expr);
    1162                                                 if(!res) { continue; }
    1163                                                 expr = res->base.get();
    1164                                         }
    1165 
    1166                                         if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
    1167                                                 auto td = cand->env.lookup(*insttype);
    1168                                                 if(!td) { continue; }
    1169                                                 expr = td->bound.get();
    1170                                         }
    1171 
    1172                                         if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
    1173                                                 if(base->base == target) {
    1174                                                         candidates.push_back( std::move(cand) );
    1175                                                         reason.code = NoReason;
    1176                                                 }
    1177                                         }
    1178                                 }
    1179                         };
    1180 
    1181                         try {
    1182                                 // Attempt 1 : turn (thread&)X into ($thread&)X.__thrd
    1183                                 // Clone is purely for memory management
    1184                                 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
    1185 
    1186                                 // don't prune here, since it's guaranteed all alternatives will have the same type
    1187                                 finder.find( tech1.get(), ResolvMode::withoutPrune() );
    1188                                 pick_alternatives(finder.candidates, false);
    1189 
    1190                                 return;
    1191                         } catch(SemanticErrorException & ) {}
    1192 
    1193                         // Fallback : turn (thread&)X into ($thread&)get_thread(X)
    1194                         std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc,  new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };
    1195                         // don't prune here, since it's guaranteed all alternatives will have the same type
    1196                         finder.find( fallback.get(), ResolvMode::withoutPrune() );
    1197 
    1198                         pick_alternatives(finder.candidates, true);
    1199 
    1200                         // Whatever happens here, we have no more fallbacks
    12011063                }
    12021064
     
    12051067                        aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
    12061068                        for ( CandidateRef & agg : aggFinder.candidates ) {
    1207                                 // it's okay for the aggregate expression to have reference type -- cast it to the
     1069                                // it's okay for the aggregate expression to have reference type -- cast it to the 
    12081070                                // base type to treat the aggregate as the referenced value
    12091071                                Cost addedCost = Cost::zero;
     
    12121074                                // find member of the given type
    12131075                                if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
    1214                                         addAggMembers(
     1076                                        addAggMembers( 
    12151077                                                structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    12161078                                } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
    1217                                         addAggMembers(
     1079                                        addAggMembers( 
    12181080                                                unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    12191081                                } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
     
    12281090
    12291091                void postvisit( const ast::NameExpr * nameExpr ) {
    1230                         std::vector< ast::SymbolTable::IdData > declList;
    1231                         if (!selfFinder.otypeKeys.empty()) {
    1232                                 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    1233                                 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());
    1234 
    1235                                 for (auto & otypeKey: selfFinder.otypeKeys) {
    1236                                         auto result = symtab.specialLookupId(kind, otypeKey);
    1237                                         declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
    1238                                 }
    1239                         }
    1240                         else {
    1241                                 declList = symtab.lookupId( nameExpr->name );
    1242                         }
     1092                        std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name );
    12431093                        PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
    1244 
    1245                         if( declList.empty() ) return;
    1246 
    1247                         reason.code = NoMatch;
    1248 
    12491094                        for ( auto & data : declList ) {
    12501095                                Cost cost = Cost::zero;
     
    12521097
    12531098                                CandidateRef newCand = std::make_shared<Candidate>(
    1254                                         newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
     1099                                        newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 
    12551100                                        cost );
    12561101                                PRINT(
     
    12621107                                        std::cerr << std::endl;
    12631108                                )
    1264                                 newCand->expr = ast::mutate_field(
    1265                                         newCand->expr.get(), &ast::Expr::result,
     1109                                newCand->expr = ast::mutate_field( 
     1110                                        newCand->expr.get(), &ast::Expr::result, 
    12661111                                        renameTyVars( newCand->expr->result ) );
    1267                                 // add anonymous member interpretations whenever an aggregate value type is seen
     1112                                // add anonymous member interpretations whenever an aggregate value type is seen 
    12681113                                // as a name expression
    12691114                                addAnonConversions( newCand );
     
    12751120                        // not sufficient to just pass `variableExpr` here, type might have changed since
    12761121                        // creation
    1277                         addCandidate(
     1122                        addCandidate( 
    12781123                                new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
    12791124                }
     
    12851130                void postvisit( const ast::SizeofExpr * sizeofExpr ) {
    12861131                        if ( sizeofExpr->type ) {
    1287                                 addCandidate(
    1288                                         new ast::SizeofExpr{
    1289                                                 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) },
     1132                                addCandidate( 
     1133                                        new ast::SizeofExpr{ 
     1134                                                sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 
    12901135                                        tenv );
    12911136                        } else {
     
    12961141                                CandidateList winners = findMinCost( finder.candidates );
    12971142                                if ( winners.size() != 1 ) {
    1298                                         SemanticError(
     1143                                        SemanticError( 
    12991144                                                sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
    13001145                                }
     
    13091154                void postvisit( const ast::AlignofExpr * alignofExpr ) {
    13101155                        if ( alignofExpr->type ) {
    1311                                 addCandidate(
    1312                                         new ast::AlignofExpr{
    1313                                                 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) },
     1156                                addCandidate( 
     1157                                        new ast::AlignofExpr{ 
     1158                                                alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 
    13141159                                        tenv );
    13151160                        } else {
     
    13201165                                CandidateList winners = findMinCost( finder.candidates );
    13211166                                if ( winners.size() != 1 ) {
    1322                                         SemanticError(
     1167                                        SemanticError( 
    13231168                                                alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
    13241169                                }
     
    13271172                                choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    13281173                                choice->cost = Cost::zero;
    1329                                 addCandidate(
     1174                                addCandidate( 
    13301175                                        *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
    13311176                        }
     
    13331178
    13341179                void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
    1335                         const ast::BaseInstType * aggInst;
     1180                        const ast::ReferenceToType * aggInst;
    13361181                        if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
    13371182                        else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
     
    13401185                        for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
    13411186                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
    1342                                 addCandidate(
     1187                                addCandidate( 
    13431188                                        new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
    13441189                        }
     
    13611206                        finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
    13621207                        if ( finder2.candidates.empty() ) return;
    1363 
    1364                         reason.code = NoMatch;
    13651208
    13661209                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    13751218
    13761219                                        addCandidate(
    1377                                                 new ast::LogicalExpr{
     1220                                                new ast::LogicalExpr{ 
    13781221                                                        logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
    13791222                                                move( env ), move( open ), move( need ), r1->cost + r2->cost );
     
    13971240                        finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    13981241                        if ( finder3.candidates.empty() ) return;
    1399 
    1400                         reason.code = NoMatch;
    14011242
    14021243                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    14151256                                                ast::AssertionSet have;
    14161257
    1417                                                 // unify true and false results, then infer parameters to produce new
     1258                                                // unify true and false results, then infer parameters to produce new 
    14181259                                                // candidates
    14191260                                                ast::ptr< ast::Type > common;
    1420                                                 if (
    1421                                                         unify(
    1422                                                                 r2->expr->result, r3->expr->result, env, need, have, open, symtab,
    1423                                                                 common )
     1261                                                if ( 
     1262                                                        unify( 
     1263                                                                r2->expr->result, r3->expr->result, env, need, have, open, symtab, 
     1264                                                                common ) 
    14241265                                                ) {
    14251266                                                        // generate typed expression
    1426                                                         ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
     1267                                                        ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 
    14271268                                                                conditionalExpr->location, r1->expr, r2->expr, r3->expr };
    14281269                                                        newExpr->result = common ? common : r2->expr->result;
    14291270                                                        // convert both options to result type
    14301271                                                        Cost cost = r1->cost + r2->cost + r3->cost;
    1431                                                         newExpr->arg2 = computeExpressionConversionCost(
     1272                                                        newExpr->arg2 = computeExpressionConversionCost( 
    14321273                                                                newExpr->arg2, newExpr->result, symtab, env, cost );
    14331274                                                        newExpr->arg3 = computeExpressionConversionCost(
     
    14461287                        ast::TypeEnvironment env{ tenv };
    14471288                        ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env );
    1448 
     1289                       
    14491290                        CandidateFinder finder2{ symtab, env };
    14501291                        finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
     
    14761317                        finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
    14771318                        if ( finder2.candidates.empty() ) return;
    1478 
    1479                         reason.code = NoMatch;
    14801319
    14811320                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    14911330
    14921331                                        ast::ptr< ast::Type > common;
    1493                                         if (
    1494                                                 unify(
    1495                                                         r1->expr->result, r2->expr->result, env, need, have, open, symtab,
    1496                                                         common )
     1332                                        if ( 
     1333                                                unify( 
     1334                                                        r1->expr->result, r2->expr->result, env, need, have, open, symtab, 
     1335                                                        common ) 
    14971336                                        ) {
    14981337                                                // generate new expression
    1499                                                 ast::RangeExpr * newExpr =
     1338                                                ast::RangeExpr * newExpr = 
    15001339                                                        new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
    15011340                                                newExpr->result = common ? common : r1->expr->result;
    15021341                                                // add candidate
    15031342                                                CandidateRef newCand = std::make_shared<Candidate>(
    1504                                                         newExpr, move( env ), move( open ), move( need ),
     1343                                                        newExpr, move( env ), move( open ), move( need ), 
    15051344                                                        r1->cost + r2->cost );
    15061345                                                inferParameters( newCand, candidates );
     
    15111350
    15121351                void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
    1513                         std::vector< CandidateFinder > subCandidates =
     1352                        std::vector< CandidateFinder > subCandidates = 
    15141353                                selfFinder.findSubExprs( tupleExpr->exprs );
    15151354                        std::vector< CandidateList > possibilities;
     
    15311370
    15321371                                addCandidate(
    1533                                         new ast::TupleExpr{ tupleExpr->location, move( exprs ) },
     1372                                        new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 
    15341373                                        move( env ), move( open ), move( need ), sumCost( subs ) );
    15351374                        }
     
    15711410                                // calculate target type
    15721411                                const ast::Type * toType = resolveTypeof( initAlt.type, symtab );
    1573                                 // toType = SymTab::validateType( initExpr->location, toType, symtab );
     1412                                toType = SymTab::validateType( initExpr->location, toType, symtab );
    15741413                                toType = adjustExprType( toType, tenv, symtab );
    1575                                 // The call to find must occur inside this loop, otherwise polymorphic return
    1576                                 // types are not bound to the initialization type, since return type variables are
    1577                                 // only open for the duration of resolving the UntypedExpr.
     1414                                // The call to find must occur inside this loop, otherwise polymorphic return 
     1415                                // types are not bound to the initialization type, since return type variables are 
     1416                                // only open for the duration of resolving the UntypedExpr. 
    15781417                                CandidateFinder finder{ symtab, tenv, toType };
    15791418                                finder.find( initExpr->expr, ResolvMode::withAdjustment() );
    15801419                                for ( CandidateRef & cand : finder.candidates ) {
    1581                                         if(reason.code == NotFound) reason.code = NoMatch;
    1582 
    15831420                                        ast::TypeEnvironment env{ cand->env };
    15841421                                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     
    15891426                                        )
    15901427
    1591                                         // It is possible that a cast can throw away some values in a multiply-valued
    1592                                         // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
    1593                                         // the subexpression results that are cast directly. The candidate is invalid
     1428                                        // It is possible that a cast can throw away some values in a multiply-valued 
     1429                                        // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 
     1430                                        // the subexpression results that are cast directly. The candidate is invalid 
    15941431                                        // if it has fewer results than there are types to cast to.
    15951432                                        int discardedValues = cand->expr->result->size() - toType->size();
     
    15971434
    15981435                                        // unification run for side-effects
    1599                                         bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
    1600                                         (void) canUnify;
    1601                                         Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1602                                                 symtab, env );
    1603                                         PRINT(
    1604                                                 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1605                                                         symtab, env );
    1606                                                 std::cerr << "Considering initialization:";
    1607                                                 std::cerr << std::endl << "  FROM: " << cand->expr->result << std::endl;
    1608                                                 std::cerr << std::endl << "  TO: "   << toType             << std::endl;
    1609                                                 std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
    1610                                                 std::cerr << std::endl << "  Legacy cost " << legacyCost;
    1611                                                 std::cerr << std::endl << "  New cost " << thisCost;
    1612                                                 std::cerr << std::endl;
    1613                                         )
     1436                                        unify( toType, cand->expr->result, env, need, have, open, symtab );
     1437                                        Cost thisCost = castCost( cand->expr->result, toType, symtab, env );
     1438                                       
    16141439                                        if ( thisCost != Cost::infinity ) {
    16151440                                                // count one safe conversion for each value that is thrown away
    16161441                                                thisCost.incSafe( discardedValues );
    1617                                                 CandidateRef newCand = std::make_shared<Candidate>(
    1618                                                         new ast::InitExpr{
    1619                                                                 initExpr->location, restructureCast( cand->expr, toType ),
    1620                                                                 initAlt.designation },
    1621                                                         move(env), move( open ), move( need ), cand->cost, thisCost );
     1442                                                CandidateRef newCand = std::make_shared<Candidate>( 
     1443                                                        new ast::InitExpr{ 
     1444                                                                initExpr->location, restructureCast( cand->expr, toType ), 
     1445                                                                initAlt.designation }, 
     1446                                                        copy( cand->env ), move( open ), move( need ), cand->cost, thisCost );
    16221447                                                inferParameters( newCand, matches );
    16231448                                        }
    16241449                                }
    1625 
    16261450                        }
    16271451
     
    16451469        };
    16461470
    1647         // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
    1648         /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
     1471        /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
    16491472        /// return type. Skips ambiguous candidates.
    1650 
    1651 } // anonymous namespace
    1652 
    1653 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {
    1654         struct PruneStruct {
    1655                 CandidateRef candidate;
    1656                 bool ambiguous;
    1657 
    1658                 PruneStruct() = default;
    1659                 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
    1660         };
    1661 
    1662         // find lowest-cost candidate for each type
    1663         std::unordered_map< std::string, PruneStruct > selected;
    1664         // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found
    1665         std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});
    1666         for ( CandidateRef & candidate : candidates ) {
    1667                 std::string mangleName;
    1668                 {
    1669                         ast::ptr< ast::Type > newType = candidate->expr->result;
    1670                         assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
    1671                         candidate->env.apply( newType );
    1672                         mangleName = Mangle::mangle( newType );
    1673                 }
    1674 
    1675                 auto found = selected.find( mangleName );
    1676                 if (found != selected.end() && found->second.candidate->cost < candidate->cost) {
    1677                         PRINT(
    1678                                 std::cerr << "cost " << candidate->cost << " loses to "
    1679                                         << found->second.candidate->cost << std::endl;
    1680                         )
    1681                         continue;
    1682                 }
    1683 
    1684                 // xxx - when do satisfyAssertions produce more than 1 result?
    1685                 // this should only happen when initial result type contains
    1686                 // unbound type parameters, then it should never be pruned by
    1687                 // the previous step, since renameTyVars guarantees the mangled name
    1688                 // is unique.
    1689                 CandidateList satisfied;
    1690                 bool needRecomputeKey = false;
    1691                 if (candidate->need.empty()) {
    1692                         satisfied.emplace_back(candidate);
    1693                 }
    1694                 else {
    1695                         satisfyAssertions(candidate, localSyms, satisfied, errors);
    1696                         needRecomputeKey = true;
    1697                 }
    1698 
    1699                 for (auto & newCand : satisfied) {
    1700                         // recomputes type key, if satisfyAssertions changed it
    1701                         if (needRecomputeKey)
     1473        CandidateList pruneCandidates( CandidateList & candidates ) {
     1474                struct PruneStruct {
     1475                        CandidateRef candidate;
     1476                        bool ambiguous;
     1477
     1478                        PruneStruct() = default;
     1479                        PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
     1480                };
     1481
     1482                // find lowest-cost candidate for each type
     1483                std::unordered_map< std::string, PruneStruct > selected;
     1484                for ( CandidateRef & candidate : candidates ) {
     1485                        std::string mangleName;
    17021486                        {
    1703                                 ast::ptr< ast::Type > newType = newCand->expr->result;
    1704                                 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());
    1705                                 newCand->env.apply( newType );
     1487                                ast::ptr< ast::Type > newType = candidate->expr->result;
     1488                                candidate->env.apply( newType );
    17061489                                mangleName = Mangle::mangle( newType );
    17071490                        }
     1491
    17081492                        auto found = selected.find( mangleName );
    17091493                        if ( found != selected.end() ) {
    1710                                 if ( newCand->cost < found->second.candidate->cost ) {
     1494                                if ( candidate->cost < found->second.candidate->cost ) {
    17111495                                        PRINT(
    1712                                                 std::cerr << "cost " << newCand->cost << " beats "
     1496                                                std::cerr << "cost " << candidate->cost << " beats "
    17131497                                                        << found->second.candidate->cost << std::endl;
    17141498                                        )
    17151499
    1716                                         found->second = PruneStruct{ newCand };
    1717                                 } else if ( newCand->cost == found->second.candidate->cost ) {
    1718                                         // if one of the candidates contains a deleted identifier, can pick the other,
    1719                                         // since deleted expressions should not be ambiguous if there is another option
     1500                                        found->second = PruneStruct{ candidate };
     1501                                } else if ( candidate->cost == found->second.candidate->cost ) {
     1502                                        // if one of the candidates contains a deleted identifier, can pick the other, 
     1503                                        // since deleted expressions should not be ambiguous if there is another option 
    17201504                                        // that is at least as good
    1721                                         if ( findDeletedExpr( newCand->expr ) ) {
     1505                                        if ( findDeletedExpr( candidate->expr ) ) {
    17221506                                                // do nothing
    17231507                                                PRINT( std::cerr << "candidate is deleted" << std::endl; )
    17241508                                        } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
    17251509                                                PRINT( std::cerr << "current is deleted" << std::endl; )
    1726                                                 found->second = PruneStruct{ newCand };
     1510                                                found->second = PruneStruct{ candidate };
    17271511                                        } else {
    17281512                                                PRINT( std::cerr << "marking ambiguous" << std::endl; )
    17291513                                                found->second.ambiguous = true;
    17301514                                        }
    1731                                 } else {
    1732                                         // xxx - can satisfyAssertions increase the cost?
     1515                                } else {
    17331516                                        PRINT(
    1734                                                 std::cerr << "cost " << newCand->cost << " loses to "
     1517                                                std::cerr << "cost " << candidate->cost << " loses to "
    17351518                                                        << found->second.candidate->cost << std::endl;
    1736                                         )       
     1519                                        )
    17371520                                }
    17381521                        } else {
    1739                                 selected.emplace_hint( found, mangleName, newCand );
    1740                         }
    1741                 }
     1522                                selected.emplace_hint( found, mangleName, candidate );
     1523                        }
     1524                }
     1525
     1526                // report unambiguous min-cost candidates
     1527                CandidateList out;
     1528                for ( auto & target : selected ) {
     1529                        if ( target.second.ambiguous ) continue;
     1530
     1531                        CandidateRef cand = target.second.candidate;
     1532                       
     1533                        ast::ptr< ast::Type > newResult = cand->expr->result;
     1534                        cand->env.applyFree( newResult );
     1535                        cand->expr = ast::mutate_field(
     1536                                cand->expr.get(), &ast::Expr::result, move( newResult ) );
     1537                       
     1538                        out.emplace_back( cand );
     1539                }
     1540                return out;
    17421541        }
    17431542
    1744         // report unambiguous min-cost candidates
    1745         // CandidateList out;
    1746         for ( auto & target : selected ) {
    1747                 if ( target.second.ambiguous ) continue;
    1748 
    1749                 CandidateRef cand = target.second.candidate;
    1750 
    1751                 ast::ptr< ast::Type > newResult = cand->expr->result;
    1752                 cand->env.applyFree( newResult );
    1753                 cand->expr = ast::mutate_field(
    1754                         cand->expr.get(), &ast::Expr::result, move( newResult ) );
    1755 
    1756                 out.emplace_back( cand );
    1757         }
    1758         // if everything is lost in satisfyAssertions, report the error
    1759         return !selected.empty();
    1760 }
     1543} // anonymous namespace
    17611544
    17621545void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
     
    17661549
    17671550        if ( mode.failFast && candidates.empty() ) {
    1768                 switch(finder.core.reason.code) {
    1769                 case Finder::NotFound:
    1770                         { SemanticError( expr, "No alternatives for expression " ); break; }
    1771                 case Finder::NoMatch:
    1772                         { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
    1773                 case Finder::ArgsToFew:
    1774                 case Finder::ArgsToMany:
    1775                 case Finder::RetsToFew:
    1776                 case Finder::RetsToMany:
    1777                 case Finder::NoReason:
    1778                 default:
    1779                         { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
    1780                 }
     1551                SemanticError( expr, "No reasonable alternatives for expression " );
    17811552        }
    17821553
    1783         /*
    17841554        if ( mode.satisfyAssns || mode.prune ) {
    17851555                // trim candidates to just those where the assertions are satisfiable
     
    17881558                std::vector< std::string > errors;
    17891559                for ( CandidateRef & candidate : candidates ) {
    1790                         satisfyAssertions( candidate, localSyms, satisfied, errors );
     1560                        satisfyAssertions( candidate, symtab, satisfied, errors );
    17911561                }
    17921562
     
    18041574                candidates = move( satisfied );
    18051575        }
    1806         */
    18071576
    18081577        if ( mode.prune ) {
     
    18131582                )
    18141583
    1815                 CandidateList pruned;
    1816                 std::vector<std::string> errors;
    1817                 bool found = pruneCandidates( candidates, pruned, errors );
    1818 
     1584                CandidateList pruned = pruneCandidates( candidates );
     1585               
    18191586                if ( mode.failFast && pruned.empty() ) {
    18201587                        std::ostringstream stream;
    1821                         if (found) {           
    1822                                 CandidateList winners = findMinCost( candidates );
    1823                                 stream << "Cannot choose between " << winners.size() << " alternatives for "
    1824                                         "expression\n";
    1825                                 ast::print( stream, expr );
    1826                                 stream << " Alternatives are:\n";
    1827                                 print( stream, winners, 1 );
    1828                                 SemanticError( expr->location, stream.str() );
    1829                         }
    1830                         else {
    1831                                 stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    1832                                 for ( const auto& err : errors ) {
    1833                                         stream << err;
    1834                                 }
    1835                                 SemanticError( expr->location, stream.str() );
    1836                         }
     1588                        CandidateList winners = findMinCost( candidates );
     1589                        stream << "Cannot choose between " << winners.size() << " alternatives for "
     1590                                "expression\n";
     1591                        ast::print( stream, expr );
     1592                        stream << " Alternatives are:\n";
     1593                        print( stream, winners, 1 );
     1594                        SemanticError( expr->location, stream.str() );
    18371595                }
    18381596
     
    18441602                )
    18451603                PRINT(
    1846                         std::cerr << "there are " << candidates.size() << " alternatives after elimination"
     1604                        std::cerr << "there are " << candidates.size() << " alternatives after elimination" 
    18471605                                << std::endl;
    18481606                )
    18491607        }
    18501608
    1851         // adjust types after pruning so that types substituted by pruneAlternatives are correctly
     1609        // adjust types after pruning so that types substituted by pruneAlternatives are correctly 
    18521610        // adjusted
    18531611        if ( mode.adjust ) {
    18541612                for ( CandidateRef & r : candidates ) {
    1855                         r->expr = ast::mutate_field(
    1856                                 r->expr.get(), &ast::Expr::result,
    1857                                 adjustExprType( r->expr->result, r->env, localSyms ) );
     1613                        r->expr = ast::mutate_field( 
     1614                                r->expr.get(), &ast::Expr::result, 
     1615                                adjustExprType( r->expr->result, r->env, symtab ) );
    18581616                }
    18591617        }
     
    18671625}
    18681626
    1869 std::vector< CandidateFinder > CandidateFinder::findSubExprs(
    1870         const std::vector< ast::ptr< ast::Expr > > & xs
     1627std::vector< CandidateFinder > CandidateFinder::findSubExprs( 
     1628        const std::vector< ast::ptr< ast::Expr > > & xs 
    18711629) {
    18721630        std::vector< CandidateFinder > out;
    18731631
    18741632        for ( const auto & x : xs ) {
    1875                 out.emplace_back( localSyms, env );
     1633                out.emplace_back( symtab, env );
    18761634                out.back().find( x, ResolvMode::withAdjustment() );
    1877 
     1635               
    18781636                PRINT(
    18791637                        std::cerr << "findSubExprs" << std::endl;
  • src/ResolvExpr/CandidateFinder.hpp

    reef8dfb rbdfc032  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed Jun 5 14:30:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct  1  9:51:00 2019
    13 // Update Count     : 2
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Wed Jun 5 14:30:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    2828struct CandidateFinder {
    2929        CandidateList candidates;          ///< List of candidate resolutions
    30         const ast::SymbolTable & localSyms;   ///< Symbol table to lookup candidates
     30        const ast::SymbolTable & symtab;   ///< Symbol table to lookup candidates
    3131        const ast::TypeEnvironment & env;  ///< Substitutions performed in this resolution
    3232        ast::ptr< ast::Type > targetType;  ///< Target type for resolution
    33         std::set< std::string > otypeKeys;  /// different type may map to same key
    3433
    35         CandidateFinder(
    36                 const ast::SymbolTable & syms, const ast::TypeEnvironment & env,
     34        CandidateFinder( 
     35                const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
    3736                const ast::Type * tt = nullptr )
    38         : candidates(), localSyms( syms ), env( env ), targetType( tt ) {}
     37        : candidates(), symtab( symtab ), env( env ), targetType( tt ) {}
    3938
    4039        /// Fill candidates with feasible resolutions for `expr`
    4140        void find( const ast::Expr * expr, ResolvMode mode = {} );
    42         bool pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors );
    4341
    4442        /// Runs new candidate finder on each element in xs, returning the list of finders
     
    5149        iterator begin() { return candidates.begin(); }
    5250        const_iterator begin() const { return candidates.begin(); }
    53 
     51       
    5452        iterator end() { return candidates.end(); }
    5553        const_iterator end() const { return candidates.end(); }
     
    5755
    5856/// Computes conversion cost between two types
    59 Cost computeConversionCost(
    60         const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
    61         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
     57Cost computeConversionCost( 
     58        const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,
     59        const ast::TypeEnvironment & env );
    6260
    6361} // namespace ResolvExpr
  • src/ResolvExpr/CastCost.cc

    reef8dfb rbdfc032  
    1010// Created On       : Sun May 17 06:57:43 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct  4 15:00:00 2019
    13 // Update Count     : 9
     12// Last Modified On : Thu Aug  8 16:12:00 2019
     13// Update Count     : 8
    1414//
    1515
     
    142142
    143143                CastCost_new(
    144                         const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
     144                        const ast::Type * dst, const ast::SymbolTable & symtab,
    145145                        const ast::TypeEnvironment & env, CostCalculation costFunc )
    146                 : ConversionCost_new( dst, srcIsLvalue, symtab, env, costFunc ) {}
     146                : ConversionCost_new( dst, symtab, env, costFunc ) {}
    147147
    148148                void postvisit( const ast::BasicType * basicType ) {
     
    152152                                cost = Cost::unsafe;
    153153                        } else {
    154                                 cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env );
     154                                cost = conversionCost( basicType, dst, symtab, env );
    155155                        }
    156156                }
     
    165165                                } else {
    166166                                        ast::TypeEnvironment newEnv{ env };
    167                                         if ( auto wParams = pointerType->base.as< ast::FunctionType >() ) {
     167                                        if ( auto wParams = pointerType->base.as< ast::ParameterizedType >() ) {
    168168                                                newEnv.add( wParams->forall );
    169169                                        }
     
    183183                }
    184184        };
    185 
    186         #warning For overload resolution between the two versions.
    187         int localPtrsCastable(const ast::Type * t1, const ast::Type * t2,
    188                         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) {
    189                 return ptrsCastable( t1, t2, symtab, env );
    190         }
    191         Cost localCastCost(
    192                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    193                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    194         ) { return castCost( src, dst, srcIsLvalue, symtab, env ); }
    195185} // anonymous namespace
    196186
    197 
    198 
    199187Cost castCost(
    200         const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    201         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     188        const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     189        const ast::TypeEnvironment & env
    202190) {
    203191        if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    204                 if ( const ast::EqvClass * eqvClass = env.lookup( *typeInst ) ) {
     192                if ( const ast::EqvClass * eqvClass = env.lookup( typeInst->name ) ) {
    205193                        // check cast cost against bound type, if present
    206194                        if ( eqvClass->bound ) {
    207                                 return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env );
     195                                return castCost( src, eqvClass->bound, symtab, env );
    208196                        } else {
    209197                                return Cost::infinity;
     
    213201                        auto type = strict_dynamic_cast< const ast::TypeDecl * >( named );
    214202                        if ( type->base ) {
    215                                 return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
     203                                return castCost( src, type->base, symtab, env ) + Cost::safe;
    216204                        }
    217205                }
     
    236224                #warning cast on ptrsCastable artifact of having two functions, remove when port done
    237225                return convertToReferenceCost(
    238                         src, refType, srcIsLvalue, symtab, env, localPtrsCastable );
     226                        src, refType, symtab, env,
     227                        ( int (*)(
     228                                const ast::Type *, const ast::Type *, const ast::SymbolTable &,
     229                                const ast::TypeEnvironment & )
     230                        ) ptrsCastable );
    239231        } else {
    240232                #warning cast on castCost artifact of having two functions, remove when port done
    241                 ast::Pass< CastCost_new > converter(
    242                         dst, srcIsLvalue, symtab, env, localCastCost );
     233                ast::Pass< CastCost_new > converter{
     234                        dst, symtab, env,
     235                        ( Cost (*)(
     236                                const ast::Type *, const ast::Type *, const ast::SymbolTable &,
     237                                const ast::TypeEnvironment & )
     238                        ) castCost };
    243239                src->accept( converter );
    244                 return converter.core.cost;
     240                return converter.pass.cost;
    245241        }
    246242}
  • src/ResolvExpr/CommonType.cc

    reef8dfb rbdfc032  
    666666                const ast::OpenVarSet & open;
    667667        public:
    668                 static size_t traceId;
    669668                ast::ptr< ast::Type > result;
    670669
     
    713712                        const ast::Type * base = oPtr->base;
    714713                        if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) {
    715                                 auto entry = open.find( *var );
     714                                auto entry = open.find( var->name );
    716715                                if ( entry != open.end() ) {
    717716                                        ast::AssertionSet need, have;
     
    894893        };
    895894
    896         // size_t CommonType_new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new");
    897895        namespace {
    898896                ast::ptr< ast::Type > handleReference(
     
    941939                        ast::ptr< ast::Type > result;
    942940                        const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >();
    943                         const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >();
     941                        const ast::ReferenceType * ref2 = type1.as< ast::ReferenceType >();
    944942
    945943                        if ( depth1 > depth2 ) {
     
    968966                ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open };
    969967                type1->accept( visitor );
    970                 ast::ptr< ast::Type > result = visitor.core.result;
     968                ast::ptr< ast::Type > result = visitor.pass.result;
    971969
    972970                // handling for opaque type declarations (?)
  • src/ResolvExpr/ConversionCost.cc

    reef8dfb rbdfc032  
    1010// Created On       : Sun May 17 07:06:19 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jul 29 16:11:00 2020
    13 // Update Count     : 28
     12// Last Modified On : Mon Aug 12 10:21:00 2019
     13// Update Count     : 27
    1414//
    1515
     
    392392        void ConversionCost::postvisit( const FunctionType * ) {}
    393393
     394        void ConversionCost::postvisit( const StructInstType * inst ) {
     395                if ( const StructInstType * destAsInst = dynamic_cast< const StructInstType * >( dest ) ) {
     396                        if ( inst->name == destAsInst->name ) {
     397                                cost = Cost::zero;
     398                        } // if
     399                } // if
     400        }
     401
     402        void ConversionCost::postvisit( const UnionInstType * inst ) {
     403                if ( const UnionInstType * destAsInst = dynamic_cast< const UnionInstType * >( dest ) ) {
     404                        if ( inst->name == destAsInst->name ) {
     405                                cost = Cost::zero;
     406                        } // if
     407                } // if
     408        }
     409
    394410        void ConversionCost::postvisit( const EnumInstType * ) {
    395411                static Type::Qualifiers q;
     
    481497        }
    482498
    483 namespace {
    484         # warning For overload resolution between the two versions.
    485         int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
    486                         const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
    487                 return ptrsAssignable( t1, t2, env );
    488         }
    489         Cost localConversionCost(
    490                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    491                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    492         ) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); }
    493 }
     499static int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
     500                const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
     501        return ptrsAssignable( t1, t2, env );
     502}
     503
     504// TODO: This is used for overload resolution. It might be able to be dropped once the old system
     505// is removed.
     506static Cost localConversionCost(
     507        const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     508        const ast::TypeEnvironment & env
     509) { return conversionCost( src, dst, symtab, env ); }
    494510
    495511Cost conversionCost(
    496         const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    497         const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     512        const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     513        const ast::TypeEnvironment & env
    498514) {
    499515        if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    500                 if ( const ast::EqvClass * eqv = env.lookup( *inst ) ) {
     516                if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) {
    501517                        if ( eqv->bound ) {
    502                                 return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env );
     518                                return conversionCost(src, eqv->bound, symtab, env );
    503519                        } else {
    504520                                return Cost::infinity;
     
    508524                        assertf( type, "Unexpected typedef." );
    509525                        if ( type->base ) {
    510                                 return conversionCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
     526                                return conversionCost( src, type->base, symtab, env ) + Cost::safe;
    511527                        }
    512528                }
     
    518534        } else if ( const ast::ReferenceType * refType =
    519535                         dynamic_cast< const ast::ReferenceType * >( dst ) ) {
    520                 return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable );
     536                return convertToReferenceCost( src, refType, symtab, env, localPtrsAssignable );
    521537        } else {
    522                 return ast::Pass<ConversionCost_new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost );
    523         }
    524 }
    525 
    526 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     538                ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
     539                src->accept( converter );
     540                return converter.pass.cost;
     541        }
     542}
     543
     544static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst,
    527545                int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
    528                 PtrsCalculation func ) {
     546                NumCostCalculation func ) {
    529547        if ( 0 < diff ) {
    530548                Cost cost = convertToReferenceCost(
    531                         strict_dynamic_cast< const ast::ReferenceType * >( src )->base, dst,
    532                         srcIsLvalue, (diff - 1), symtab, env, func );
     549                        strict_dynamic_cast< const ast::ReferenceType * >( src )->base,
     550                        dst, (diff - 1), symtab, env, func );
    533551                cost.incReference();
    534552                return cost;
     
    536554                Cost cost = convertToReferenceCost(
    537555                        src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base,
    538                         srcIsLvalue, (diff + 1), symtab, env, func );
     556                        (diff + 1), symtab, env, func );
    539557                cost.incReference();
    540558                return cost;
     
    561579                        }
    562580                } else {
    563                         return ast::Pass<ConversionCost_new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost );
     581                        ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
     582                        src->accept( converter );
     583                        return converter.pass.cost;
    564584                }
    565585        } else {
     
    568588                assert( dstAsRef );
    569589                if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) {
    570                         if ( srcIsLvalue ) {
     590                        if ( src->is_lvalue() ) {
    571591                                if ( src->qualifiers == dstAsRef->base->qualifiers ) {
    572592                                        return Cost::reference;
     
    587607
    588608Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst,
    589                 bool srcIsLvalue, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
    590                 PtrsCalculation func ) {
     609            const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
     610                NumCostCalculation func ) {
    591611        int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth();
    592         return convertToReferenceCost( src, dst, srcIsLvalue, sdepth - ddepth, symtab, env, func );
     612        return convertToReferenceCost( src, dst, sdepth - ddepth, symtab, env, func );
    593613}
    594614
     
    647667        assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) );
    648668
    649         cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env );
     669        cost = costCalc( refType->base, dst, symtab, env );
    650670        if ( refType->base->qualifiers == dst->qualifiers ) {
    651671                cost.incReference();
     
    661681}
    662682
     683void ConversionCost_new::postvisit( const ast::StructInstType * structInstType ) {
     684        if ( const ast::StructInstType * dstAsInst =
     685                        dynamic_cast< const ast::StructInstType * >( dst ) ) {
     686                if ( structInstType->name == dstAsInst->name ) {
     687                        cost = Cost::zero;
     688                }
     689        }
     690}
     691
     692void ConversionCost_new::postvisit( const ast::UnionInstType * unionInstType ) {
     693        if ( const ast::UnionInstType * dstAsInst =
     694                        dynamic_cast< const ast::UnionInstType * >( dst ) ) {
     695                if ( unionInstType->name == dstAsInst->name ) {
     696                        cost = Cost::zero;
     697                }
     698        }
     699}
     700
    663701void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) {
    664702        (void)enumInstType;
    665         static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
    666         cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
     703        static const ast::BasicType integer( ast::BasicType::SignedInt );
     704        cost = costCalc( &integer, dst, symtab, env );
    667705        if ( cost < Cost::unsafe ) {
    668706                cost.incSafe();
     
    675713
    676714void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) {
    677         if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) {
    678                 cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env );
     715        if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
     716                cost = costCalc( eqv->bound, dst, symtab, env );
    679717        } else if ( const ast::TypeInstType * dstAsInst =
    680718                        dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    681                 if ( *typeInstType == *dstAsInst ) {
     719                if ( typeInstType->name == dstAsInst->name ) {
    682720                        cost = Cost::zero;
    683721                }
     
    686724                assertf( type, "Unexpected typedef.");
    687725                if ( type->base ) {
    688                         cost = costCalc( type->base, dst, srcIsLvalue, symtab, env ) + Cost::safe;
     726                        cost = costCalc( type->base, dst, symtab, env ) + Cost::safe;
    689727                }
    690728        }
     
    699737                auto dstEnd = dstAsTuple->types.end();
    700738                while ( srcIt != srcEnd && dstIt != dstEnd ) {
    701                         Cost newCost = costCalc( * srcIt++, * dstIt++, srcIsLvalue, symtab, env );
     739                        Cost newCost = costCalc( * srcIt++, * dstIt++, symtab, env );
    702740                        if ( newCost == Cost::infinity ) {
    703741                                return;
     
    734772                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    735773                }
    736         } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
    737                 cost = Cost::zero;
    738                 // +1 for zero_t ->, +1 for disambiguation
    739                 cost.incSafe( maxIntCost + 2 );
    740774        }
    741775}
     
    755789                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    756790                }
    757         }
    758 }
    759 // size_t ConversionCost_new::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
     791        } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
     792                cost = Cost::zero;
     793                cost.incSafe( maxIntCost + 2 );
     794        }
     795}
     796
    760797
    761798} // namespace ResolvExpr
  • src/ResolvExpr/ConversionCost.h

    reef8dfb rbdfc032  
    1010// Created On       : Sun May 17 09:37:28 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jul 29 16:12:00 2020
    13 // Update Count     : 7
     12// Last Modified On : Thu Aug  8 16:13:00 2019
     13// Update Count     : 6
    1414//
    1515
     
    5151                void postvisit( const ReferenceType * refType );
    5252                void postvisit( const FunctionType * functionType );
     53                void postvisit( const StructInstType * aggregateUseType );
     54                void postvisit( const UnionInstType * aggregateUseType );
    5355                void postvisit( const EnumInstType * aggregateUseType );
    5456                void postvisit( const TraitInstType * aggregateUseType );
     
    7274
    7375// Some function pointer types, differ in return type.
    74 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, bool,
     76using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *,
    7577        const ast::SymbolTable &, const ast::TypeEnvironment &)>;
    76 using PtrsCalculation = std::function<int(const ast::Type *, const ast::Type *,
     78using NumCostCalculation = std::function<int(const ast::Type *, const ast::Type *,
    7779        const ast::SymbolTable &, const ast::TypeEnvironment &)>;
    7880
     
    8183protected:
    8284        const ast::Type * dst;
    83         bool srcIsLvalue;
    8485        const ast::SymbolTable & symtab;
    8586        const ast::TypeEnvironment & env;
    8687        CostCalculation costCalc;
    8788public:
    88         static size_t traceId;
    8989        Cost cost;
    90         Cost result() { return cost; }
    9190
    92         ConversionCost_new( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
     91        ConversionCost_new( const ast::Type * dst, const ast::SymbolTable & symtab,
    9392                        const ast::TypeEnvironment & env, CostCalculation costCalc ) :
    94                 dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ),
    95                 costCalc( costCalc ), cost( Cost::infinity )
     93                dst( dst ), symtab( symtab ), env( env ), costCalc( costCalc ), cost( Cost::infinity )
    9694        {}
    9795
     
    104102        void postvisit( const ast::ReferenceType * refType );
    105103        void postvisit( const ast::FunctionType * functionType );
     104        void postvisit( const ast::StructInstType * structInstType );
     105        void postvisit( const ast::UnionInstType * unionInstType );
    106106        void postvisit( const ast::EnumInstType * enumInstType );
    107107        void postvisit( const ast::TraitInstType * traitInstType );
     
    114114
    115115Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest,
    116         bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env,
    117         PtrsCalculation func );
     116        const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, NumCostCalculation func );
    118117
    119118} // namespace ResolvExpr
  • src/ResolvExpr/CurrentObject.cc

    reef8dfb rbdfc032  
    2121#include <string>                      // for string, operator<<, allocator
    2222
    23 #include "AST/Copy.hpp"                // for shallowCopy
    2423#include "AST/Expr.hpp"                // for InitAlternative
    2524#include "AST/GenericSubstitution.hpp" // for genericSubstitution
    2625#include "AST/Init.hpp"                // for Designation
    2726#include "AST/Node.hpp"                // for readonly
    28 #include "AST/Print.hpp"                // for readonly
    2927#include "AST/Type.hpp"
    3028#include "Common/Indenter.h"           // for Indenter, operator<<
     
    594592        class SimpleIterator final : public MemberIterator {
    595593                CodeLocation location;
    596                 const Type * type = nullptr;
     594                readonly< Type > type = nullptr;
    597595        public:
    598596                SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {}
    599597
    600                 void setPosition(
    601                         std::deque< ptr< Expr > >::const_iterator begin,
     598                void setPosition( 
     599                        std::deque< ptr< Expr > >::const_iterator begin, 
    602600                        std::deque< ptr< Expr > >::const_iterator end
    603601                ) override {
     
    630628        class ArrayIterator final : public MemberIterator {
    631629                CodeLocation location;
    632                 const ArrayType * array = nullptr;
    633                 const Type * base = nullptr;
     630                readonly< ArrayType > array = nullptr;
     631                readonly< Type > base = nullptr;
    634632                size_t index = 0;
    635633                size_t size = 0;
     
    639637                        auto res = eval(expr);
    640638                        if ( ! res.second ) {
    641                                 SemanticError( location,
     639                                SemanticError( location, 
    642640                                        toString("Array designator must be a constant expression: ", expr ) );
    643641                        }
     
    646644
    647645        public:
    648                 ArrayIterator( const CodeLocation & loc, const ArrayType * at )
     646                ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 
    649647                : location( loc ), array( at ), base( at->base ) {
    650648                        PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
     
    657655
    658656                void setPosition( const Expr * expr ) {
    659                         // need to permit integer-constant-expressions, including: integer constants,
    660                         // enumeration constants, character constants, sizeof expressions, alignof expressions,
     657                        // need to permit integer-constant-expressions, including: integer constants, 
     658                        // enumeration constants, character constants, sizeof expressions, alignof expressions, 
    661659                        // cast expressions
    662660                        if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     
    664662                                        index = constExpr->intValue();
    665663                                } catch ( SemanticErrorException & ) {
    666                                         SemanticError( expr,
     664                                        SemanticError( expr, 
    667665                                                "Constant expression of non-integral type in array designator: " );
    668666                                }
    669667                        } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
    670668                                setPosition( castExpr->arg );
    671                         } else if (
    672                                 dynamic_cast< const SizeofExpr * >( expr )
    673                                 || dynamic_cast< const AlignofExpr * >( expr )
     669                        } else if ( 
     670                                dynamic_cast< const SizeofExpr * >( expr ) 
     671                                || dynamic_cast< const AlignofExpr * >( expr ) 
    674672                        ) {
    675673                                index = 0;
    676674                        } else {
    677                                 assertf( false,
     675                                assertf( false, 
    678676                                        "bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
    679677                        }
    680678                }
    681679
    682                 void setPosition(
    683                         std::deque< ptr< Expr > >::const_iterator begin,
     680                void setPosition( 
     681                        std::deque< ptr< Expr > >::const_iterator begin, 
    684682                        std::deque< ptr< Expr > >::const_iterator end
    685683                ) override {
     
    760758                }
    761759
    762                 AggregateIterator(
    763                         const CodeLocation & loc, const std::string k, const std::string & n, const Type * i,
     760                AggregateIterator( 
     761                        const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 
    764762                        const MemberList & ms )
    765                 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ),
     763                : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 
    766764                  sub( genericSubstitution( i ) ) {
    767765                        PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
     
    770768
    771769        public:
    772                 void setPosition(
    773                         std::deque< ptr< Expr > >::const_iterator begin,
     770                void setPosition( 
     771                        std::deque< ptr< Expr > >::const_iterator begin, 
    774772                        std::deque< ptr< Expr > >::const_iterator end
    775773                ) final {
     
    788786                                        return;
    789787                                }
    790                                 assertf( false,
     788                                assertf( false, 
    791789                                        "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
    792790                        } else {
    793                                 assertf( false,
     791                                assertf( false, 
    794792                                        "bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
    795793                        }
     
    805803                                                new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
    806804                                        // need to substitute for generic types so that casts are to concrete types
    807                                         alt.type = shallowCopy(alt.type.get());
    808805                                        PRINT( std::cerr << "  type is: " << alt.type; )
    809806                                        sub.apply( alt.type ); // also apply to designation??
     
    845842                                for ( InitAlternative & alt : ret ) {
    846843                                        PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    847                                         alt.designation.get_and_mutate()->designators.emplace_front(
     844                                        alt.designation.get_and_mutate()->designators.emplace_front( 
    848845                                                new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
    849846                                }
     
    900897        class TupleIterator final : public AggregateIterator {
    901898        public:
    902                 TupleIterator( const CodeLocation & loc, const TupleType * inst )
    903                 : AggregateIterator(
    904                         loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members
     899                TupleIterator( const CodeLocation & loc, const TupleType * inst ) 
     900                : AggregateIterator( 
     901                        loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 
    905902                ) {}
    906903
     
    923920
    924921        MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) {
    925                 if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) {
     922                if ( auto aggr = dynamic_cast< const ReferenceToType * >( type ) ) {
    926923                        if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) {
    927924                                return new StructIterator{ loc, sit };
     
    929926                                return new UnionIterator{ loc, uit };
    930927                        } else {
    931                                 assertf(
    932                                         dynamic_cast< const EnumInstType * >( type )
    933                                                 || dynamic_cast< const TypeInstType * >( type ),
    934                                         "Encountered unhandled BaseInstType in createMemberIterator: %s",
     928                                assertf( 
     929                                        dynamic_cast< const EnumInstType * >( aggr )
     930                                                || dynamic_cast< const TypeInstType * >( aggr ),
     931                                        "Encountered unhandled ReferenceToType in createMemberIterator: %s",
    935932                                                toString( type ).c_str() );
    936933                                return new SimpleIterator{ loc, type };
     
    952949                using DesignatorChain = std::deque< ptr< Expr > >;
    953950                PRINT( std::cerr << "___findNext" << std::endl; )
    954 
     951               
    955952                // find all the d's
    956953                std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
     
    965962                                        DesignatorChain & d = *dit;
    966963                                        PRINT( std::cerr << "____actual: " << t << std::endl; )
    967                                         if ( auto refType = dynamic_cast< const BaseInstType * >( t ) ) {
     964                                        if ( auto refType = dynamic_cast< const ReferenceToType * >( t ) ) {
    968965                                                // concatenate identical field names
    969966                                                for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
     
    10161013                // set new designators
    10171014                assertf( ! objStack.empty(), "empty object stack when setting designation" );
    1018                 Designation * actualDesignation =
     1015                Designation * actualDesignation = 
    10191016                        new Designation{ designation->location, DesignatorChain{d} };
    10201017                objStack.back()->setPosition( d ); // destroys d
  • src/ResolvExpr/FindOpenVars.cc

    reef8dfb rbdfc032  
    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

    reef8dfb rbdfc032  
    5858
    5959// TODO: When the old PolyCost is torn out get rid of the _new suffix.
    60 class PolyCost_new {
     60struct PolyCost_new {
     61        int result;
    6162        const ast::SymbolTable &symtab;
    62 public:
    63         int result;
    6463        const ast::TypeEnvironment &env_;
    6564
    66         PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
    67         : symtab( symtab ), result( 0 ), env_( env ) {}
     65        PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :
     66                result( 0 ), symtab( symtab ), env_( env ) {}
    6867
    6968        void previsit( const ast::TypeInstType * type ) {
    70                 if ( const ast::EqvClass * eqv = env_.lookup( *type ) ) /* && */ if ( eqv->bound ) {
     69                if ( const ast::EqvClass * eqv = env_.lookup( type->name ) ) /* && */ if ( eqv->bound ) {
    7170                        if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) {
    7271                                if ( symtab.lookupType( otherType->name ) ) {
     
    8786        ast::Pass<PolyCost_new> costing( symtab, env );
    8887        type->accept( costing );
    89         return costing.core.result;
     88        return costing.pass.result;
    9089}
    9190
  • src/ResolvExpr/PtrsAssignable.cc

    reef8dfb rbdfc032  
    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                }
     
    155155                ast::Pass<PtrsAssignable_new> visitor( dst, env );
    156156                src->accept( visitor );
    157                 return visitor.core.result;
     157                return visitor.pass.result;
    158158        }
    159159
  • src/ResolvExpr/PtrsCastable.cc

    reef8dfb rbdfc032  
    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                }
     
    293293                ast::Pass< PtrsCastable_new > ptrs{ dst, env, symtab };
    294294                src->accept( ptrs );
    295                 return ptrs.core.result;
     295                return ptrs.pass.result;
    296296        }
    297297}
  • src/ResolvExpr/RenameVars.cc

    reef8dfb rbdfc032  
    3030#include "SynTree/Visitor.h"       // for acceptAll, maybeAccept
    3131
    32 #include "AST/Copy.hpp"
    33 
    3432namespace ResolvExpr {
    3533
     
    3836                int level = 0;
    3937                int resetCount = 0;
     38                ScopedMap< std::string, std::string > nameMap;
    4039
    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;
    4540        public:
    4641                void reset() {
     
    4944                }
    5045
     46                using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;
     47
    5148                void rename( TypeInstType * type ) {
    52                         auto it = nameMap.find( type->name );
     49                        mapConstIterator it = nameMap.find( type->name );
    5350                        if ( it != nameMap.end() ) {
    5451                                type->name = it->second;
    5552                        }
    56                 }
    57 
    58                 void nextUsage() {
    59                         ++next_usage_id;
    6053                }
    6154
     
    7265                                        // ditto for assertion names, the next level in
    7366                                        level++;
    74                                 }
    75                         }
     67                                        // acceptAll( td->assertions, *this );
     68                                } // for
     69                        } // if
    7670                }
    7771
     
    8377
    8478                const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
    85                         // 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;
    94                     type = mut;
     79                        mapConstIterator it = nameMap.find( type->name );
     80                        if ( it != nameMap.end() ) {
     81                                ast::TypeInstType * mutType = ast::mutate( type );
     82                                mutType->name = it->second;
     83                    type = mutType;
    9584                        }
    96 
    9785                        return type;
    9886                }
    9987
    100                 const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
    101                         if ( type->forall.empty() ) return type;
    102                         idMap.beginScope();
     88                template<typename NodeT>
     89                const NodeT * openLevel( const NodeT * type ) {
     90                        if ( !type->forall.empty() ) {
     91                                nameMap.beginScope();
     92                                // Load new names from this forall clause and perform renaming.
     93                                NodeT * mutType = ast::mutate( type );
     94                                for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
     95                                        std::ostringstream output;
     96                                        output << "_" << resetCount << "_" << level << "_" << td->name;
     97                                        std::string newname( output.str() );
     98                                        nameMap[ td->name ] = newname;
     99                                        ++level;
    103100
    104                         // 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" );
    110 
    111                                 if (mode == GEN_EXPR_ID) {
    112                                         mut->expr_id = next_expr_id;
    113                                         mut->formal_usage = -1;
    114                                         ++next_expr_id;
     101                                        ast::TypeDecl * decl = ast::mutate( td.get() );
     102                                        decl->name = newname;
     103                                        td = decl;
    115104                                }
    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;
    126105                        }
    127 
    128                         return mutType;
     106                        return type;
    129107                }
    130108
    131                 void closeLevel( const ast::FunctionType * type ) {
    132                         if ( type->forall.empty() ) return;
    133                         idMap.endScope();
     109                template<typename NodeT>
     110                const NodeT * closeLevel( const NodeT * type ) {
     111                        if ( !type->forall.empty() ) {
     112                                nameMap.endScope();
     113                        }
     114                        return type;
    134115                }
    135116        };
     
    138119        RenamingData renaming;
    139120
    140         struct RenameVars_old {
     121        struct RenameVars {
    141122                void previsit( TypeInstType * instType ) {
    142123                        renaming.openLevel( (Type*)instType );
     
    149130                        renaming.closeLevel( type );
    150131                }
    151         };
    152 
    153         struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
    154                 RenameMode mode;
    155132
    156133                const ast::FunctionType * previsit( const ast::FunctionType * type ) {
    157                         return renaming.openLevel( type, mode );
     134                        return renaming.openLevel( type );
    158135                }
    159 
    160                 /*
    161136                const ast::StructInstType * previsit( const ast::StructInstType * type ) {
    162137                        return renaming.openLevel( type );
     
    168143                        return renaming.openLevel( type );
    169144                }
    170                 */
    171 
    172145                const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
    173                         if (mode == GEN_USAGE && !type->formal_usage) return type; // do not rename an actual type
    174                         return renaming.rename( type );
     146                        return renaming.rename( renaming.openLevel( type ) );
    175147                }
    176                 void postvisit( const ast::FunctionType * type ) {
    177                         renaming.closeLevel( type );
     148                const ast::ParameterizedType * postvisit( const ast::ParameterizedType * type ) {
     149                        return renaming.closeLevel( type );
    178150                }
    179151        };
     
    182154
    183155void renameTyVars( Type * t ) {
    184         PassVisitor<RenameVars_old> renamer;
     156        PassVisitor<RenameVars> renamer;
    185157        t->accept( renamer );
    186158}
    187159
    188 const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) {
    189         // ast::Type *tc = ast::deepCopy(t);
    190         ast::Pass<RenameVars_new> renamer;
    191         renamer.core.mode = mode;
    192         if (mode == GEN_USAGE && reset) {
    193                 renaming.nextUsage();
    194         }
     160const ast::Type * renameTyVars( const ast::Type * t ) {
     161        ast::Pass<RenameVars> renamer;
    195162        return t->accept( renamer );
    196163}
     
    198165void resetTyVarRenaming() {
    199166        renaming.reset();
    200         renaming.nextUsage();
    201167}
    202168
  • src/ResolvExpr/RenameVars.h

    reef8dfb rbdfc032  
    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

    reef8dfb rbdfc032  
    2222                const bool prune;            ///< Prune alternatives to min-cost per return type? [true]
    2323                const bool failFast;         ///< Fail on no resulting alternatives? [true]
     24                const bool satisfyAssns;     ///< Satisfy assertions? [false]
    2425
    25                 constexpr ResolvMode(bool a, bool p, bool ff)
    26                 : adjust(a), prune(p), failFast(ff) {}
     26        private:
     27                constexpr ResolvMode(bool a, bool p, bool ff, bool sa)
     28                : adjust(a), prune(p), failFast(ff), satisfyAssns(sa) {}
    2729
     30        public:
    2831                /// Default settings
    29                 constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {}
     32                constexpr ResolvMode() : adjust(false), prune(true), failFast(true), satisfyAssns(false) {}
    3033               
    3134                /// With adjust flag set; turns array and function types into equivalent pointers
    32                 static constexpr ResolvMode withAdjustment() { return { true, true, true }; }
     35                static constexpr ResolvMode withAdjustment() { return { true, true, true, false }; }
    3336
    3437                /// With adjust flag set but prune unset; pruning ensures there is at least one alternative
    3538                /// per result type
    36                 static constexpr ResolvMode withoutPrune() { return { true, false, true }; }
     39                static constexpr ResolvMode withoutPrune() { return { true, false, true, false }; }
    3740
    3841                /// With adjust and prune flags set but failFast unset; failFast ensures there is at least
    3942                /// one resulting alternative
    40                 static constexpr ResolvMode withoutFailFast() { return { true, true, false }; }
     43                static constexpr ResolvMode withoutFailFast() { return { true, true, false, false }; }
    4144
    4245                /// The same mode, but with satisfyAssns turned on; for top-level calls
    43                 ResolvMode atTopLevel() const { return { adjust, true, failFast }; }
     46                ResolvMode atTopLevel() const { return { adjust, prune, failFast, true }; }
    4447        };
    4548} // namespace ResolvExpr
  • src/ResolvExpr/ResolveAssertions.cc

    reef8dfb rbdfc032  
    277277                        const DeclarationWithType * candidate = cdata.id;
    278278
    279                         // ignore deleted candidates.
    280                         // NOTE: this behavior is different from main resolver.
    281                         // further investigations might be needed to determine
    282                         // if we should implement the same rule here
    283                         // (i.e. error if unique best match is deleted)
    284                         if (candidate->isDeleted) continue;
    285 
    286                         // build independent unification context. for candidate
     279                        // build independent unification context for candidate
    287280                        AssertionSet have, newNeed;
    288281                        TypeEnvironment newEnv{ resn.alt.env };
  • src/ResolvExpr/ResolveTypeof.cc

    reef8dfb rbdfc032  
    1515
    1616#include "ResolveTypeof.h"
    17 #include "RenameVars.h"
    1817
    1918#include <cassert>               // for assert
     
    3029#include "SynTree/Mutator.h"     // for Mutator
    3130#include "SynTree/Type.h"        // for TypeofType, Type
    32 #include "SymTab/Mangler.h"
    33 #include "InitTweak/InitTweak.h" // for isConstExpr
    3431
    3532namespace SymTab {
     
    10299                        // replace basetypeof(<enum>) by int
    103100                        if ( dynamic_cast<EnumInstType*>(newType) ) {
    104                                 Type* newerType =
    105                                         new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,
     101                                Type* newerType = 
     102                                        new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 
    106103                                        newType->attributes };
    107104                                delete newType;
    108105                                newType = newerType;
    109106                        }
    110                         newType->get_qualifiers().val
     107                        newType->get_qualifiers().val 
    111108                                = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;
    112109                } else {
    113110                        newType->get_qualifiers().val |= oldQuals;
    114111                }
    115 
     112               
    116113                return newType;
    117114        }
     
    123120                ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {}
    124121
    125                 void previsit( const ast::TypeofType * ) { visit_children = false; }
     122                void premutate( const ast::TypeofType * ) { visit_children = false; }
    126123
    127                 const ast::Type * postvisit( const ast::TypeofType * typeofType ) {
     124                const ast::Type * postmutate( const ast::TypeofType * typeofType ) {
    128125                        // pass on null expression
    129126                        if ( ! typeofType->expr ) return typeofType;
     
    136133                                // typeof wrapping expression
    137134                                ast::TypeEnvironment dummy;
    138                                 ast::ptr< ast::Expr > newExpr =
     135                                ast::ptr< ast::Expr > newExpr = 
    139136                                        resolveInVoidContext( typeofType->expr, localSymtab, dummy );
    140137                                assert( newExpr->result && ! newExpr->result->isVoid() );
     
    146143                                // replace basetypeof(<enum>) by int
    147144                                if ( newType.as< ast::EnumInstType >() ) {
    148                                         newType = new ast::BasicType{
     145                                        newType = new ast::BasicType{ 
    149146                                                ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) };
    150147                                }
    151                                 reset_qualifiers(
    152                                         newType,
     148                                reset_qualifiers( 
     149                                        newType, 
    153150                                        ( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers );
    154151                        } else {
     
    156153                        }
    157154
    158                         return newType.release();
     155                        return newType;
    159156                }
    160157        };
     
    166163}
    167164
    168 struct FixArrayDimension {
    169         // should not require a mutable symbol table - prevent pass template instantiation
    170         const ast::SymbolTable & _symtab;
    171         FixArrayDimension(const ast::SymbolTable & symtab): _symtab(symtab) {}
    172 
    173         const ast::ArrayType * previsit (const ast::ArrayType * arrayType) {
    174                 if (!arrayType->dimension) return arrayType;
    175                 auto mutType = mutate(arrayType);
    176                 ast::ptr<ast::Type> sizetype = ast::sizeType ? ast::sizeType : new ast::BasicType(ast::BasicType::LongUnsignedInt);
    177                 mutType->dimension = findSingleExpression(arrayType->dimension, sizetype, _symtab);
    178 
    179                 if (InitTweak::isConstExpr(mutType->dimension)) {
    180                         mutType->isVarLen = ast::LengthFlag::FixedLen;
    181                 }
    182                 else {
    183                         mutType->isVarLen = ast::LengthFlag::VariableLen;
    184                 }
    185                 return mutType;
    186         }
    187 };
    188 
    189 const ast::Type * fixArrayType( const ast::Type * type, const ast::SymbolTable & symtab) {
    190         ast::Pass<FixArrayDimension> visitor {symtab};
    191         return type->accept(visitor);
    192 }
    193 
    194 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab ) {
    195         if (!decl->isTypeFixed) {
    196                 auto mutDecl = mutate(decl);
    197                 auto resolvedType = resolveTypeof(decl->type, symtab);
    198                 resolvedType = fixArrayType(resolvedType, symtab);
    199                 mutDecl->type = resolvedType;
    200 
    201                 // check variable length if object is an array.
    202                 // xxx - should this be part of fixObjectType?
    203 
    204                 /*
    205                 if (auto arrayType = dynamic_cast<const ast::ArrayType *>(resolvedType)) {
    206                         auto dimExpr = findSingleExpression(arrayType->dimension, ast::sizeType, symtab);
    207                         if (auto varexpr = arrayType->dimension.as<ast::VariableExpr>()) {// hoisted previously
    208                                 if (InitTweak::isConstExpr(varexpr->var.strict_as<ast::ObjectDecl>()->init)) {
    209                                         auto mutType = mutate(arrayType);
    210                                         mutType->isVarLen = ast::LengthFlag::VariableLen;
    211                                         mutDecl->type = mutType;
    212                                 }
    213                         }
    214                 }
    215                 */
    216 
    217 
    218                 if (!mutDecl->name.empty())
    219                         mutDecl->mangleName = Mangle::mangle(mutDecl); // do not mangle unnamed variables
    220                
    221                 mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID);
    222                 mutDecl->isTypeFixed = true;
    223                 return mutDecl;
    224         }
    225         return decl;
    226 }
    227 
    228165} // namespace ResolvExpr
    229166
  • src/ResolvExpr/ResolveTypeof.h

    reef8dfb rbdfc032  
    2323        class Type;
    2424        class SymbolTable;
    25         class ObjectDecl;
    2625}
    2726
     
    2928        Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );
    3029        const ast::Type * resolveTypeof( const ast::Type *, const ast::SymbolTable & );
    31         const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab );
    3230} // namespace ResolvExpr
    3331
  • src/ResolvExpr/Resolver.cc

    reef8dfb rbdfc032  
    99// Author           : Aaron B. Moss
    1010// Created On       : Sun May 17 12:17:01 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Mar 27 11:58:00 2020
    13 // Update Count     : 242
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Wed May 29 11:00:00 2019
     13// Update Count     : 241
    1414//
    1515
     
    2626#include "RenameVars.h"                  // for RenameVars, global_renamer
    2727#include "Resolver.h"
    28 #include "ResolveTypeof.h"
    2928#include "ResolvMode.h"                  // for ResolvMode
    3029#include "typeops.h"                     // for extractResultType
    3130#include "Unify.h"                       // for unify
    32 #include "CompilationState.h"
    3331#include "AST/Chain.hpp"
    3432#include "AST/Decl.hpp"
     
    4038#include "Common/PassVisitor.h"          // for PassVisitor
    4139#include "Common/SemanticError.h"        // for SemanticError
    42 #include "Common/Stats/ResolveTime.h"    // for ResolveTime::start(), ResolveTime::stop()
    4340#include "Common/utility.h"              // for ValueGuard, group_iterate
    4441#include "InitTweak/GenInit.h"
     
    4744#include "SymTab/Autogen.h"              // for SizeType
    4845#include "SymTab/Indexer.h"              // for Indexer
    49 #include "SymTab/Mangler.h"              // for Mangler
    5046#include "SynTree/Declaration.h"         // for ObjectDecl, TypeDecl, Declar...
    5147#include "SynTree/Expression.h"          // for Expression, CastExpr, InitExpr
     
    8884                void previsit( ThrowStmt * throwStmt );
    8985                void previsit( CatchStmt * catchStmt );
    90                 void postvisit( CatchStmt * catchStmt );
    9186                void previsit( WaitForStmt * stmt );
    9287
     
    564559                // TODO: Replace *exception type with &exception type.
    565560                if ( throwStmt->get_expr() ) {
    566                         const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );
     561                        const StructDecl * exception_decl = indexer.lookupStruct( "__cfaabi_ehm__base_exception_t" );
    567562                        assert( exception_decl );
    568563                        Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );
     
    572567
    573568        void Resolver_old::previsit( CatchStmt * catchStmt ) {
    574                 // Until we are very sure this invarent (ifs that move between passes have thenPart)
    575                 // holds, check it. This allows a check for when to decode the mangling.
    576                 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {
    577                         assert( ifStmt->thenPart );
    578                 }
    579                 // Encode the catchStmt so the condition can see the declaration.
    580569                if ( catchStmt->cond ) {
    581                         IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body );
    582                         catchStmt->cond = nullptr;
    583                         catchStmt->body = ifStmt;
    584                 }
    585         }
    586 
    587         void Resolver_old::postvisit( CatchStmt * catchStmt ) {
    588                 // Decode the catchStmt so everything is stored properly.
    589                 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );
    590                 if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) {
    591                         assert( ifStmt->condition );
    592                         assert( ifStmt->elsePart );
    593                         catchStmt->cond = ifStmt->condition;
    594                         catchStmt->body = ifStmt->elsePart;
    595                         ifStmt->condition = nullptr;
    596                         ifStmt->elsePart = nullptr;
    597                         delete ifStmt;
     570                        findSingleExpression( catchStmt->cond, new BasicType( noQualifiers, BasicType::Bool ), indexer );
    598571                }
    599572        }
     
    968941        namespace {
    969942                /// Finds deleted expressions in an expression tree
    970                 struct DeleteFinder_new final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder_new> {
    971                         const ast::DeletedExpr * result = nullptr;
     943                struct DeleteFinder_new final : public ast::WithShortCircuiting {
     944                        const ast::DeletedExpr * delExpr = nullptr;
    972945
    973946                        void previsit( const ast::DeletedExpr * expr ) {
    974                                 if ( result ) { visit_children = false; }
    975                                 else { result = expr; }
    976                         }
    977 
    978                         void previsit( const ast::Expr * expr ) {
    979                                 if ( result ) { visit_children = false; }
    980                                 if (expr->inferred.hasParams()) {
    981                                         for (auto & imp : expr->inferred.inferParams() ) {
    982                                                 imp.second.expr->accept(*visitor);
    983                                         }
    984                                 }
     947                                if ( delExpr ) { visit_children = false; }
     948                                else { delExpr = expr; }
     949                        }
     950
     951                        void previsit( const ast::Expr * ) {
     952                                if ( delExpr ) { visit_children = false; }
    985953                        }
    986954                };
    987955        } // anonymous namespace
     956
    988957        /// Check if this expression is or includes a deleted expression
    989958        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
    990                 return ast::Pass<DeleteFinder_new>::read( expr );
     959                ast::Pass<DeleteFinder_new> finder;
     960                expr->accept( finder );
     961                return finder.pass.delExpr;
    991962        }
    992963
     
    10781049                /// Strips extraneous casts out of an expression
    10791050                struct StripCasts_new final {
    1080                         const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
     1051                        const ast::Expr * postmutate( const ast::CastExpr * castExpr ) {
    10811052                                if (
    1082                                         castExpr->isGenerated == ast::GeneratedCast
     1053                                        castExpr->isGenerated
    10831054                                        && typesCompatible( castExpr->arg->result, castExpr->result )
    10841055                                ) {
     
    11121083                }
    11131084
    1114                
    1115         } // anonymous namespace
    1116 /// Establish post-resolver invariants for expressions
     1085                /// Establish post-resolver invariants for expressions
    11171086                void finishExpr(
    11181087                        ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
     
    11271096                        StripCasts_new::strip( expr );
    11281097                }
     1098        } // anonymous namespace
     1099
    11291100
    11301101        ast::ptr< ast::Expr > resolveInVoidContext(
     
    11341105
    11351106                // set up and resolve expression cast to void
    1136                 ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
     1107                ast::CastExpr * untyped = new ast::CastExpr{ expr };
    11371108                CandidateRef choice = findUnfinishedKindExpression(
    11381109                        untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
     
    11461117        }
    11471118
    1148         /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
     1119        namespace {
     1120                /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
    11491121                /// context.
    11501122                ast::ptr< ast::Expr > findVoidExpression(
    11511123                        const ast::Expr * untyped, const ast::SymbolTable & symtab
    11521124                ) {
     1125                        resetTyVarRenaming();
    11531126                        ast::TypeEnvironment env;
    11541127                        ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, symtab, env );
     
    11561129                        return newExpr;
    11571130                }
    1158 
    1159         namespace {
    1160                
    11611131
    11621132                /// resolve `untyped` to the expression whose candidate satisfies `pred` with the
     
    11701140                        CandidateRef choice =
    11711141                                findUnfinishedKindExpression( untyped, symtab, kind, pred, mode );
    1172                         ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
     1142                        finishExpr( choice->expr, choice->env, untyped->env );
    11731143                        return std::move( choice->expr );
    11741144                }
     
    11781148                        const ast::Expr * untyped, const ast::SymbolTable & symtab
    11791149                ) {
    1180                         Stats::ResolveTime::start( untyped );
    1181                         auto res = findKindExpression( untyped, symtab );
    1182                         Stats::ResolveTime::stop();
    1183                         return res;
     1150                        return findKindExpression( untyped, symtab );
    11841151                }
    11851152        } // anonymous namespace
    11861153
    1187         ast::ptr< ast::Expr > findSingleExpression(
    1188                 const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab
    1189         ) {
    1190                 assert( untyped && type );
    1191                 ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
    1192                 ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
    1193                 removeExtraneousCast( newExpr, symtab );
    1194                 return newExpr;
    1195         }
     1154                ast::ptr< ast::Expr > findSingleExpression(
     1155                        const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab
     1156                ) {
     1157                        assert( untyped && type );
     1158                        ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
     1159                        ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
     1160                        removeExtraneousCast( newExpr, symtab );
     1161                        return newExpr;
     1162                }
    11961163
    11971164        namespace {
    1198                 bool structOrUnion( const Candidate & i ) {
    1199                         const ast::Type * t = i.expr->result->stripReferences();
    1200                         return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t );
    1201                 }
    12021165                /// Predicate for "Candidate has integral type"
    12031166                bool hasIntegralType( const Candidate & i ) {
     
    12351198                template<typename Iter>
    12361199                inline bool nextMutex( Iter & it, const Iter & end ) {
    1237                         while ( it != end && ! (*it)->is_mutex() ) { ++it; }
     1200                        while ( it != end && ! (*it)->get_type()->is_mutex() ) { ++it; }
    12381201                        return it != end;
    12391202                }
     
    12471210                ast::ptr< ast::Type > functionReturn = nullptr;
    12481211                ast::CurrentObject currentObject;
    1249                 // for work previously in GenInit
    1250                 static InitTweak::ManagedTypes_new managedTypes;
    1251 
    12521212                bool inEnumDecl = false;
    12531213
    12541214        public:
    1255                 static size_t traceId;
    12561215                Resolver_new() = default;
    12571216                Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; }
    12581217
    1259                 const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
     1218                void previsit( const ast::FunctionDecl * );
    12601219                const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
    1261                 const ast::ObjectDecl * previsit( const ast::ObjectDecl * );
    1262                 void previsit( const ast::AggregateDecl * );
    1263                 void previsit( const ast::StructDecl * );
     1220                void previsit( const ast::ObjectDecl * );
    12641221                void previsit( const ast::EnumDecl * );
    12651222                const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
     
    12801237                const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
    12811238                const ast::CatchStmt *       previsit( const ast::CatchStmt * );
    1282                 const ast::CatchStmt *       postvisit( const ast::CatchStmt * );
    12831239                const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
    1284                 const ast::WithStmt *        previsit( const ast::WithStmt * );
    12851240
    12861241                const ast::SingleInit *      previsit( const ast::SingleInit * );
    12871242                const ast::ListInit *        previsit( const ast::ListInit * );
    12881243                const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
    1289 
    1290                 void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
    1291 
    1292                 void beginScope() { managedTypes.beginScope(); }
    1293                 void endScope() { managedTypes.endScope(); }
    1294                 bool on_error(ast::ptr<ast::Decl> & decl);
    12951244        };
    1296         // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver");
    1297 
    1298         InitTweak::ManagedTypes_new Resolver_new::managedTypes;
    1299 
    1300         void resolve( ast::TranslationUnit& translationUnit ) {
    1301                 ast::Pass< Resolver_new >::run( translationUnit );
     1245
     1246        void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit ) {
     1247                ast::Pass< Resolver_new > resolver;
     1248                accept_all( translationUnit, resolver );
    13021249        }
    13031250
     
    13101257        }
    13111258
    1312         const ast::Expr * resolveStmtExpr(
     1259        ast::ptr< ast::Expr > resolveStmtExpr(
    13131260                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab
    13141261        ) {
    13151262                assert( stmtExpr );
    13161263                ast::Pass< Resolver_new > resolver{ symtab };
    1317                 auto ret = mutate(stmtExpr->accept(resolver));
    1318                 strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
     1264                ast::ptr< ast::Expr > ret = stmtExpr;
     1265                ret = ret->accept( resolver );
     1266                strict_dynamic_cast< ast::StmtExpr * >( ret.get_and_mutate() )->computeResult();
    13191267                return ret;
    13201268        }
    13211269
    1322         namespace {
    1323                 const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ast::SymbolTable & symtab) {
    1324                         std::string name = attr->normalizedName();
    1325                         if (name == "constructor" || name == "destructor") {
    1326                                 if (attr->params.size() == 1) {
    1327                                         auto arg = attr->params.front();
    1328                                         auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), symtab );
    1329                                         auto result = eval(arg);
    1330 
    1331                                         auto mutAttr = mutate(attr);
    1332                                         mutAttr->params.front() = resolved;
    1333                                         if (! result.second) {
    1334                                                 SemanticWarning(loc, Warning::GccAttributes,
    1335                                                         toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
    1336                                         }
    1337                                         else {
    1338                                                 auto priority = result.first;
    1339                                                 if (priority < 101) {
    1340                                                         SemanticWarning(loc, Warning::GccAttributes,
    1341                                                                 toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
    1342                                                 } else if (priority < 201 && ! buildingLibrary()) {
    1343                                                         SemanticWarning(loc, Warning::GccAttributes,
    1344                                                                 toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
    1345                                                 }
    1346                                         }
    1347                                         return mutAttr;
    1348                                 } else if (attr->params.size() > 1) {
    1349                                         SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
    1350                                 } else {
    1351                                         SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
    1352                                 }
    1353                         }
    1354                         return attr;
    1355                 }
    1356         }
    1357 
    1358         const ast::FunctionDecl * Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) {
     1270        void Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) {
    13591271                GuardValue( functionReturn );
    1360 
    1361                 assert (functionDecl->unique());
    1362                 if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) {
    1363                         SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations");
    1364                 }
    1365 
    1366                 if (!functionDecl->isTypeFixed) {
    1367                         auto mutDecl = mutate(functionDecl);
    1368                         auto mutType = mutDecl->type.get_and_mutate();
    1369 
    1370                         for (auto & attr: mutDecl->attributes) {
    1371                                 attr = handleAttribute(mutDecl->location, attr, symtab);
    1372                         }
    1373 
    1374                         // handle assertions
    1375 
    1376                         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));
    1387                         }
    1388 
    1389                         // temporarily adds params to symbol table.
    1390                         // actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl)
    1391 
    1392                         std::vector<ast::ptr<ast::Type>> paramTypes;
    1393                         std::vector<ast::ptr<ast::Type>> returnTypes;
    1394 
    1395                         for (auto & param : mutDecl->params) {
    1396                                 param = fixObjectType(param.strict_as<ast::ObjectDecl>(), symtab);
    1397                                 symtab.addId(param);
    1398                                 paramTypes.emplace_back(param->get_type());
    1399                         }
    1400                         for (auto & ret : mutDecl->returns) {
    1401                                 ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), symtab);
    1402                                 returnTypes.emplace_back(ret->get_type());
    1403                         }
    1404                         // since function type in decl is just a view of param types, need to update that as well
    1405                         mutType->params = std::move(paramTypes);
    1406                         mutType->returns = std::move(returnTypes);
    1407 
    1408                         auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
    1409 
    1410                         std::list<ast::ptr<ast::Stmt>> newStmts;
    1411                         resolveWithExprs (mutDecl->withExprs, newStmts);
    1412 
    1413                         if (mutDecl->stmts) {
    1414                                 auto mutStmt = mutDecl->stmts.get_and_mutate();
    1415                                 mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts));
    1416                                 mutDecl->stmts = mutStmt;
    1417                         }
    1418 
    1419                         symtab.leaveScope();
    1420 
    1421                         mutDecl->type = renamedType;
    1422                         mutDecl->mangleName = Mangle::mangle(mutDecl);
    1423                         mutDecl->isTypeFixed = true;
    1424                         functionDecl = mutDecl;
    1425                 }
    1426                 managedTypes.handleDWT(functionDecl);
    1427 
    14281272                functionReturn = extractResultType( functionDecl->type );
    1429                 return functionDecl;
    14301273        }
    14311274
     
    14331276                // default value expressions have an environment which shouldn't be there and trips up
    14341277                // later passes.
    1435                 assert( functionDecl->unique() );
    1436                 ast::FunctionType * mutType = mutate( functionDecl->type.get() );
    1437 
    1438                 for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
    1439                         if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
     1278                ast::ptr< ast::FunctionDecl > ret = functionDecl;
     1279                for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) {
     1280                        const ast::ptr<ast::DeclWithType> & d = functionDecl->type->params[i];
     1281
     1282                        if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) {
    14401283                                if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
    14411284                                        if ( init->value->env == nullptr ) continue;
    14421285                                        // clone initializer minus the initializer environment
    1443                                         auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
    1444                                         auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
    1445                                         auto mutValue = mutate( mutInit->value.get() );
    1446 
    1447                                         mutValue->env = nullptr;
    1448                                         mutInit->value = mutValue;
    1449                                         mutParam->init = mutInit;
    1450                                         mutType->params[i] = mutParam;
    1451 
    1452                                         assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
     1286                                        ast::chain_mutate( ret )
     1287                                                ( &ast::FunctionDecl::type )
     1288                                                        ( &ast::FunctionType::params )[i]
     1289                                                                ( &ast::ObjectDecl::init )
     1290                                                                        ( &ast::SingleInit::value )->env = nullptr;
     1291
     1292                                        assert( functionDecl != ret.get() || functionDecl->unique() );
     1293                                        assert( ! ret->type->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env );
    14531294                                }
    14541295                        }
    14551296                }
    1456                 mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
    1457                 return functionDecl;
    1458         }
    1459 
    1460         const ast::ObjectDecl * Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) {
     1297                return ret.get();
     1298        }
     1299
     1300        void Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) {
    14611301                // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
    14621302                // class-variable `initContext` is changed multiple times because the LHS is analyzed
     
    14661306                // selecting the RHS.
    14671307                GuardValue( currentObject );
    1468 
     1308                currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
    14691309                if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
    14701310                        // enumerator initializers should not use the enum type to initialize, since the
    14711311                        // enum type is still incomplete at this point. Use `int` instead.
    1472                         objectDecl = fixObjectType(objectDecl, symtab);
    14731312                        currentObject = ast::CurrentObject{
    14741313                                objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
    14751314                }
    1476                 else {
    1477                         if (!objectDecl->isTypeFixed) {
    1478                                 auto newDecl = fixObjectType(objectDecl, symtab);
    1479                                 auto mutDecl = mutate(newDecl);
    1480 
    1481                                 // generate CtorInit wrapper when necessary.
    1482                                 // in certain cases, fixObjectType is called before reaching
    1483                                 // this object in visitor pass, thus disabling CtorInit codegen.
    1484                                 // this happens on aggregate members and function parameters.
    1485                                 if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) {
    1486                                         // constructed objects cannot be designated
    1487                                         if ( InitTweak::isDesignated( mutDecl->init ) ) SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
    1488                                         // constructed objects should not have initializers nested too deeply
    1489                                         if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
    1490 
    1491                                         mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
    1492                                 }
    1493 
    1494                                 objectDecl = mutDecl;
    1495                         }
    1496                         currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
    1497                 }
    1498 
    1499                 return objectDecl;
    1500         }
    1501 
    1502         void Resolver_new::previsit( const ast::AggregateDecl * _aggDecl ) {
    1503                 auto aggDecl = mutate(_aggDecl);
    1504                 assertf(aggDecl == _aggDecl, "type declarations must be unique");
    1505 
    1506                 for (auto & member: aggDecl->members) {
    1507                         // nested type decls are hoisted already. no need to do anything
    1508                         if (auto obj = member.as<ast::ObjectDecl>()) {
    1509                                 member = fixObjectType(obj, symtab);
    1510                         }
    1511                 }
    1512         }
    1513 
    1514         void Resolver_new::previsit( const ast::StructDecl * structDecl ) {
    1515                 previsit(static_cast<const ast::AggregateDecl *>(structDecl));
    1516                 managedTypes.handleStruct(structDecl);
    15171315        }
    15181316
     
    15201318                // in case we decide to allow nested enums
    15211319                GuardValue( inEnumDecl );
    1522                 inEnumDecl = true;
    1523                 // don't need to fix types for enum fields
    1524         }
    1525 
     1320                inEnumDecl = false;
     1321        }
    15261322
    15271323        const ast::StaticAssertDecl * Resolver_new::previsit(
     
    15361332        const PtrType * handlePtrType( const PtrType * type, const ast::SymbolTable & symtab ) {
    15371333                if ( type->dimension ) {
    1538                         ast::ptr< ast::Type > sizeType = ast::sizeType;
     1334                        #warning should use new equivalent to Validate::SizeType rather than sizeType here
     1335                        ast::ptr< ast::Type > sizeType = new ast::BasicType{ ast::BasicType::LongUnsignedInt };
    15391336                        ast::mutate_field(
    15401337                                type, &PtrType::dimension,
     
    16571454                if ( throwStmt->expr ) {
    16581455                        const ast::StructDecl * exceptionDecl =
    1659                                 symtab.lookupStruct( "__cfaehm_base_exception_t" );
     1456                                symtab.lookupStruct( "__cfaabi_ehm__base_exception_t" );
    16601457                        assert( exceptionDecl );
    16611458                        ast::ptr< ast::Type > exceptType =
     
    16691466
    16701467        const ast::CatchStmt * Resolver_new::previsit( const ast::CatchStmt * catchStmt ) {
    1671                 // Until we are very sure this invarent (ifs that move between passes have thenPart)
    1672                 // holds, check it. This allows a check for when to decode the mangling.
    1673                 if ( auto ifStmt = catchStmt->body.as<ast::IfStmt>() ) {
    1674                         assert( ifStmt->thenPart );
    1675                 }
    1676                 // Encode the catchStmt so the condition can see the declaration.
    16771468                if ( catchStmt->cond ) {
    1678                         ast::CatchStmt * stmt = mutate( catchStmt );
    1679                         stmt->body = new ast::IfStmt( stmt->location, stmt->cond, nullptr, stmt->body );
    1680                         stmt->cond = nullptr;
    1681                         return stmt;
    1682                 }
    1683                 return catchStmt;
    1684         }
    1685 
    1686         const ast::CatchStmt * Resolver_new::postvisit( const ast::CatchStmt * catchStmt ) {
    1687                 // Decode the catchStmt so everything is stored properly.
    1688                 const ast::IfStmt * ifStmt = catchStmt->body.as<ast::IfStmt>();
    1689                 if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) {
    1690                         assert( ifStmt->cond );
    1691                         assert( ifStmt->elsePart );
    1692                         ast::CatchStmt * stmt = ast::mutate( catchStmt );
    1693                         stmt->cond = ifStmt->cond;
    1694                         stmt->body = ifStmt->elsePart;
    1695                         // ifStmt should be implicately deleted here.
    1696                         return stmt;
     1469                        ast::ptr< ast::Type > boolType = new ast::BasicType{ ast::BasicType::Bool };
     1470                        catchStmt = ast::mutate_field(
     1471                                catchStmt, &ast::CatchStmt::cond,
     1472                                findSingleExpression( catchStmt->cond, boolType, symtab ) );
    16971473                }
    16981474                return catchStmt;
     
    18111587                                                                // Check if the argument matches the parameter type in the current
    18121588                                                                // scope
    1813                                                                 // ast::ptr< ast::Type > paramType = (*param)->get_type();
     1589                                                                ast::ptr< ast::Type > paramType = (*param)->get_type();
    18141590                                                                if (
    18151591                                                                        ! unify(
    1816                                                                                 arg->expr->result, *param, resultEnv, need, have, open,
     1592                                                                                arg->expr->result, paramType, resultEnv, need, have, open,
    18171593                                                                                symtab )
    18181594                                                                ) {
     
    18211597                                                                        ss << "candidate function not viable: no known conversion "
    18221598                                                                                "from '";
    1823                                                                         ast::print( ss, *param );
     1599                                                                        ast::print( ss, (*param)->get_type() );
    18241600                                                                        ss << "' to '";
    18251601                                                                        ast::print( ss, arg->expr->result );
     
    19511727        }
    19521728
    1953         const ast::WithStmt * Resolver_new::previsit( const ast::WithStmt * withStmt ) {
    1954                 auto mutStmt = mutate(withStmt);
    1955                 resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
    1956                 return mutStmt;
    1957         }
    1958 
    1959         void Resolver_new::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
    1960                 for (auto & expr : exprs) {
    1961                         // only struct- and union-typed expressions are viable candidates
    1962                         expr = findKindExpression( expr, symtab, structOrUnion, "with expression" );
    1963 
    1964                         // if with expression might be impure, create a temporary so that it is evaluated once
    1965                         if ( Tuples::maybeImpure( expr ) ) {
    1966                                 static UniqueName tmpNamer( "_with_tmp_" );
    1967                                 const CodeLocation loc = expr->location;
    1968                                 auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) );
    1969                                 expr = new ast::VariableExpr( loc, tmp );
    1970                                 stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) );
    1971                                 if ( InitTweak::isConstructable( tmp->type ) ) {
    1972                                         // generate ctor/dtor and resolve them
    1973                                         tmp->init = InitTweak::genCtorInit( loc, tmp );
    1974                                 }
    1975                                 // since tmp is freshly created, this should modify tmp in-place
    1976                                 tmp->accept( *visitor );
    1977                         }
    1978                 }
    1979         }
    19801729
    19811730
     
    20731822        }
    20741823
    2075         // suppress error on autogen functions and mark invalid autogen as deleted.
    2076         bool Resolver_new::on_error(ast::ptr<ast::Decl> & decl) {
    2077                 if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
    2078                         // xxx - can intrinsic gen ever fail?
    2079                         if (functionDecl->linkage == ast::Linkage::AutoGen) {
    2080                                 auto mutDecl = mutate(functionDecl);
    2081                                 mutDecl->isDeleted = true;
    2082                                 mutDecl->stmts = nullptr;
    2083                                 decl = mutDecl;
    2084                                 return false;
    2085                         }
    2086                 }
    2087                 return true;
    2088         }
    2089 
    20901824} // namespace ResolvExpr
    20911825
  • src/ResolvExpr/Resolver.h

    reef8dfb rbdfc032  
    3535        class StmtExpr;
    3636        class SymbolTable;
    37         struct TranslationUnit;
    3837        class Type;
    3938        class TypeEnvironment;
     
    5655
    5756        /// Checks types and binds syntactic constructs to typed representations
    58         void resolve( ast::TranslationUnit& translationUnit );
     57        void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit );
    5958        /// Searches expr and returns the first DeletedExpr found, otherwise nullptr
    6059        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr );
     
    6362        ast::ptr< ast::Expr > resolveInVoidContext(
    6463                const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env );
    65         /// Resolve `untyped` to the single expression whose candidate is the best match for the
     64        /// Resolve `untyped` to the single expression whose candidate is the best match for the 
    6665        /// given type.
    6766        ast::ptr< ast::Expr > findSingleExpression(
    6867                const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab );
    69         ast::ptr< ast::Expr > findVoidExpression(
    70                 const ast::Expr * untyped, const ast::SymbolTable & symtab);
    7168        /// Resolves a constructor init expression
    72         ast::ptr< ast::Init > resolveCtorInit(
     69        ast::ptr< ast::Init > resolveCtorInit( 
    7370                const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab );
    74         /// Resolves a statement expression 
    75         const ast::Expr * resolveStmtExpr(
     71        /// Resolves a statement expression
     72        ast::ptr< ast::Expr > resolveStmtExpr(
    7673                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab );
    7774} // namespace ResolvExpr
  • src/ResolvExpr/SatisfyAssertions.cpp

    reef8dfb rbdfc032  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon Jun 10 17:45:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct  1 13:56:00 2019
    13 // Update Count     : 2
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Mon Jun 10 17:45:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    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;
     
    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
    8383                DeferItem(
    84                         const ast::VariableExpr * d, const ast::AssertionSetValue & i, AssnCandidateList && ms )
    85                 : expr( d ), info( i ), matches( std::move( ms ) ) {}
     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
     
    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        }
     
    144144        /// Binds a single assertion, updating satisfaction state
    145145        void bindAssertion(
    146                 const ast::VariableExpr * expr, const ast::AssertionSetValue & info, CandidateRef & cand,
     146                const ast::DeclWithType * decl, const ast::AssertionSetValue & info, CandidateRef & cand,
    147147                AssnCandidate & match, InferCache & inferred
    148148        ) {
     
    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
     
    167167                // find candidates that unify with the desired type
    168168                AssnCandidateList matches;
    169 
    170                 std::vector<ast::SymbolTable::IdData> candidates;
    171                 auto kind = ast::SymbolTable::getSpecialFunctionKind(assn.first->var->name);
    172                 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
    173                         // prefilter special decls by argument type, if already known
    174                         ast::ptr<ast::Type> thisArgType = assn.first->result.strict_as<ast::PointerType>()->base
    175                                 .strict_as<ast::FunctionType>()->params[0]
    176                                 .strict_as<ast::ReferenceType>()->base;
    177                         sat.cand->env.apply(thisArgType);
    178 
    179                         std::string otypeKey = "";
    180                         if (thisArgType.as<ast::PointerType>()) otypeKey = Mangle::Encoding::pointer;
    181                         else if (!isUnboundType(thisArgType)) otypeKey = Mangle::mangle(thisArgType, Mangle::Type | Mangle::NoGenericParams);
    182 
    183                         candidates = sat.symtab.specialLookupId(kind, otypeKey);
    184                 }
    185                 else {
    186                         candidates = sat.symtab.lookupId(assn.first->var->name);
    187                 }
    188                 for ( const ast::SymbolTable::IdData & cdata : candidates ) {
     169                for ( const ast::SymbolTable::IdData & cdata : sat.symtab.lookupId( assn.first->name ) ) {
    189170                        const ast::DeclWithType * candidate = cdata.id;
    190 
    191                         // ignore deleted candidates.
    192                         // NOTE: this behavior is different from main resolver.
    193                         // further investigations might be needed to determine
    194                         // if we should implement the same rule here
    195                         // (i.e. error if unique best match is deleted)
    196                         if (candidate->isDeleted && candidate->linkage == ast::Linkage::AutoGen) continue;
    197171
    198172                        // build independent unification context for candidate
     
    200174                        ast::TypeEnvironment newEnv{ sat.cand->env };
    201175                        ast::OpenVarSet newOpen{ sat.cand->open };
    202                         ast::ptr< ast::Type > toType = assn.first->result;
     176                        ast::ptr< ast::Type > toType = assn.first->get_type();
    203177                        ast::ptr< ast::Type > adjType =
    204                                 renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ), GEN_USAGE, false );
     178                                renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ) );
    205179
    206180                        // only keep candidates which unify
     
    214188
    215189                                matches.emplace_back(
    216                                         cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
     190                                        cdata, adjType, std::move( newEnv ), std::move( newNeed ), std::move( have ),
    217191                                        std::move( newOpen ), crntResnSlot );
    218192                        }
     
    255229                InferMatcher( InferCache & inferred ) : inferred( inferred ) {}
    256230
    257                 const ast::Expr * postvisit( const ast::Expr * expr ) {
     231                const ast::Expr * postmutate( const ast::Expr * expr ) {
    258232                        // Skip if no slots to find
    259                         if ( !expr->inferred.hasSlots() ) return expr;
    260                         // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
    261                         std::vector<UniqueId> missingSlots;
     233                        if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
     234
    262235                        // find inferred parameters for resolution slots
    263                         ast::InferredParams * newInferred = new ast::InferredParams();
     236                        ast::InferredParams newInferred;
    264237                        for ( UniqueId slot : expr->inferred.resnSlots() ) {
    265238                                // fail if no matching assertions found
    266239                                auto it = inferred.find( slot );
    267240                                if ( it == inferred.end() ) {
    268                                         // std::cerr << "missing assertion " << slot << std::endl;
    269                                         missingSlots.push_back(slot);
    270                                         continue;
     241                                        assert(!"missing assertion");
    271242                                }
    272243
     
    274245                                for ( auto & entry : it->second ) {
    275246                                        // recurse on inferParams of resolved expressions
    276                                         entry.second.expr = postvisit( entry.second.expr );
    277                                         auto res = newInferred->emplace( entry );
     247                                        entry.second.expr = postmutate( entry.second.expr );
     248                                        auto res = newInferred.emplace( entry );
    278249                                        assert( res.second && "all assertions newly placed" );
    279250                                }
     
    281252
    282253                        ast::Expr * ret = mutate( expr );
    283                         ret->inferred.set_inferParams( newInferred );
    284                         if (!missingSlots.empty()) ret->inferred.resnSlots() = missingSlots;
     254                        ret->inferred.set_inferParams( std::move( newInferred ) );
    285255                        return ret;
    286256                }
     
    337307                                        // compute conversion cost from satisfying decl to assertion
    338308                                        cost += computeConversionCost(
    339                                                 assn.match.adjType, assn.expr->result, false, symtab, env );
     309                                                assn.match.adjType, assn.decl->get_type(), symtab, env );
    340310
    341311                                        // mark vars+specialization on function-type assertions
     
    344314                                        if ( ! func ) continue;
    345315
    346                                         for ( const auto & param : func->params ) {
    347                                                 cost.decSpec( specCost( param ) );
     316                                        for ( const ast::DeclWithType * param : func->params ) {
     317                                                cost.decSpec( specCost( param->get_type() ) );
    348318                                        }
    349319
    350320                                        cost.incVar( func->forall.size() );
    351321
    352                                         cost.decSpec( func->assertions.size() );
     322                                        for ( const ast::TypeDecl * td : func->forall ) {
     323                                                cost.decSpec( td->assertions.size() );
     324                                        }
    353325                                }
    354326                        }
     
    385357
    386358        /// Limit to depth of recursion of assertion satisfaction
    387         static const int recursionLimit = 8;
     359        static const int recursionLimit = 7;
    388360        /// Maximum number of simultaneously-deferred assertions to attempt concurrent satisfaction of
    389361        static const int deferLimit = 10;
     
    417389                        if ( it != thresholds.end() && it->second < sat.costs ) goto nextSat;
    418390
    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()) {
     391                        // make initial pass at matching assertions
     392                        for ( auto & assn : sat.need ) {
     393                                // fail early if any assertion is not satisfiable
     394                                if ( ! satisfyAssertion( assn, sat ) ) {
    435395                                        Indenter tabs{ 3 };
    436396                                        std::ostringstream ss;
     
    438398                                        print( ss, *sat.cand, ++tabs );
    439399                                        ss << (tabs-1) << "Could not satisfy assertion:\n";
    440                                         ast::print( ss, next[0].first, tabs );
     400                                        ast::print( ss, assn.first, tabs );
    441401
    442402                                        errors.emplace_back( ss.str() );
    443403                                        goto nextSat;
    444404                                }
    445                                 sat.need = std::move(next);
    446405                        }
    447406
     
    462421                                ss << (tabs-1) << "Too many non-unique satisfying assignments for assertions:\n";
    463422                                for ( const auto & d : sat.deferred ) {
    464                                         ast::print( ss, d.expr, tabs );
     423                                        ast::print( ss, d.decl, tabs );
    465424                                }
    466425
     
    480439                                        ss << (tabs-1) << "No mutually-compatible satisfaction for assertions:\n";
    481440                                        for ( const auto& d : sat.deferred ) {
    482                                                 ast::print( ss, d.expr, tabs );
     441                                                ast::print( ss, d.decl, tabs );
    483442                                        }
    484443
     
    512471                                                nextNewNeed.insert( match.need.begin(), match.need.end() );
    513472
    514                                                 bindAssertion( r.expr, r.info, nextCand, match, nextInferred );
     473                                                bindAssertion( r.decl, r.info, nextCand, match, nextInferred );
    515474                                        }
    516475
  • src/ResolvExpr/SatisfyAssertions.hpp

    reef8dfb rbdfc032  
    2727namespace ResolvExpr {
    2828
    29 /// Recursively satisfies all assertions provided in a candidate
    30 /// returns true if it has been run (candidate has any assertions)
    31 void satisfyAssertions(
    32         CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out,
     29/// Recursively satisfies all assertions provided in a candidate; returns true if succeeds
     30void satisfyAssertions(
     31        CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out,
    3332        std::vector<std::string> & errors );
    3433
  • src/ResolvExpr/SpecCost.cc

    reef8dfb rbdfc032  
    1010// Created On       : Tue Oct 02 15:50:00 2018
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jul  3 11:07:00 2019
    13 // Update Count     : 3
    14 //
    15 
    16 #include <cassert>
     12// Last Modified On : Wed Jun 19 10:43:00 2019
     13// Update Count     : 2
     14//
     15
    1716#include <limits>
    1817#include <list>
     
    130129                        typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
    131130
    132                 #warning Should use a standard maybe_accept
    133                 void maybe_accept( ast::Type const * type ) {
    134                         if ( type ) {
    135                                 auto node = type->accept( *visitor );
    136                                 assert( node == nullptr || node == type );
    137                         }
    138                 }
    139 
    140131                // Update the minimum to the new lowest non-none value.
    141132                template<typename T>
     
    143134                        for ( const auto & node : list ) {
    144135                                count = -1;
    145                                 maybe_accept( mapper( node ) );
     136                                mapper( node )->accept( *visitor );
    146137                                if ( count != -1 && count < minimum ) minimum = count;
    147138                        }
     
    178169                void previsit( const ast::FunctionType * fty ) {
    179170                        int minCount = std::numeric_limits<int>::max();
    180                         updateMinimumPresent( minCount, fty->params, type_deref );
    181                         updateMinimumPresent( minCount, fty->returns, type_deref );
     171                        updateMinimumPresent( minCount, fty->params, decl_type );
     172                        updateMinimumPresent( minCount, fty->returns, decl_type );
    182173                        // Add another level to minCount if set.
    183174                        count = toNoneOrInc( minCount );
     
    217208        }
    218209        ast::Pass<SpecCounter> counter;
    219         type->accept( counter );
    220         return counter.core.get_count();
     210        type->accept( *counter.pass.visitor );
     211        return counter.pass.get_count();
    221212}
    222213
  • src/ResolvExpr/TypeEnvironment.cc

    reef8dfb rbdfc032  
    2020#include <utility>                     // for pair, move
    2121
    22 #include "CompilationState.h"          // for deterministic_output
    2322#include "Common/utility.h"            // for maybeClone
    2423#include "SynTree/Type.h"              // for Type, FunctionType, Type::Fora...
     
    107106
    108107        void EqvClass::print( std::ostream &os, Indenter indent ) const {
    109                 os << "(";
    110                 bool first = true;
    111                 for(const auto & var : vars) {
    112                         if(first) first = false;
    113                         else os << " ";
    114                         if( deterministic_output && isUnboundType(var) ) os << "[unbound]";
    115                         else os << var;
    116                 }
     108                os << "( ";
     109                std::copy( vars.begin(), vars.end(), std::ostream_iterator< std::string >( os, " " ) );
    117110                os << ")";
    118111                if ( type ) {
     
    242235                // check safely bindable
    243236                if ( r.type && occursIn( r.type, s.vars.begin(), s.vars.end(), *this ) ) return false;
    244 
     237               
    245238                // merge classes in
    246239                r.vars.insert( s.vars.begin(), s.vars.end() );
  • src/ResolvExpr/TypeEnvironment.h

    reef8dfb rbdfc032  
    149149                iterator end() const { return env.end(); }
    150150
    151                 auto size() const { return env.size(); }
    152 
    153151          private:
    154152                ClassList env;
  • src/ResolvExpr/Unify.cc

    reef8dfb rbdfc032  
    2525#include <vector>
    2626
    27 #include "AST/Copy.hpp"
    2827#include "AST/Decl.hpp"
    2928#include "AST/Node.hpp"
    3029#include "AST/Pass.hpp"
    31 #include "AST/Print.hpp"
    3230#include "AST/Type.hpp"
    3331#include "AST/TypeEnvironment.hpp"
     
    137135                findOpenVars( newSecond, open, closed, need, have, FirstOpen );
    138136
    139                 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
     137                return unifyExact(
     138                        newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
    140139        }
    141140
     
    149148                newFirst->get_qualifiers() = Type::Qualifiers();
    150149                newSecond->get_qualifiers() = Type::Qualifiers();
    151 
     150///   std::cerr << "first is ";
     151///   first->print( std::cerr );
     152///   std::cerr << std::endl << "second is ";
     153///   second->print( std::cerr );
     154///   std::cerr << std::endl << "newFirst is ";
     155///   newFirst->print( std::cerr );
     156///   std::cerr << std::endl << "newSecond is ";
     157///   newSecond->print( std::cerr );
     158///   std::cerr << std::endl;
    152159                bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    153160                delete newFirst;
     
    163170                ast::AssertionSet need, have;
    164171
    165                 ast::Type * newFirst  = shallowCopy( first  );
    166                 ast::Type * newSecond = shallowCopy( second );
    167                 newFirst ->qualifiers = {};
    168                 newSecond->qualifiers = {};
    169                 ast::ptr< ast::Type > t1_(newFirst );
    170                 ast::ptr< ast::Type > t2_(newSecond);
    171 
    172                 ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
    173                 ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
     172                ast::ptr<ast::Type> newFirst{ first }, newSecond{ second };
     173                env.apply( newFirst );
     174                env.apply( newSecond );
     175                reset_qualifiers( newFirst );
     176                reset_qualifiers( newSecond );
    174177
    175178                return unifyExact(
    176                         subFirst,
    177                         subSecond,
    178                         newEnv, need, have, open, noWiden(), symtab );
     179                        newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
    179180        }
    180181
     
    325326
    326327        void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {
     328///   std::cerr << "assertion set is" << std::endl;
     329///   printAssertionSet( assertions, std::cerr, 8 );
     330///   std::cerr << "looking for ";
     331///   assert->print( std::cerr );
     332///   std::cerr << std::endl;
    327333                AssertionSet::iterator i = assertions.find( assert );
    328334                if ( i != assertions.end() ) {
     335///     std::cerr << "found it!" << std::endl;
    329336                        i->second.isUsed = true;
    330337                } // if
     
    395402
    396403        template< typename Iterator1, typename Iterator2 >
    397         bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
     404        bool unifyDeclList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    398405                auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); };
    399406                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
     
    489496                                        || flatOther->isTtype()
    490497                        ) {
    491                                 if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    492                                         if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
     498                                if ( unifyDeclList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
     499                                        if ( unifyDeclList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    493500
    494501                                                // the original types must be used in mark assertions, since pointer comparisons are used
     
    702709                const ast::SymbolTable & symtab;
    703710        public:
    704                 static size_t traceId;
    705711                bool result;
    706712
     
    767773                /// If this isn't done when satifying ttype assertions, then argument lists can have
    768774                /// different size and structure when they should be compatible.
    769                 struct TtypeExpander_new : public ast::WithShortCircuiting, public ast::PureVisitor {
     775                struct TtypeExpander_new : public ast::WithShortCircuiting {
    770776                        ast::TypeEnvironment & tenv;
    771777
     
    773779
    774780                        const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
    775                                 if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
     781                                if ( const ast::EqvClass * clz = tenv.lookup( typeInst->name ) ) {
    776782                                        // expand ttype parameter into its actual type
    777783                                        if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
     
    784790
    785791                /// returns flattened version of `src`
    786                 static std::vector< ast::ptr< ast::Type > > flattenList(
    787                         const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
     792                static std::vector< ast::ptr< ast::DeclWithType > > flattenList(
     793                        const std::vector< ast::ptr< ast::DeclWithType > > & src, ast::TypeEnvironment & env
    788794                ) {
    789                         std::vector< ast::ptr< ast::Type > > dst;
     795                        std::vector< ast::ptr< ast::DeclWithType > > dst;
    790796                        dst.reserve( src.size() );
    791                         for ( const auto & d : src ) {
     797                        for ( const ast::DeclWithType * d : src ) {
    792798                                ast::Pass<TtypeExpander_new> expander{ env };
    793                                 // TtypeExpander pass is impure (may mutate nodes in place)
    794                                 // need to make nodes shared to prevent accidental mutation
    795                                 ast::ptr<ast::Type> dc = d->accept(expander);
    796                                 auto types = flatten( dc );
     799                                d = d->accept( expander );
     800                                auto types = flatten( d->get_type() );
    797801                                for ( ast::ptr< ast::Type > & t : types ) {
    798802                                        // outermost const, volatile, _Atomic qualifiers in parameters should not play
     
    803807                                        // requirements than a non-mutex function
    804808                                        remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
    805                                         dst.emplace_back( t );
     809                                        dst.emplace_back( new ast::ObjectDecl{ d->location, "", t } );
    806810                                }
    807811                        }
     
    811815                /// Creates a tuple type based on a list of DeclWithType
    812816                template< typename Iter >
    813                 static const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
     817                static ast::ptr< ast::Type > tupleFromDecls( Iter crnt, Iter end ) {
    814818                        std::vector< ast::ptr< ast::Type > > types;
    815819                        while ( crnt != end ) {
    816820                                // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
    817821                                // that this results in a flat tuple
    818                                 flatten( *crnt, types );
     822                                flatten( (*crnt)->get_type(), types );
    819823
    820824                                ++crnt;
    821825                        }
    822826
    823                         return new ast::TupleType{ std::move(types) };
     827                        return { new ast::TupleType{ std::move(types) } };
    824828                }
    825829
    826830                template< typename Iter >
    827                 static bool unifyTypeList(
     831                static bool unifyDeclList(
    828832                        Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
    829833                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     
    831835                ) {
    832836                        while ( crnt1 != end1 && crnt2 != end2 ) {
    833                                 const ast::Type * t1 = *crnt1;
    834                                 const ast::Type * t2 = *crnt2;
     837                                const ast::Type * t1 = (*crnt1)->get_type();
     838                                const ast::Type * t2 = (*crnt2)->get_type();
    835839                                bool isTuple1 = Tuples::isTtype( t1 );
    836840                                bool isTuple2 = Tuples::isTtype( t2 );
     
    840844                                        // combine remainder of list2, then unify
    841845                                        return unifyExact(
    842                                                 t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
     846                                                t1, tupleFromDecls( crnt2, end2 ), env, need, have, open,
    843847                                                noWiden(), symtab );
    844848                                } else if ( ! isTuple1 && isTuple2 ) {
    845849                                        // combine remainder of list1, then unify
    846850                                        return unifyExact(
    847                                                 tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
     851                                                tupleFromDecls( crnt1, end1 ), t2, env, need, have, open,
    848852                                                noWiden(), symtab );
    849853                                }
     
    860864                        if ( crnt1 != end1 ) {
    861865                                // try unifying empty tuple with ttype
    862                                 const ast::Type * t1 = *crnt1;
     866                                const ast::Type * t1 = (*crnt1)->get_type();
    863867                                if ( ! Tuples::isTtype( t1 ) ) return false;
    864868                                return unifyExact(
    865                                         t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
     869                                        t1, tupleFromDecls( crnt2, end2 ), env, need, have, open,
    866870                                        noWiden(), symtab );
    867871                        } else if ( crnt2 != end2 ) {
    868872                                // try unifying empty tuple with ttype
    869                                 const ast::Type * t2 = *crnt2;
     873                                const ast::Type * t2 = (*crnt2)->get_type();
    870874                                if ( ! Tuples::isTtype( t2 ) ) return false;
    871875                                return unifyExact(
    872                                         tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
     876                                        tupleFromDecls( crnt1, end1 ), t2, env, need, have, open,
    873877                                        noWiden(), symtab );
    874878                        }
     
    877881                }
    878882
    879                 static bool unifyTypeList(
    880                         const std::vector< ast::ptr< ast::Type > > & list1,
    881                         const std::vector< ast::ptr< ast::Type > > & list2,
     883                static bool unifyDeclList(
     884                        const std::vector< ast::ptr< ast::DeclWithType > > & list1,
     885                        const std::vector< ast::ptr< ast::DeclWithType > > & list2,
    882886                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    883887                        const ast::OpenVarSet & open, const ast::SymbolTable & symtab
    884888                ) {
    885                         return unifyTypeList(
     889                        return unifyDeclList(
    886890                                list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open,
    887891                                symtab );
    888892                }
    889893
    890                 static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
     894                static void markAssertionSet( ast::AssertionSet & assns, const ast::DeclWithType * assn ) {
    891895                        auto i = assns.find( assn );
    892896                        if ( i != assns.end() ) {
     
    898902                static void markAssertions(
    899903                        ast::AssertionSet & assn1, ast::AssertionSet & assn2,
    900                         const ast::FunctionType * type
     904                        const ast::ParameterizedType * type
    901905                ) {
    902                         for ( auto & assert : type->assertions ) {
    903                                 markAssertionSet( assn1, assert );
    904                                 markAssertionSet( assn2, assert );
     906                        for ( const auto & tyvar : type->forall ) {
     907                                for ( const ast::DeclWithType * assert : tyvar->assertions ) {
     908                                        markAssertionSet( assn1, assert );
     909                                        markAssertionSet( assn2, assert );
     910                                }
    905911                        }
    906912                }
     
    926932                        ) return;
    927933
    928                         if ( ! unifyTypeList( params, params2, tenv, need, have, open, symtab ) ) return;
    929                         if ( ! unifyTypeList(
     934                        if ( ! unifyDeclList( params, params2, tenv, need, have, open, symtab ) ) return;
     935                        if ( ! unifyDeclList(
    930936                                func->returns, func2->returns, tenv, need, have, open, symtab ) ) return;
    931937
     
    937943
    938944        private:
    939                 // Returns: other, cast as XInstType
    940                 // Assigns this->result: whether types are compatible (up to generic parameters)
    941                 template< typename XInstType >
    942                 const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
     945                template< typename RefType >
     946                const RefType * handleRefType( const RefType * inst, const ast::Type * other ) {
    943947                        // check that the other type is compatible and named the same
    944                         auto otherInst = dynamic_cast< const XInstType * >( other );
    945                         this->result = otherInst && inst->name == otherInst->name;
     948                        auto otherInst = dynamic_cast< const RefType * >( other );
     949                        result = otherInst && inst->name == otherInst->name;
    946950                        return otherInst;
    947951                }
     
    964968                }
    965969
    966                 template< typename XInstType >
    967                 void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
     970                template< typename RefType >
     971                void handleGenericRefType( const RefType * inst, const ast::Type * other ) {
    968972                        // check that other type is compatible and named the same
    969                         const XInstType * otherInst = handleRefType( inst, other );
    970                         if ( ! this->result ) return;
     973                        const RefType * inst2 = handleRefType( inst, other );
     974                        if ( ! inst2 ) return;
    971975
    972976                        // check that parameters of types unify, if any
    973977                        const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
    974                         const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
     978                        const std::vector< ast::ptr< ast::Expr > > & params2 = inst2->params;
    975979
    976980                        auto it = params.begin();
     
    10281032
    10291033                void postvisit( const ast::TypeInstType * typeInst ) {
    1030                         assert( open.find( *typeInst ) == open.end() );
     1034                        assert( open.find( typeInst->name ) == open.end() );
    10311035                        handleRefType( typeInst, type2 );
    10321036                }
     
    10341038        private:
    10351039                /// Creates a tuple type based on a list of Type
    1036                 static const ast::Type * tupleFromTypes(
     1040                static ast::ptr< ast::Type > tupleFromTypes(
    10371041                        const std::vector< ast::ptr< ast::Type > > & tys
    10381042                ) {
     
    11101114
    11111115                        ast::Pass<TtypeExpander_new> expander{ tenv };
    1112 
    11131116                        const ast::Type * flat = tuple->accept( expander );
    11141117                        const ast::Type * flat2 = tuple2->accept( expander );
     
    11371140        };
    11381141
    1139         // size_t Unify_new::traceId = Stats::Heap::new_stacktrace_id("Unify_new");
    11401142        bool unify(
    11411143                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     
    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();
     
    11861188                        ast::Pass<Unify_new> comparator{ type2, env, need, have, open, widen, symtab };
    11871189                        type1->accept( comparator );
    1188                         return comparator.core.result;
     1190                        return comparator.pass.result;
    11891191                }
    11901192        }
     
    12001202                // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
    12011203                // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
    1202                 ast::Type * t1 = shallowCopy(type1.get());
    1203                 ast::Type * t2 = shallowCopy(type2.get());
    1204                 t1->qualifiers = {};
    1205                 t2->qualifiers = {};
    1206                 ast::ptr< ast::Type > t1_(t1);
    1207                 ast::ptr< ast::Type > t2_(t2);
     1204                ast::ptr<ast::Type> t1{ type1 }, t2{ type2 };
     1205                reset_qualifiers( t1 );
     1206                reset_qualifiers( t2 );
    12081207
    12091208                if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) {
     1209                        t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
     1210
    12101211                        // if exact unification on unqualified types, try to merge qualifiers
    12111212                        if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
    1212                                 t1->qualifiers = q1 | q2;
    1213                                 common = t1;
     1213                                common = type1;
     1214                                reset_qualifiers( common, q1 | q2 );
    12141215                                return true;
    12151216                        } else {
     
    12181219
    12191220                } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) {
     1221                        t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
     1222
    12201223                        // no exact unification, but common type
    1221                         auto c = shallowCopy(common.get());
    1222                         c->qualifiers = q1 | q2;
    1223                         common = c;
     1224                        reset_qualifiers( common, q1 | q2 );
    12241225                        return true;
    12251226                } else {
     
    12301231        ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
    12311232                if ( func->returns.empty() ) return new ast::VoidType{};
    1232                 if ( func->returns.size() == 1 ) return func->returns[0];
     1233                if ( func->returns.size() == 1 ) return func->returns[0]->get_type();
    12331234
    12341235                std::vector<ast::ptr<ast::Type>> tys;
    1235                 for ( const auto & decl : func->returns ) {
    1236                         tys.emplace_back( decl );
     1236                for ( const ast::DeclWithType * decl : func->returns ) {
     1237                        tys.emplace_back( decl->get_type() );
    12371238                }
    12381239                return new ast::TupleType{ std::move(tys) };
  • src/ResolvExpr/module.mk

    reef8dfb rbdfc032  
    1919      ResolvExpr/Alternative.cc \
    2020      ResolvExpr/AlternativeFinder.cc \
    21       ResolvExpr/AlternativeFinder.h \
    22       ResolvExpr/Alternative.h \
    2321      ResolvExpr/Candidate.cpp \
    2422      ResolvExpr/CandidateFinder.cpp \
    25       ResolvExpr/CandidateFinder.hpp \
    26       ResolvExpr/Candidate.hpp \
    2723      ResolvExpr/CastCost.cc \
    2824      ResolvExpr/CommonType.cc \
    2925      ResolvExpr/ConversionCost.cc \
    30       ResolvExpr/ConversionCost.h \
    31       ResolvExpr/Cost.h \
    3226      ResolvExpr/CurrentObject.cc \
    33       ResolvExpr/CurrentObject.h \
    3427      ResolvExpr/ExplodedActual.cc \
    35       ResolvExpr/ExplodedActual.h \
    3628      ResolvExpr/ExplodedArg.cpp \
    37       ResolvExpr/ExplodedArg.hpp \
    3829      ResolvExpr/FindOpenVars.cc \
    39       ResolvExpr/FindOpenVars.h \
    4030      ResolvExpr/Occurs.cc \
    4131      ResolvExpr/PolyCost.cc \
     
    4333      ResolvExpr/PtrsCastable.cc \
    4434      ResolvExpr/RenameVars.cc \
    45       ResolvExpr/RenameVars.h \
    4635      ResolvExpr/ResolveAssertions.cc \
    47       ResolvExpr/ResolveAssertions.h \
    4836      ResolvExpr/Resolver.cc \
    49       ResolvExpr/Resolver.h \
    5037      ResolvExpr/ResolveTypeof.cc \
    51       ResolvExpr/ResolveTypeof.h \
    52       ResolvExpr/ResolvMode.h \
    5338      ResolvExpr/SatisfyAssertions.cpp \
    54       ResolvExpr/SatisfyAssertions.hpp \
    5539      ResolvExpr/SpecCost.cc \
    5640      ResolvExpr/TypeEnvironment.cc \
    57       ResolvExpr/TypeEnvironment.h \
    58       ResolvExpr/typeops.h \
    59       ResolvExpr/Unify.cc \
    60       ResolvExpr/Unify.h \
    61       ResolvExpr/WidenMode.h
     41      ResolvExpr/Unify.cc
    6242
    63 
    64 SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc ResolvExpr/AlternativePrinter.h
     43SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc
    6544SRCDEMANGLE += $(SRC_RESOLVEXPR)
  • src/ResolvExpr/typeops.h

    reef8dfb rbdfc032  
    1010// Created On       : Sun May 17 07:28:22 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct  1 09:45:00 2019
    13 // Update Count     : 6
     12// Last Modified On : Thu Aug  8 16:36:00 2019
     13// Update Count     : 5
    1414//
    1515
     
    8383                const SymTab::Indexer & indexer, const TypeEnvironment & env );
    8484        Cost castCost(
    85                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    86                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
     85                const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     86                const ast::TypeEnvironment & env );
    8787
    8888        // in ConversionCost.cc
     
    9090                const SymTab::Indexer & indexer, const TypeEnvironment & env );
    9191        Cost conversionCost(
    92                 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    93                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
     92                const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     93                const ast::TypeEnvironment & env );
    9494
    9595        // in AlternativeFinder.cc
  • src/SymTab/Autogen.cc

    reef8dfb rbdfc032  
    3838#include "SynTree/Type.h"          // for FunctionType, Type, TypeInstType
    3939#include "SynTree/Visitor.h"       // for maybeAccept, Visitor, acceptAll
    40 #include "CompilationState.h"
    4140
    4241class Attribute;
     
    234233        }
    235234
    236         // shallow copy the pointer list for return
    237         std::vector<ast::ptr<ast::TypeDecl>> getGenericParams (const ast::Type * t) {
    238                 if (auto structInst = dynamic_cast<const ast::StructInstType*>(t)) {
    239                         return structInst->base->params;
    240                 }
    241                 if (auto unionInst = dynamic_cast<const ast::UnionInstType*>(t)) {
    242                         return unionInst->base->params;
    243                 }
    244                 return {};
    245         }
    246 
    247235        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
    248236        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
     
    256244                ftype->parameters.push_back( dstParam );
    257245                return ftype;
    258         }
    259 
    260         ///
    261         ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic) {
    262                 std::vector<ast::ptr<ast::TypeDecl>> typeParams;
    263                 if (maybePolymorphic) typeParams = getGenericParams(paramType);
    264                 auto dstParam = new ast::ObjectDecl(loc, "_dst", new ast::ReferenceType(paramType), nullptr, {}, ast::Linkage::Cforall);
    265                 return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc));
    266246        }
    267247
     
    347327        void FuncGenerator::resolve( FunctionDecl * dcl ) {
    348328                try {
    349                         if (!useNewAST) // attempt to delay resolver call
    350                                 ResolvExpr::resolveDecl( dcl, indexer );
     329                        ResolvExpr::resolveDecl( dcl, indexer );
    351330                        if ( functionNesting == 0 ) {
    352331                                // forward declare if top-level struct, so that
     
    360339                } catch ( SemanticErrorException & ) {
    361340                        // okay if decl does not resolve - that means the function should not be generated
    362                         // delete dcl;
    363                         delete dcl->statements;
    364                         dcl->statements = nullptr;
    365                         dcl->isDeleted = true;
    366                         definitions.push_back( dcl );
    367                         indexer.addId( dcl );
     341                        delete dcl;
    368342                }
    369343        }
  • src/SymTab/Autogen.h

    reef8dfb rbdfc032  
    2121
    2222#include "AST/Decl.hpp"
    23 #include "AST/Eval.hpp"
    2423#include "AST/Expr.hpp"
    2524#include "AST/Init.hpp"
     
    5554        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
    5655        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true );
    57 
    58         ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true);
    5956
    6057        /// generate the type of a copy constructor for paramType.
     
    167164                fExpr->args.emplace_back( dstParam );
    168165
    169                 ast::ptr<ast::Stmt> listInit = srcParam.buildListInit( fExpr );
     166                const ast::Stmt * listInit = srcParam.buildListInit( fExpr );
    170167
    171168                // fetch next set of arguments
     
    268265                }
    269266
    270                 ast::ptr< ast::Expr > begin, end;
    271                 std::string cmp, update;
     267                ast::ptr< ast::Expr > begin, end, cmp, update;
    272268
    273269                if ( forward ) {
     
    275271                        begin = ast::ConstantExpr::from_int( loc, 0 );
    276272                        end = array->dimension;
    277                         cmp = "?<?";
    278                         update = "++?";
     273                        cmp = new ast::NameExpr{ loc, "?<?" };
     274                        update = new ast::NameExpr{ loc, "++?" };
    279275                } else {
    280276                        // generate: for ( int i = N-1; i >= 0; --i )
    281                         begin = ast::call(
    282                                 loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) );
     277                        begin = new ast::UntypedExpr{
     278                                loc, new ast::NameExpr{ loc, "?-?" },
     279                                { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } };
    283280                        end = ast::ConstantExpr::from_int( loc, 0 );
    284                         cmp = "?>=?";
    285                         update = "--?";
     281                        cmp = new ast::NameExpr{ loc, "?>=?" };
     282                        update = new ast::NameExpr{ loc, "--?" };
    286283                }
    287284
     
    289286                        loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt },
    290287                        new ast::SingleInit{ loc, begin } };
    291                 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
    292                
    293                 ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end );
    294                
    295                 ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar );
    296                
    297                 ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar );
     288               
     289                ast::ptr< ast::Expr > cond = new ast::UntypedExpr{
     290                        loc, cmp, { new ast::VariableExpr{ loc, index }, end } };
     291               
     292                ast::ptr< ast::Expr > inc = new ast::UntypedExpr{
     293                        loc, update, { new ast::VariableExpr{ loc, index } } };
     294               
     295                ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{
     296                        loc, new ast::NameExpr{ loc, "?[?]" },
     297                        { dstParam, new ast::VariableExpr{ loc, index } } };
    298298               
    299299                // srcParam must keep track of the array indices to build the source parameter and/or
    300300                // array list initializer
    301                 srcParam.addArrayIndex( indexVar, array->dimension );
     301                srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension );
    302302
    303303                // for stmt's body, eventually containing call
     
    385385                if ( isUnnamedBitfield( obj ) ) return {};
    386386
    387                 ast::ptr< ast::Type > addCast;
     387                ast::ptr< ast::Type > addCast = nullptr;
    388388                if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
    389389                        assert( dstParam->result );
  • src/SymTab/Demangle.cc

    reef8dfb rbdfc032  
    1010// Created On       : Thu Jul 19 12:52:41 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 11 15:09:18 2020
    13 // Update Count     : 10
     12// Last Modified On : Fri Dec 13 14:54:15 2019
     13// Update Count     : 4
    1414//
    1515
     
    1919#include "CodeGen/GenType.h"
    2020#include "Common/PassVisitor.h"
    21 #include "Common/utility.h"                                                             // isPrefix
    2221#include "Mangler.h"
    2322#include "SynTree/Type.h"
     
    417416
    418417                        bool StringView::isPrefix(const std::string & pref) {
    419                                 // if ( pref.size() > str.size()-idx ) return false;
    420                                 // auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );
    421                                 // if (its.first == pref.end()) {
    422                                 //      idx += pref.size();
    423                                 //      return true;
    424                                 // }
    425 
    426                                 // This update is untested because there are no tests for this code.
    427                                 if ( ::isPrefix( str, pref, idx ) ) {
     418                                if ( pref.size() > str.size()-idx ) return false;
     419                                auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );
     420                                if (its.first == pref.end()) {
    428421                                        idx += pref.size();
    429422                                        return true;
     
    436429                                PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
    437430                                if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
    438                                 if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false;
     431                                if (! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back())) return false;
    439432
    440433                                // get name
  • src/SymTab/FixFunction.cc

    reef8dfb rbdfc032  
    106106                bool isVoid = false;
    107107
    108                 void previsit( const ast::FunctionDecl * ) { visit_children = false; }
     108                void premutate( const ast::FunctionDecl * ) { visit_children = false; }
    109109
    110                 const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) {
     110                const ast::DeclWithType * postmutate( const ast::FunctionDecl * func ) {
    111111                        return new ast::ObjectDecl{
    112112                                func->location, func->name, new ast::PointerType{ func->type }, nullptr,
     
    114114                }
    115115
    116                 void previsit( const ast::ArrayType * ) { visit_children = false; }
     116                void premutate( const ast::ArrayType * ) { visit_children = false; }
    117117
    118                 const ast::Type * postvisit( const ast::ArrayType * array ) {
     118                const ast::Type * postmutate( const ast::ArrayType * array ) {
    119119                        return new ast::PointerType{
    120120                                array->base, array->dimension, array->isVarLen, array->isStatic,
     
    122122                }
    123123
    124                 void previsit( const ast::VoidType * ) { isVoid = true; }
     124                void premutate( const ast::VoidType * ) { isVoid = true; }
    125125
    126                 void previsit( const ast::BasicType * ) { visit_children = false; }
    127                 void previsit( const ast::PointerType * ) { visit_children = false; }
    128                 void previsit( const ast::StructInstType * ) { visit_children = false; }
    129                 void previsit( const ast::UnionInstType * ) { visit_children = false; }
    130                 void previsit( const ast::EnumInstType * ) { visit_children = false; }
    131                 void previsit( const ast::TraitInstType * ) { visit_children = false; }
    132                 void previsit( const ast::TypeInstType * ) { visit_children = false; }
    133                 void previsit( const ast::TupleType * ) { visit_children = false; }
    134                 void previsit( const ast::VarArgsType * ) { visit_children = false; }
    135                 void previsit( const ast::ZeroType * ) { visit_children = false; }
    136                 void previsit( const ast::OneType * ) { visit_children = false; }
     126                void premutate( const ast::BasicType * ) { visit_children = false; }
     127                void premutate( const ast::PointerType * ) { visit_children = false; }
     128                void premutate( const ast::StructInstType * ) { visit_children = false; }
     129                void premutate( const ast::UnionInstType * ) { visit_children = false; }
     130                void premutate( const ast::EnumInstType * ) { visit_children = false; }
     131                void premutate( const ast::TraitInstType * ) { visit_children = false; }
     132                void premutate( const ast::TypeInstType * ) { visit_children = false; }
     133                void premutate( const ast::TupleType * ) { visit_children = false; }
     134                void premutate( const ast::VarArgsType * ) { visit_children = false; }
     135                void premutate( const ast::ZeroType * ) { visit_children = false; }
     136                void premutate( const ast::OneType * ) { visit_children = false; }
    137137        };
    138138} // anonymous namespace
     
    141141        ast::Pass< FixFunction_new > fixer;
    142142        dwt = dwt->accept( fixer );
    143         isVoid |= fixer.core.isVoid;
     143        isVoid |= fixer.pass.isVoid;
    144144        return dwt;
    145145}
  • src/SymTab/Mangler.cc

    reef8dfb rbdfc032  
    1010// Created On       : Sun May 17 21:40:29 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Nov 18 12:01:38 2020
    13 // Update Count     : 64
     12// Last Modified On : Fri Dec 13 23:43:49 2019
     13// Update Count     : 28
    1414//
    1515#include "Mangler.h"
     
    6565                                void postvisit( const QualifiedType * qualType );
    6666
    67                                 std::string get_mangleName() { return mangleName; }
     67                                std::string get_mangleName() { return mangleName.str(); }
    6868                          private:
    69                                 std::string mangleName;         ///< Mangled name being constructed
     69                                std::ostringstream mangleName;  ///< Mangled name being constructed
    7070                                typedef std::map< std::string, std::pair< int, int > > VarMapType;
    7171                                VarMapType varNums;             ///< Map of type variables to indices
     
    127127                                        isTopLevel = false;
    128128                                } // if
    129                                 mangleName += Encoding::manglePrefix;
    130                                 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() );
    131                                 if ( opInfo ) {
    132                                         mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
     129                                mangleName << Encoding::manglePrefix;
     130                                CodeGen::OperatorInfo opInfo;
     131                                if ( operatorLookup( declaration->get_name(), opInfo ) ) {
     132                                        mangleName << opInfo.outputName.size() << opInfo.outputName;
    133133                                } else {
    134                                         mangleName += std::to_string( declaration->name.size() ) + declaration->name;
     134                                        mangleName << declaration->name.size() << declaration->name;
    135135                                } // if
    136136                                maybeAccept( declaration->get_type(), *visitor );
     
    139139                                        // so they need a different name mangling
    140140                                        if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {
    141                                                 mangleName += Encoding::autogen;
     141                                                mangleName << Encoding::autogen;
    142142                                        } else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
    143                                                 mangleName += Encoding::intrinsic;
     143                                                mangleName << Encoding::intrinsic;
    144144                                        } else {
    145145                                                // if we add another kind of overridable function, this has to change
     
    160160                        void Mangler_old::postvisit( const VoidType * voidType ) {
    161161                                printQualifiers( voidType );
    162                                 mangleName += Encoding::void_t;
     162                                mangleName << Encoding::void_t;
    163163                        }
    164164
     
    166166                                printQualifiers( basicType );
    167167                                assertf( basicType->kind < BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
    168                                 mangleName += Encoding::basicTypes[ basicType->kind ];
     168                                mangleName << Encoding::basicTypes[ basicType->kind ];
    169169                        }
    170170
     
    172172                                printQualifiers( pointerType );
    173173                                // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers
    174                                 if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName += Encoding::pointer;
     174                                if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName << Encoding::pointer;
    175175                                maybeAccept( pointerType->base, *visitor );
    176176                        }
     
    179179                                // TODO: encode dimension
    180180                                printQualifiers( arrayType );
    181                                 mangleName += Encoding::array + "0";
     181                                mangleName << Encoding::array << "0";
    182182                                maybeAccept( arrayType->base, *visitor );
    183183                        }
     
    204204                        void Mangler_old::postvisit( const FunctionType * functionType ) {
    205205                                printQualifiers( functionType );
    206                                 mangleName += Encoding::function;
     206                                mangleName << Encoding::function;
    207207                                // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
    208208                                // since qualifiers on outermost parameter type do not differentiate function types, e.g.,
     
    211211                                inFunctionType = true;
    212212                                std::list< Type* > returnTypes = getTypes( functionType->returnVals );
    213                                 if (returnTypes.empty()) mangleName += Encoding::void_t;
     213                                if (returnTypes.empty()) mangleName << Encoding::void_t;
    214214                                else acceptAll( returnTypes, *visitor );
    215                                 mangleName += "_";
     215                                mangleName << "_";
    216216                                std::list< Type* > paramTypes = getTypes( functionType->parameters );
    217217                                acceptAll( paramTypes, *visitor );
    218                                 mangleName += "_";
     218                                mangleName << "_";
    219219                        }
    220220
     
    222222                                printQualifiers( refType );
    223223
    224                                 mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
     224                                mangleName << prefix << refType->name.length() << refType->name;
    225225
    226226                                if ( mangleGenericParams ) {
    227227                                        const std::list< Expression* > & params = refType->parameters;
    228228                                        if ( ! params.empty() ) {
    229                                                 mangleName += "_";
     229                                                mangleName << "_";
    230230                                                for ( const Expression * param : params ) {
    231231                                                        const TypeExpr * paramType = dynamic_cast< const TypeExpr * >( param );
     
    233233                                                        maybeAccept( paramType->type, *visitor );
    234234                                                }
    235                                                 mangleName += "_";
     235                                                mangleName << "_";
    236236                                        }
    237237                                }
     
    262262                                        // are first found and prefixing with the appropriate encoding for the type class.
    263263                                        assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
    264                                         mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
     264                                        mangleName << Encoding::typeVariables[varNum->second.second] << varNum->second.first;
    265265                                } // if
    266266                        }
     
    268268                        void Mangler_old::postvisit( const TraitInstType * inst ) {
    269269                                printQualifiers( inst );
    270                                 mangleName += std::to_string( inst->name.size() ) + inst->name;
     270                                mangleName << inst->name.size() << inst->name;
    271271                        }
    272272
    273273                        void Mangler_old::postvisit( const TupleType * tupleType ) {
    274274                                printQualifiers( tupleType );
    275                                 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
     275                                mangleName << Encoding::tuple << tupleType->types.size();
    276276                                acceptAll( tupleType->types, *visitor );
    277277                        }
     
    280280                                printQualifiers( varArgsType );
    281281                                static const std::string vargs = "__builtin_va_list";
    282                                 mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
     282                                mangleName << Encoding::type << vargs.size() << vargs;
    283283                        }
    284284
    285285                        void Mangler_old::postvisit( const ZeroType * ) {
    286                                 mangleName += Encoding::zero;
     286                                mangleName << Encoding::zero;
    287287                        }
    288288
    289289                        void Mangler_old::postvisit( const OneType * ) {
    290                                 mangleName += Encoding::one;
     290                                mangleName << Encoding::one;
    291291                        }
    292292
     
    296296                                        // N marks the start of a qualified type
    297297                                        inQualifiedType = true;
    298                                         mangleName += Encoding::qualifiedTypeStart;
     298                                        mangleName << Encoding::qualifiedTypeStart;
    299299                                }
    300300                                maybeAccept( qualType->parent, *visitor );
     
    303303                                        // E marks the end of a qualified type
    304304                                        inQualifiedType = false;
    305                                         mangleName += Encoding::qualifiedTypeEnd;
     305                                        mangleName << Encoding::qualifiedTypeEnd;
    306306                                }
    307307                        }
     
    315315                                assertf(false, "Mangler_old should not visit typedecl: %s", toCString(decl));
    316316                                assertf( decl->kind < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
    317                                 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
     317                                mangleName << Encoding::typeVariables[ decl->kind ] << ( decl->name.length() ) << decl->name;
    318318                        }
    319319
     
    330330                                        std::list< std::string > assertionNames;
    331331                                        int dcount = 0, fcount = 0, vcount = 0, acount = 0;
    332                                         mangleName += Encoding::forall;
     332                                        mangleName << Encoding::forall;
    333333                                        for ( const TypeDecl * i : type->forall ) {
    334334                                                switch ( i->kind ) {
     
    354354                                                } // for
    355355                                        } // for
    356                                         mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
    357                                         for(const auto & a : assertionNames) mangleName += a;
    358 //                                      std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
    359                                         mangleName += "_";
     356                                        mangleName << dcount << "_" << fcount << "_" << vcount << "_" << acount << "_";
     357                                        std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
     358                                        mangleName << "_";
    360359                                } // if
    361360                                if ( ! inFunctionType ) {
    362361                                        // these qualifiers do not distinguish the outermost type of a function parameter
    363362                                        if ( type->get_const() ) {
    364                                                 mangleName += Encoding::qualifiers.at(Type::Const);
     363                                                mangleName << Encoding::qualifiers.at(Type::Const);
    365364                                        } // if
    366365                                        if ( type->get_volatile() ) {
    367                                                 mangleName += Encoding::qualifiers.at(Type::Volatile);
     366                                                mangleName << Encoding::qualifiers.at(Type::Volatile);
    368367                                        } // if
    369368                                        // Removed due to restrict not affecting function compatibility in GCC
    370369                                        // if ( type->get_isRestrict() ) {
    371                                         //      mangleName += "E";
     370                                        //      mangleName << "E";
    372371                                        // } // if
    373372                                        if ( type->get_atomic() ) {
    374                                                 mangleName += Encoding::qualifiers.at(Type::Atomic);
     373                                                mangleName << Encoding::qualifiers.at(Type::Atomic);
    375374                                        } // if
    376375                                }
    377376                                if ( type->get_mutex() ) {
    378                                         mangleName += Encoding::qualifiers.at(Type::Mutex);
     377                                        mangleName << Encoding::qualifiers.at(Type::Mutex);
    379378                                } // if
    380379                                if ( inFunctionType ) {
     
    384383                                }
    385384                        }
    386                 } // namespace
     385                }       // namespace
    387386        } // namespace Mangler
    388387} // namespace SymTab
     
    418417                        void postvisit( const ast::QualifiedType * qualType );
    419418
    420                         std::string get_mangleName() { return mangleName; }
     419                        std::string get_mangleName() { return mangleName.str(); }
    421420                  private:
    422                         std::string mangleName;         ///< Mangled name being constructed
     421                        std::ostringstream mangleName;  ///< Mangled name being constructed
    423422                        typedef std::map< std::string, std::pair< int, int > > VarMapType;
    424423                        VarMapType varNums;             ///< Map of type variables to indices
     
    438437                  private:
    439438                        void mangleDecl( const ast::DeclWithType *declaration );
    440                         void mangleRef( const ast::BaseInstType *refType, std::string prefix );
     439                        void mangleRef( const ast::ReferenceToType *refType, std::string prefix );
    441440
    442441                        void printQualifiers( const ast::Type *type );
     
    448447                ast::Pass<Mangler_new> mangler( mode );
    449448                maybeAccept( decl, mangler );
    450                 return mangler.core.get_mangleName();
     449                return mangler.pass.get_mangleName();
    451450        }
    452451
     
    471470                                isTopLevel = false;
    472471                        } // if
    473                         mangleName += Encoding::manglePrefix;
    474                         const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( decl->name );
    475                         if ( opInfo ) {
    476                                 mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
     472                        mangleName << Encoding::manglePrefix;
     473                        CodeGen::OperatorInfo opInfo;
     474                        if ( operatorLookup( decl->name, opInfo ) ) {
     475                                mangleName << opInfo.outputName.size() << opInfo.outputName;
    477476                        } else {
    478                                 mangleName += std::to_string( decl->name.size() ) + decl->name;
     477                                mangleName << decl->name.size() << decl->name;
    479478                        } // if
    480479                        maybeAccept( decl->get_type(), *visitor );
     
    483482                                // so they need a different name mangling
    484483                                if ( decl->linkage == ast::Linkage::AutoGen ) {
    485                                         mangleName += Encoding::autogen;
     484                                        mangleName << Encoding::autogen;
    486485                                } else if ( decl->linkage == ast::Linkage::Intrinsic ) {
    487                                         mangleName += Encoding::intrinsic;
     486                                        mangleName << Encoding::intrinsic;
    488487                                } else {
    489488                                        // if we add another kind of overridable function, this has to change
     
    504503                void Mangler_new::postvisit( const ast::VoidType * voidType ) {
    505504                        printQualifiers( voidType );
    506                         mangleName += Encoding::void_t;
     505                        mangleName << Encoding::void_t;
    507506                }
    508507
     
    510509                        printQualifiers( basicType );
    511510                        assertf( basicType->kind < ast::BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
    512                         mangleName += Encoding::basicTypes[ basicType->kind ];
     511                        mangleName << Encoding::basicTypes[ basicType->kind ];
    513512                }
    514513
     
    516515                        printQualifiers( pointerType );
    517516                        // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers
    518                         if ( ! pointerType->base.as<ast::FunctionType>() ) mangleName += Encoding::pointer;
     517                        if ( ! pointerType->base.as<ast::FunctionType>() ) mangleName << Encoding::pointer;
    519518                        maybe_accept( pointerType->base.get(), *visitor );
    520519                }
     
    523522                        // TODO: encode dimension
    524523                        printQualifiers( arrayType );
    525                         mangleName += Encoding::array + "0";
     524                        mangleName << Encoding::array << "0";
    526525                        maybeAccept( arrayType->base.get(), *visitor );
    527526                }
     
    546545                void Mangler_new::postvisit( const ast::FunctionType * functionType ) {
    547546                        printQualifiers( functionType );
    548                         mangleName += Encoding::function;
     547                        mangleName << Encoding::function;
    549548                        // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
    550549                        // since qualifiers on outermost parameter type do not differentiate function types, e.g.,
     
    552551                        GuardValue( inFunctionType );
    553552                        inFunctionType = true;
    554                         if (functionType->returns.empty()) mangleName += Encoding::void_t;
    555                         else accept_each( functionType->returns, *visitor );
    556                         mangleName += "_";
    557                         accept_each( functionType->params, *visitor );
    558                         mangleName += "_";
    559                 }
    560 
    561                 void Mangler_new::mangleRef( const ast::BaseInstType * refType, std::string prefix ) {
     553                        std::vector< ast::ptr< ast::Type > > returnTypes = getTypes( functionType->returns );
     554                        if (returnTypes.empty()) mangleName << Encoding::void_t;
     555                        else accept_each( returnTypes, *visitor );
     556                        mangleName << "_";
     557                        std::vector< ast::ptr< ast::Type > > paramTypes = getTypes( functionType->params );
     558                        accept_each( paramTypes, *visitor );
     559                        mangleName << "_";
     560                }
     561
     562                void Mangler_new::mangleRef( const ast::ReferenceToType * refType, std::string prefix ) {
    562563                        printQualifiers( refType );
    563564
    564                         mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
     565                        mangleName << prefix << refType->name.length() << refType->name;
    565566
    566567                        if ( mangleGenericParams ) {
    567568                                if ( ! refType->params.empty() ) {
    568                                         mangleName += "_";
     569                                        mangleName << "_";
    569570                                        for ( const ast::Expr * param : refType->params ) {
    570571                                                auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
     
    572573                                                maybeAccept( paramType->type.get(), *visitor );
    573574                                        }
    574                                         mangleName += "_";
     575                                        mangleName << "_";
    575576                                }
    576577                        }
     
    601602                                // are first found and prefixing with the appropriate encoding for the type class.
    602603                                assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
    603                                 mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
     604                                mangleName << Encoding::typeVariables[varNum->second.second] << varNum->second.first;
    604605                        } // if
    605606                }
     
    607608                void Mangler_new::postvisit( const ast::TraitInstType * inst ) {
    608609                        printQualifiers( inst );
    609                         mangleName += std::to_string( inst->name.size() ) + inst->name;
     610                        mangleName << inst->name.size() << inst->name;
    610611                }
    611612
    612613                void Mangler_new::postvisit( const ast::TupleType * tupleType ) {
    613614                        printQualifiers( tupleType );
    614                         mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
     615                        mangleName << Encoding::tuple << tupleType->types.size();
    615616                        accept_each( tupleType->types, *visitor );
    616617                }
     
    619620                        printQualifiers( varArgsType );
    620621                        static const std::string vargs = "__builtin_va_list";
    621                         mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
     622                        mangleName << Encoding::type << vargs.size() << vargs;
    622623                }
    623624
    624625                void Mangler_new::postvisit( const ast::ZeroType * ) {
    625                         mangleName += Encoding::zero;
     626                        mangleName << Encoding::zero;
    626627                }
    627628
    628629                void Mangler_new::postvisit( const ast::OneType * ) {
    629                         mangleName += Encoding::one;
     630                        mangleName << Encoding::one;
    630631                }
    631632
     
    635636                                // N marks the start of a qualified type
    636637                                inQualifiedType = true;
    637                                 mangleName += Encoding::qualifiedTypeStart;
     638                                mangleName << Encoding::qualifiedTypeStart;
    638639                        }
    639640                        maybeAccept( qualType->parent.get(), *visitor );
     
    642643                                // E marks the end of a qualified type
    643644                                inQualifiedType = false;
    644                                 mangleName += Encoding::qualifiedTypeEnd;
     645                                mangleName << Encoding::qualifiedTypeEnd;
    645646                        }
    646647                }
     
    654655                        assertf(false, "Mangler_new should not visit typedecl: %s", toCString(decl));
    655656                        assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
    656                         mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
     657                        mangleName << Encoding::typeVariables[ decl->kind ] << ( decl->name.length() ) << decl->name;
    657658                }
    658659
     
    666667                        // skip if not including qualifiers
    667668                        if ( typeMode ) return;
    668                         if ( auto ptype = dynamic_cast< const ast::FunctionType * >(type) ) {
     669                        if ( auto ptype = dynamic_cast< const ast::ParameterizedType * >(type) ) {
    669670                                if ( ! ptype->forall.empty() ) {
    670671                                        std::list< std::string > assertionNames;
    671672                                        int dcount = 0, fcount = 0, vcount = 0, acount = 0;
    672                                         mangleName += Encoding::forall;
    673                                         for ( auto & decl : ptype->forall ) {
     673                                        mangleName << Encoding::forall;
     674                                        for ( const ast::TypeDecl * decl : ptype->forall ) {
    674675                                                switch ( decl->kind ) {
    675676                                                case ast::TypeDecl::Kind::Dtype:
     
    686687                                                } // switch
    687688                                                varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
     689                                                for ( const ast::DeclWithType * assert : decl->assertions ) {
     690                                                        ast::Pass<Mangler_new> sub_mangler(
     691                                                                mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
     692                                                        assert->accept( sub_mangler );
     693                                                        assertionNames.push_back( sub_mangler.pass.get_mangleName() );
     694                                                        acount++;
     695                                                } // for
    688696                                        } // 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++;
    695                                         } // for
    696                                         mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
    697                                         for(const auto & a : assertionNames) mangleName += a;
    698 //                                      std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
    699                                         mangleName += "_";
     697                                        mangleName << dcount << "_" << fcount << "_" << vcount << "_" << acount << "_";
     698                                        std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
     699                                        mangleName << "_";
    700700                                } // if
    701701                        } // if
     
    703703                                // these qualifiers do not distinguish the outermost type of a function parameter
    704704                                if ( type->is_const() ) {
    705                                         mangleName += Encoding::qualifiers.at(Type::Const);
     705                                        mangleName << Encoding::qualifiers.at(Type::Const);
    706706                                } // if
    707707                                if ( type->is_volatile() ) {
    708                                         mangleName += Encoding::qualifiers.at(Type::Volatile);
     708                                        mangleName << Encoding::qualifiers.at(Type::Volatile);
    709709                                } // if
    710710                                // Removed due to restrict not affecting function compatibility in GCC
    711711                                // if ( type->get_isRestrict() ) {
    712                                 //      mangleName += "E";
     712                                //      mangleName << "E";
    713713                                // } // if
    714714                                if ( type->is_atomic() ) {
    715                                         mangleName += Encoding::qualifiers.at(Type::Atomic);
     715                                        mangleName << Encoding::qualifiers.at(Type::Atomic);
    716716                                } // if
    717717                        }
    718718                        if ( type->is_mutex() ) {
    719                                 mangleName += Encoding::qualifiers.at(Type::Mutex);
     719                                mangleName << Encoding::qualifiers.at(Type::Mutex);
    720720                        } // if
    721721                        if ( inFunctionType ) {
  • src/SymTab/Validate.cc

    reef8dfb rbdfc032  
    6464#include "Common/UniqueName.h"         // for UniqueName
    6565#include "Common/utility.h"            // for operator+, cloneAll, deleteAll
    66 #include "CompilationState.h"          // skip some passes in new-ast build
    6766#include "Concurrency/Keywords.h"      // for applyKeywords
    6867#include "FixFunction.h"               // for FixFunction
     
    271270        };
    272271
    273         struct InitializerLength {
     272        struct ArrayLength : public WithIndexer {
    274273                /// for array types without an explicit length, compute the length and store it so that it
    275274                /// is known to the rest of the phases. For example,
     
    282281
    283282                void previsit( ObjectDecl * objDecl );
    284         };
    285 
    286         struct ArrayLength : public WithIndexer {
    287                 static void computeLength( std::list< Declaration * > & translationUnit );
    288 
    289283                void previsit( ArrayType * arrayType );
    290284        };
     
    317311                        Stats::Heap::newPass("validate-A");
    318312                        Stats::Time::BlockGuard guard("validate-A");
    319                         VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
    320313                        acceptAll( translationUnit, hoistDecls );
    321314                        ReplaceTypedef::replaceTypedef( translationUnit );
     
    343336                        Stats::Time::BlockGuard guard("validate-C");
    344337                        acceptAll( translationUnit, genericParams );  // check as early as possible - can't happen before LinkReferenceToTypes_old
     338                        VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
    345339                        ReturnChecker::checkFunctionReturns( translationUnit );
    346340                        InitTweak::fixReturnStatements( translationUnit ); // must happen before autogen
     
    374368                                mutateAll( translationUnit, compoundliteral );
    375369                        });
    376                         if (!useNewAST) {
    377                                 Stats::Time::TimeBlock("Resolve With Expressions", [&]() {
    378                                         ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables
    379                                 });
    380                         }
     370                        Stats::Time::TimeBlock("Resolve With Expressions", [&]() {
     371                                ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables
     372                        });
    381373                }
    382374                {
    383375                        Stats::Heap::newPass("validate-F");
    384376                        Stats::Time::BlockGuard guard("validate-F");
    385                         if (!useNewAST) {
    386                                 Stats::Time::TimeCall("Fix Object Type",
    387                                         FixObjectType::fix, translationUnit);
    388                         }
    389                         Stats::Time::TimeCall("Initializer Length",
    390                                 InitializerLength::computeLength, translationUnit);
    391                         if (!useNewAST) {
    392                                 Stats::Time::TimeCall("Array Length",
    393                                         ArrayLength::computeLength, translationUnit);
    394                         }
     377                        Stats::Time::TimeCall("Fix Object Type",
     378                                FixObjectType::fix, translationUnit);
     379                        Stats::Time::TimeCall("Array Length",
     380                                ArrayLength::computeLength, translationUnit);
    395381                        Stats::Time::TimeCall("Find Special Declarations",
    396382                                Validate::findSpecialDecls, translationUnit);
    397383                        Stats::Time::TimeCall("Fix Label Address",
    398384                                mutateAll<LabelAddressFixer>, translationUnit, labelAddrFixer);
    399                         if (!useNewAST) {
    400                                 Stats::Time::TimeCall("Handle Attributes",
    401                                         Validate::handleAttributes, translationUnit);
    402                         }
     385                        Stats::Time::TimeCall("Handle Attributes",
     386                                Validate::handleAttributes, translationUnit);
    403387                }
    404388        }
     
    976960        }
    977961
    978         static bool isNonParameterAttribute( Attribute * attr ) {
    979                 static const std::vector<std::string> bad_names = {
    980                         "aligned", "__aligned__",
    981                 };
    982                 for ( auto name : bad_names ) {
    983                         if ( name == attr->name ) {
    984                                 return true;
    985                         }
    986                 }
    987                 return false;
    988         }
    989 
    990962        Type * ReplaceTypedef::postmutate( TypeInstType * typeInst ) {
    991963                // instances of typedef types will come here. If it is an instance
     
    996968                        ret->location = typeInst->location;
    997969                        ret->get_qualifiers() |= typeInst->get_qualifiers();
    998                         // GCC ignores certain attributes if they arrive by typedef, this mimics that.
    999                         if ( inFunctionType ) {
    1000                                 ret->attributes.remove_if( isNonParameterAttribute );
    1001                         }
    1002                         ret->attributes.splice( ret->attributes.end(), typeInst->attributes );
     970                        // attributes are not carried over from typedef to function parameters/return values
     971                        if ( ! inFunctionType ) {
     972                                ret->attributes.splice( ret->attributes.end(), typeInst->attributes );
     973                        } else {
     974                                deleteAll( ret->attributes );
     975                                ret->attributes.clear();
     976                        }
    1003977                        // place instance parameters on the typedef'd type
    1004978                        if ( ! typeInst->parameters.empty() ) {
     
    12081182                if ( CodeGen::isCtorDtorAssign( funcDecl->get_name() ) ) { // TODO: also check /=, etc.
    12091183                        if ( params.size() == 0 ) {
    1210                                 SemanticError( funcDecl->location, "Constructors, destructors, and assignment functions require at least one parameter." );
     1184                                SemanticError( funcDecl, "Constructors, destructors, and assignment functions require at least one parameter " );
    12111185                        }
    12121186                        ReferenceType * refType = dynamic_cast< ReferenceType * >( params.front()->get_type() );
    12131187                        if ( ! refType ) {
    1214                                 SemanticError( funcDecl->location, "First parameter of a constructor, destructor, or assignment function must be a reference." );
     1188                                SemanticError( funcDecl, "First parameter of a constructor, destructor, or assignment function must be a reference " );
    12151189                        }
    12161190                        if ( CodeGen::isCtorDtor( funcDecl->get_name() ) && returnVals.size() != 0 ) {
    1217                                 if(!returnVals.front()->get_type()->isVoid()) {
    1218                                         SemanticError( funcDecl->location, "Constructors and destructors cannot have explicit return values." );
    1219                                 }
     1191                                SemanticError( funcDecl, "Constructors and destructors cannot have explicit return values " );
    12201192                        }
    12211193                }
     
    13411313        }
    13421314
    1343         void InitializerLength::computeLength( std::list< Declaration * > & translationUnit ) {
    1344                 PassVisitor<InitializerLength> len;
    1345                 acceptAll( translationUnit, len );
    1346         }
    1347 
    13481315        void ArrayLength::computeLength( std::list< Declaration * > & translationUnit ) {
    13491316                PassVisitor<ArrayLength> len;
     
    13511318        }
    13521319
    1353         void InitializerLength::previsit( ObjectDecl * objDecl ) {
     1320        void ArrayLength::previsit( ObjectDecl * objDecl ) {
    13541321                if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->type ) ) {
    13551322                        if ( at->dimension ) return;
     
    14051372        /// Replaces enum types by int, and function/array types in function parameter and return
    14061373        /// lists by appropriate pointers
    1407         /*
    14081374        struct EnumAndPointerDecay_new {
    14091375                const ast::EnumDecl * previsit( const ast::EnumDecl * enumDecl ) {
     
    14561422                }
    14571423        };
    1458         */
    14591424
    14601425        /// expand assertions from a trait instance, performing appropriate type variable substitutions
     
    14751440        }
    14761441
    1477         /*
    1478 
    14791442        /// Associates forward declarations of aggregates with their definitions
    14801443        class LinkReferenceToTypes_new final
     
    15431506                }
    15441507
    1545                 void checkGenericParameters( const ast::BaseInstType * inst ) {
     1508                void checkGenericParameters( const ast::ReferenceToType * inst ) {
    15461509                        for ( const ast::Expr * param : inst->params ) {
    15471510                                if ( ! dynamic_cast< const ast::TypeExpr * >( param ) ) {
     
    18071770                static const node_t * forallFixer(
    18081771                        const CodeLocation & loc, const node_t * node,
    1809                         ast::FunctionType::ForallList parent_t::* forallField
     1772                        ast::ParameterizedType::ForallList parent_t::* forallField
    18101773                ) {
    18111774                        for ( unsigned i = 0; i < (node->* forallField).size(); ++i ) {
     
    18581821                }
    18591822        };
    1860         */
    18611823} // anonymous namespace
    18621824
    1863 /*
    18641825const ast::Type * validateType(
    18651826                const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab ) {
    1866         // ast::Pass< EnumAndPointerDecay_new > epc;
     1827        ast::Pass< EnumAndPointerDecay_new > epc;
    18671828        ast::Pass< LinkReferenceToTypes_new > lrt{ loc, symtab };
    18681829        ast::Pass< ForallPointerDecay_new > fpd{ loc };
    18691830
    1870         return type->accept( lrt )->accept( fpd );
     1831        return type->accept( epc )->accept( lrt )->accept( fpd );
    18711832}
    1872 */
    18731833
    18741834} // namespace SymTab
  • src/SymTab/module.mk

    reef8dfb rbdfc032  
    1717SRC_SYMTAB = \
    1818      SymTab/Autogen.cc \
    19       SymTab/Autogen.h \
    2019      SymTab/FixFunction.cc \
    21       SymTab/FixFunction.h \
    2220      SymTab/Indexer.cc \
    23       SymTab/Indexer.h \
    2421      SymTab/Mangler.cc \
    2522      SymTab/ManglerCommon.cc \
    26       SymTab/Mangler.h \
    27       SymTab/Validate.cc \
    28       SymTab/Validate.h
     23      SymTab/Validate.cc
    2924
    3025SRC += $(SRC_SYMTAB)
  • src/SynTree/AggregateDecl.cc

    reef8dfb rbdfc032  
    2121#include "Common/utility.h"      // for printAll, cloneAll, deleteAll
    2222#include "Declaration.h"         // for AggregateDecl, TypeDecl, Declaration
    23 #include "Expression.h"
    2423#include "Initializer.h"
    2524#include "LinkageSpec.h"         // for Spec, linkageName, Cforall
     
    8988const char * StructDecl::typeString() const { return aggrString( kind ); }
    9089
    91 StructInstType * StructDecl::makeInst( std::list< Expression * > const & new_parameters ) {
    92         std::list< Expression * > copy_parameters;
    93         cloneAll( new_parameters, copy_parameters );
    94         return makeInst( move( copy( copy_parameters ) ) );
    95 }
    96 
    97 StructInstType * StructDecl::makeInst( std::list< Expression * > && new_parameters ) {
    98         assert( parameters.size() == new_parameters.size() );
    99         StructInstType * type = new StructInstType( noQualifiers, this );
    100         type->parameters = std::move( new_parameters );
    101         return type;
    102 }
    103 
    10490const char * UnionDecl::typeString() const { return aggrString( Union ); }
    10591
  • src/SynTree/ApplicationExpr.cc

    reef8dfb rbdfc032  
    3434
    3535ParamEntry::ParamEntry( const ParamEntry &other ) :
    36                 decl( other.decl ), declptr( other.declptr ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {
     36                decl( other.decl ), declptr( maybeClone( other.declptr ) ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {
    3737}
    3838
    3939ParamEntry::~ParamEntry() {
    40         // delete declptr;
     40        delete declptr;
    4141        delete actualType;
    4242        delete formalType;
  • src/SynTree/Attribute.h

    reef8dfb rbdfc032  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 13 21:34:08 2020
    13 // Update Count     : 40
     12// Last Modified On : Sat Jul 22 09:54:14 2017
     13// Update Count     : 39
    1414//
    1515
     
    3838        virtual ~Attribute();
    3939
    40         const std::string & get_name() const { return name; }
     40        std::string get_name() const { return name; }
    4141        void set_name( const std::string & newValue ) { name = newValue; }
    4242        std::list< Expression * > & get_parameters() { return parameters; }
  • src/SynTree/Declaration.h

    reef8dfb rbdfc032  
    181181  public:
    182182        Type * base;
     183        std::list< TypeDecl * > parameters;
    183184        std::list< DeclarationWithType * > assertions;
    184185
     
    189190        Type * get_base() const { return base; }
    190191        void set_base( Type * newValue ) { base = newValue; }
     192        std::list< TypeDecl* > & get_parameters() { return parameters; }
    191193        std::list< DeclarationWithType * >& get_assertions() { return assertions; }
    192194
     
    300302
    301303        bool is_coroutine() { return kind == Coroutine; }
    302         bool is_generator() { return kind == Generator; }
    303         bool is_monitor  () { return kind == Monitor  ; }
    304         bool is_thread   () { return kind == Thread   ; }
    305 
    306         // Make a type instance of this declaration.
    307         StructInstType * makeInst( std::list< Expression * > const & parameters );
    308         StructInstType * makeInst( std::list< Expression * > && parameters );
     304        bool is_monitor() { return kind == Monitor; }
     305        bool is_thread() { return kind == Thread; }
    309306
    310307        virtual StructDecl * clone() const override { return new StructDecl( *this ); }
  • src/SynTree/Expression.cc

    reef8dfb rbdfc032  
    3030#include "Type.h"                    // for Type, BasicType, Type::Qualifiers
    3131#include "TypeSubstitution.h"        // for TypeSubstitution
    32 #include "CompilationState.h"        // for deterministic_output
    3332
    3433#include "GenPoly/Lvalue.h"
     
    7170        printInferParams( inferParams, os, indent+1, 0 );
    7271
    73         if ( result ) {
    74                 os << std::endl << indent << "with resolved type:" << std::endl;
    75                 os << (indent+1);
    76                 result->print( os, indent+1 );
    77         }
    78 
    7972        if ( env ) {
    8073                os << std::endl << indent << "... with environment:" << std::endl;
     
    300293}
    301294
    302 KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ) : Expression(), arg(arg), target( target ) {}
    303 KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target, const KeywordCastExpr::Concrete & concrete_target ) : Expression(), arg(arg), target( target ), concrete_target(concrete_target) {}
    304 
    305 KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) {}
     295KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ) : Expression(), arg(arg), target( target ) {
     296}
     297
     298KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) {
     299}
    306300
    307301KeywordCastExpr::~KeywordCastExpr() {
  • src/SynTree/Expression.h

    reef8dfb rbdfc032  
    163163};
    164164
    165 /// VariableExpr represents an expression that simply refers to the value of a named variable.
    166 /// Does not take ownership of var.
    167 class VariableExpr : public Expression {
    168   public:
    169         DeclarationWithType * var;
    170 
    171         VariableExpr();
    172         VariableExpr( DeclarationWithType * var );
    173         VariableExpr( const VariableExpr & other );
    174         virtual ~VariableExpr();
    175 
    176         bool get_lvalue() const final;
    177 
    178         DeclarationWithType * get_var() const { return var; }
    179         void set_var( DeclarationWithType * newValue ) { var = newValue; }
    180 
    181         static VariableExpr * functionPointer( FunctionDecl * decl );
    182 
    183         virtual VariableExpr * clone() const override { return new VariableExpr( * this ); }
    184         virtual void accept( Visitor & v ) override { v.visit( this ); }
    185         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    186         virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    187         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    188 };
    189 
    190165// The following classes are used to represent expression types that cannot be converted into
    191166// function-call format.
     
    231206  public:
    232207        Expression * arg;
    233 
    234         // Inidicates cast is introduced by the CFA type system.
    235         // true for casts that the resolver introduces to force a return type
    236         // false for casts from user code
    237         // false for casts from desugaring advanced CFA features into simpler CFA
    238         // example
    239         //   int * p;     // declaration
    240         //   (float *) p; // use, with subject cast
    241         // subject cast isGenerated means we are considering an interpretation with a type mismatch
    242         // subject cast not isGenerated means someone in charge wants it that way
    243         bool isGenerated = true;
     208        bool isGenerated = true; // cast generated implicitly by code generation or explicit in program
    244209
    245210        CastExpr( Expression * arg, bool isGenerated = true );
     
    273238
    274239        KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target );
    275         KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target, const Concrete & concrete_target );
    276240        KeywordCastExpr( const KeywordCastExpr & other );
    277241        virtual ~KeywordCastExpr();
     
    348312
    349313        virtual MemberExpr * clone() const override { return new MemberExpr( * this ); }
     314        virtual void accept( Visitor & v ) override { v.visit( this ); }
     315        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     316        virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     317        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     318};
     319
     320/// VariableExpr represents an expression that simply refers to the value of a named variable.
     321/// Does not take ownership of var.
     322class VariableExpr : public Expression {
     323  public:
     324        DeclarationWithType * var;
     325
     326        VariableExpr();
     327        VariableExpr( DeclarationWithType * var );
     328        VariableExpr( const VariableExpr & other );
     329        virtual ~VariableExpr();
     330
     331        bool get_lvalue() const final;
     332
     333        DeclarationWithType * get_var() const { return var; }
     334        void set_var( DeclarationWithType * newValue ) { var = newValue; }
     335
     336        static VariableExpr * functionPointer( FunctionDecl * decl );
     337
     338        virtual VariableExpr * clone() const override { return new VariableExpr( * this ); }
    350339        virtual void accept( Visitor & v ) override { v.visit( this ); }
    351340        virtual void accept( Visitor & v ) const override { v.visit( this ); }
  • src/SynTree/LinkageSpec.cc

    reef8dfb rbdfc032  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 13:22:09 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Mar  2 16:13:00 2020
    13 // Update Count     : 29
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Dec 16 15:02:29 2019
     13// Update Count     : 28
    1414//
    1515
     
    2020
    2121#include "LinkageSpec.h"
    22 #include "Common/CodeLocation.h"
    2322#include "Common/SemanticError.h"
    2423
  • src/SynTree/LinkageSpec.h

    reef8dfb rbdfc032  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 13:24:28 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Mar  2 16:13:00 2020
    13 // Update Count     : 21
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Dec 16 15:03:43 2019
     13// Update Count     : 20
    1414//
    1515
     
    1818#include <string>
    1919
    20 struct CodeLocation;
     20#include "Common/CodeLocation.h"
    2121
    2222namespace LinkageSpec {
  • src/SynTree/Mutator.h

    reef8dfb rbdfc032  
    5151        virtual Statement * mutate( CatchStmt * catchStmt ) = 0;
    5252        virtual Statement * mutate( FinallyStmt * catchStmt ) = 0;
    53         virtual Statement * mutate( SuspendStmt * suspendStmt ) = 0;
    5453        virtual Statement * mutate( WaitForStmt * waitforStmt ) = 0;
    5554        virtual Declaration * mutate( WithStmt * withStmt ) = 0;
  • src/SynTree/NamedTypeDecl.cc

    reef8dfb rbdfc032  
    2222#include "LinkageSpec.h"         // for Spec, Cforall, linkageName
    2323#include "Type.h"                // for Type, Type::StorageClasses
    24 #include "CompilationState.h"
    2524
    2625NamedTypeDecl::NamedTypeDecl( const std::string &name, Type::StorageClasses scs, Type *base )
     
    2928NamedTypeDecl::NamedTypeDecl( const NamedTypeDecl &other )
    3029        : Parent( other ), base( maybeClone( other.base ) ) {
     30        cloneAll( other.parameters, parameters );
    3131        cloneAll( other.assertions, assertions );
    3232}
     
    3434NamedTypeDecl::~NamedTypeDecl() {
    3535        delete base;
     36        deleteAll( parameters );
    3637        deleteAll( assertions );
    3738}
     
    4041        using namespace std;
    4142
    42         if ( ! name.empty() ) {
    43                 if( deterministic_output && isUnboundType(name) ) os << "[unbound]:";
    44                 else os << name << ": ";
    45         }
     43        if ( name != "" ) os << name << ": ";
    4644
    4745        if ( linkage != LinkageSpec::Cforall ) {
     
    5351                os << " for ";
    5452                base->print( os, indent+1 );
     53        } // if
     54        if ( ! parameters.empty() ) {
     55                os << endl << indent << "... with parameters" << endl;
     56                printAll( parameters, os, indent+1 );
    5557        } // if
    5658        if ( ! assertions.empty() ) {
     
    7072                base->print( os, indent+1 );
    7173        } // if
     74        if ( ! parameters.empty() ) {
     75                os << endl << indent << "... with parameters" << endl;
     76                printAll( parameters, os, indent+1 );
     77        } // if
    7278}
    7379
  • src/SynTree/ReferenceToType.cc

    reef8dfb rbdfc032  
    2424#include "Type.h"             // for TypeInstType, StructInstType, UnionInstType
    2525#include "TypeSubstitution.h" // for TypeSubstitution
    26 #include "CompilationState.h"
    2726
    2827class Attribute;
     
    206205
    207206        Type::print( os, indent );
    208         os << "instance of " << typeString() << " ";
    209         const auto & name_ = get_name();
    210         if( deterministic_output && isUnboundType(name) ) os << "[unbound]";
    211         else os << name;
    212         os << " (" << ( isFtype ? "" : "not" ) << " function type)";
     207        os << "instance of " << typeString() << " " << get_name() << " (" << ( isFtype ? "" : "not" ) << " function type)";
    213208        if ( ! parameters.empty() ) {
    214209                os << endl << indent << "... with parameters" << endl;
  • src/SynTree/Statement.cc

    reef8dfb rbdfc032  
    420420}
    421421
    422 SuspendStmt::SuspendStmt( const SuspendStmt & other )
    423         : Statement( other )
    424         , then( maybeClone(other.then) )
    425 {}
    426 
    427 SuspendStmt::~SuspendStmt() {
    428         delete then;
    429 }
    430 
    431 void SuspendStmt::print( std::ostream & os, Indenter indent ) const {
    432         os << "Suspend Statement";
    433         switch (type) {
    434                 case None     : os << " with implicit target"; break;
    435                 case Generator: os << " for generator"       ; break;
    436                 case Coroutine: os << " for coroutine"       ; break;
    437         }
    438         os << endl;
    439         indent += 1;
    440 
    441         if(then) {
    442                 os << indent << " with post statement :" << endl;
    443                 then->print( os, indent + 1);
    444         }
    445 }
    446 
    447422WaitForStmt::WaitForStmt() : Statement() {
    448423        timeout.time      = nullptr;
  • src/SynTree/Statement.h

    reef8dfb rbdfc032  
    422422};
    423423
    424 class SuspendStmt : public Statement {
    425   public:
    426         CompoundStmt * then = nullptr;
    427         enum Type { None, Coroutine, Generator } type = None;
    428 
    429         SuspendStmt() = default;
    430         SuspendStmt( const SuspendStmt & );
    431         virtual ~SuspendStmt();
    432 
    433         virtual SuspendStmt * clone() const override { return new SuspendStmt( *this ); }
    434         virtual void accept( Visitor & v ) override { v.visit( this ); }
    435         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    436         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    437         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    438 };
    439 
    440424class WaitForStmt : public Statement {
    441425  public:
     
    518502class ImplicitCtorDtorStmt : public Statement {
    519503  public:
    520         // the constructor/destructor call statement; owned here for a while, eventually transferred elsewhere
     504        // Non-owned pointer to the constructor/destructor statement
    521505        Statement * callStmt;
    522506
  • src/SynTree/SynTree.h

    reef8dfb rbdfc032  
    5454class CatchStmt;
    5555class FinallyStmt;
    56 class SuspendStmt;
    5756class WaitForStmt;
    5857class WithStmt;
  • src/SynTree/Type.cc

    reef8dfb rbdfc032  
    156156const Type::Qualifiers noQualifiers;
    157157
    158 bool isUnboundType(const Type * type) {
    159         if (auto typeInst = dynamic_cast<const TypeInstType *>(type)) {
    160                 // xxx - look for a type name produced by renameTyVars.
    161 
    162                 // TODO: once TypeInstType representation is updated, it should properly check
    163                 // if the context id is filled. this is a temporary hack for now
    164                 return isUnboundType(typeInst->name);
    165         }
    166         return false;
    167 }
    168 
    169 bool isUnboundType(const std::string & tname) {
    170         // xxx - look for a type name produced by renameTyVars.
    171 
    172         // TODO: once TypeInstType representation is updated, it should properly check
    173         // if the context id is filled. this is a temporary hack for now
    174         if (std::count(tname.begin(), tname.end(), '_') >= 3) {
    175                 return true;
    176         }
    177         return false;
    178 }
    179 
    180158// Local Variables: //
    181159// tab-width: 4 //
  • src/SynTree/Type.h

    reef8dfb rbdfc032  
    733733};
    734734
    735 
    736 bool isUnboundType(const Type * type);
    737 bool isUnboundType(const std::string & tname);
    738 
    739735// Local Variables: //
    740736// tab-width: 4 //
  • src/SynTree/TypeDecl.cc

    reef8dfb rbdfc032  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Oct  8 18:18:55 2020
    13 // Update Count     : 22
     12// Last Modified On : Fri Dec 13 15:26:14 2019
     13// Update Count     : 21
    1414//
    1515
     
    2121#include "Type.h"            // for Type, Type::StorageClasses
    2222
    23 TypeDecl::TypeDecl( const std::string & name, Type::StorageClasses scs, Type * type, Kind kind, bool sized, Type * init ) :
    24         Parent( name, scs, type ), kind( kind ), sized( kind == Ttype || sized ), init( init ) {
     23TypeDecl::TypeDecl( const std::string & name, Type::StorageClasses scs, Type * type, Kind kind, bool sized, Type * init ) : Parent( name, scs, type ), kind( kind ), sized( kind == Ttype || sized ), init( init ) {
    2524}
    2625
  • src/SynTree/Visitor.h

    reef8dfb rbdfc032  
    7878        virtual void visit( FinallyStmt * node ) { visit( const_cast<const FinallyStmt *>(node) ); }
    7979        virtual void visit( const FinallyStmt * finallyStmt ) = 0;
    80         virtual void visit( SuspendStmt * node ) { visit( const_cast<const SuspendStmt *>(node) ); }
    81         virtual void visit( const SuspendStmt * suspendStmt ) = 0;
    8280        virtual void visit( WaitForStmt * node ) { visit( const_cast<const WaitForStmt *>(node) ); }
    8381        virtual void visit( const WaitForStmt * waitforStmt ) = 0;
  • src/SynTree/module.mk

    reef8dfb rbdfc032  
    2020      SynTree/ApplicationExpr.cc \
    2121      SynTree/ArrayType.cc \
     22      SynTree/AttrType.cc \
    2223      SynTree/Attribute.cc \
    23       SynTree/Attribute.h \
    24       SynTree/AttrType.cc \
    25       SynTree/BaseSyntaxNode.h \
    2624      SynTree/BasicType.cc \
    2725      SynTree/CommaExpr.cc \
    2826      SynTree/CompoundStmt.cc \
    2927      SynTree/Constant.cc \
    30       SynTree/Constant.h \
     28      SynTree/DeclReplacer.cc \
     29      SynTree/DeclStmt.cc \
    3130      SynTree/Declaration.cc \
    32       SynTree/Declaration.h \
    3331      SynTree/DeclarationWithType.cc \
    34       SynTree/DeclReplacer.cc \
    35       SynTree/DeclReplacer.h \
    36       SynTree/DeclStmt.cc \
    3732      SynTree/Expression.cc \
    38       SynTree/Expression.h \
    3933      SynTree/FunctionDecl.cc \
    4034      SynTree/FunctionType.cc \
    4135      SynTree/Initializer.cc \
    42       SynTree/Initializer.h \
    43       SynTree/Label.h \
    4436      SynTree/LinkageSpec.cc \
    45       SynTree/LinkageSpec.h \
    46       SynTree/Mutator.h \
    4737      SynTree/NamedTypeDecl.cc \
    4838      SynTree/ObjectDecl.cc \
     
    5141      SynTree/ReferenceType.cc \
    5242      SynTree/Statement.cc \
    53       SynTree/Statement.h \
    54       SynTree/SynTree.h \
    5543      SynTree/TupleExpr.cc \
    5644      SynTree/TupleType.cc \
     
    5846      SynTree/TypeDecl.cc \
    5947      SynTree/TypeExpr.cc \
    60       SynTree/Type.h \
     48      SynTree/TypeSubstitution.cc \
    6149      SynTree/TypeofType.cc \
    62       SynTree/TypeSubstitution.cc \
    63       SynTree/TypeSubstitution.h \
    6450      SynTree/VarArgsType.cc \
    65       SynTree/Visitor.h \
    6651      SynTree/VoidType.cc \
    6752      SynTree/ZeroOneType.cc
  • src/Tuples/Explode.cc

    reef8dfb rbdfc032  
    129129                        for ( const ast::Expr * expr : tupleExpr->exprs ) {
    130130                                exprs.emplace_back( applyCast( expr, false ) );
     131                                //exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );
    131132                        }
    132133                        if ( first ) {
     
    147148        }
    148149
    149         const ast::Expr * postvisit( const ast::UniqueExpr * node ) {
     150        const ast::Expr * postmutate( const ast::UniqueExpr * node ) {
    150151                // move cast into unique expr so that the unique expr has type T& rather than
    151152                // type T. In particular, this transformation helps with generating the
     
    161162                        castAdded = false;
    162163                        const ast::Type * newType = getReferenceBase( newNode->result );
    163                         return new ast::CastExpr{ newNode->location, newNode, newType };
     164                        return new ast::CastExpr{ newNode->location, node, newType };
    164165                }
    165166                return newNode;
    166167        }
    167168
    168         const ast::Expr * postvisit( const ast::TupleIndexExpr * tupleExpr ) {
     169        const ast::Expr * postmutate( const ast::TupleIndexExpr * tupleExpr ) {
    169170                // tuple index expr needs to be rebuilt to ensure that the type of the
    170171                // field is consistent with the type of the tuple expr, since the field
     
    179180        ast::Pass<CastExploderCore> exploder;
    180181        expr = expr->accept( exploder );
    181         if ( ! exploder.core.foundUniqueExpr ) {
     182        if ( ! exploder.pass.foundUniqueExpr ) {
    182183                expr = new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } };
    183184        }
  • src/Tuples/Explode.h

    reef8dfb rbdfc032  
    210210                        }
    211211                        // Cast a reference away to a value-type to allow further explosion.
    212                         if ( local->result.as< ast::ReferenceType >() ) {
     212                        if ( dynamic_cast< const ast::ReferenceType *>( local->result.get() ) ) {
    213213                                local = new ast::CastExpr{ local, tupleType };
    214214                        }
     
    220220                                // delete idx;
    221221                        }
     222                        // delete local;
    222223                }
    223224        } else {
  • src/Tuples/TupleAssignment.cc

    reef8dfb rbdfc032  
    465465                                        // resolve ctor/dtor for the new object
    466466                                        ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
    467                                                         InitTweak::genCtorInit( location, ret ), spotter.crntFinder.localSyms );
     467                                                        InitTweak::genCtorInit( location, ret ), spotter.crntFinder.symtab );
    468468                                        // remove environments from subexpressions of stmtExpr
    469469                                        ast::Pass< EnvRemover > rm{ env };
     
    560560                                        // resolve the cast expression so that rhsCand return type is bound by the cast
    561561                                        // type as needed, and transfer the resulting environment
    562                                         ResolvExpr::CandidateFinder finder{ spotter.crntFinder.localSyms, env };
     562                                        ResolvExpr::CandidateFinder finder{ spotter.crntFinder.symtab, env };
    563563                                        finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );
    564564                                        assert( finder.candidates.size() == 1 );
     
    609609                                        // explode the LHS so that each field of a tuple-valued expr is assigned
    610610                                        ResolvExpr::CandidateList lhs;
    611                                         explode( *lhsCand, crntFinder.localSyms, back_inserter(lhs), true );
     611                                        explode( *lhsCand, crntFinder.symtab, back_inserter(lhs), true );
    612612                                        for ( ResolvExpr::CandidateRef & cand : lhs ) {
    613613                                                // each LHS value must be a reference - some come in with a cast, if not
     
    629629                                                        if ( isTuple( rhsCand->expr ) ) {
    630630                                                                // multiple assignment
    631                                                                 explode( *rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
     631                                                                explode( *rhsCand, crntFinder.symtab, back_inserter(rhs), true );
    632632                                                                matcher.reset(
    633633                                                                        new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     
    648648                                                        // multiple assignment
    649649                                                        ResolvExpr::CandidateList rhs;
    650                                                         explode( rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
     650                                                        explode( rhsCand, crntFinder.symtab, back_inserter(rhs), true );
    651651                                                        matcher.reset(
    652652                                                                new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     
    678678                                )
    679679
    680                                 ResolvExpr::CandidateFinder finder{ crntFinder.localSyms, matcher->env };
     680                                ResolvExpr::CandidateFinder finder{ crntFinder.symtab, matcher->env };
    681681
    682682                                try {
  • src/Tuples/TupleExpansion.cc

    reef8dfb rbdfc032  
    323323                std::vector<ast::ptr<ast::Type>> types;
    324324                ast::CV::Qualifiers quals{
    325                         ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict |
     325                        ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |
    326326                        ast::CV::Atomic | ast::CV::Mutex };
    327327
  • src/Tuples/Tuples.cc

    reef8dfb rbdfc032  
    4343        };
    4444        struct ImpurityDetectorIgnoreUnique : public ImpurityDetector {
    45                 using ImpurityDetector::previsit;
    4645                void previsit( ast::UniqueExpr const * ) {
    4746                        visit_children = false;
     
    5352                ast::Pass<Detector> detector;
    5453                expr->accept( detector );
    55                 return detector.core.maybeImpure;
     54                return detector.pass.maybeImpure;
    5655        }
    5756} // namespace
  • src/Tuples/module.mk

    reef8dfb rbdfc032  
    1515###############################################################################
    1616
    17 SRC_TUPLES = \
    18         Tuples/Explode.cc \
    19         Tuples/Explode.h \
    20         Tuples/TupleAssignment.cc \
    21         Tuples/TupleExpansion.cc \
    22         Tuples/Tuples.cc \
    23         Tuples/Tuples.h
    24 
    25 
    26 SRC += $(SRC_TUPLES)
    27 SRCDEMANGLE += $(SRC_TUPLES)
     17SRC += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \
     18        Tuples/Tuples.cc
     19SRCDEMANGLE += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \
     20        Tuples/Tuples.cc
  • src/Validate/module.mk

    reef8dfb rbdfc032  
    1515###############################################################################
    1616
    17 SRC += Validate/HandleAttributes.cc Validate/HandleAttributes.h Validate/FindSpecialDecls.cc Validate/FindSpecialDecls.h
    18 SRCDEMANGLE += Validate/HandleAttributes.cc Validate/HandleAttributes.h Validate/FindSpecialDecls.cc Validate/FindSpecialDecls.h
     17SRC += Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc
     18SRCDEMANGLE += Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc
  • src/Virtual/ExpandCasts.cc

    reef8dfb rbdfc032  
    1010// Created On       : Mon Jul 24 13:59:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jul 31 10:29:00 2020
    13 // Update Count     : 4
     12// Last Modified On : Tus Aug  2 14:59:00 2017
     13// Update Count     : 1
    1414//
    1515
     
    1818#include <cassert>                 // for assert, assertf
    1919#include <iterator>                // for back_inserter, inserter
     20#include <map>                     // for map, _Rb_tree_iterator, map<>::ite...
    2021#include <string>                  // for string, allocator, operator==, ope...
     22#include <utility>                 // for pair
    2123
    2224#include "Common/PassVisitor.h"    // for PassVisitor
    23 #include "Common/ScopedMap.h"      // for ScopedMap
    2425#include "Common/SemanticError.h"  // for SemanticError
    25 #include "SymTab/Mangler.h"        // for mangleType
    2626#include "SynTree/Declaration.h"   // for ObjectDecl, StructDecl, FunctionDecl
    2727#include "SynTree/Expression.h"    // for VirtualCastExpr, CastExpr, Address...
     
    3232namespace Virtual {
    3333
    34         // Indented until the new ast code gets added.
    35 
    36         /// Maps virtual table types the instance for that type.
    37         class VirtualTableMap final {
    38                 ScopedMap<std::string, ObjectDecl *> vtable_instances;
    39         public:
    40                 void enterScope() {
    41                         vtable_instances.beginScope();
    42                 }
    43                 void leaveScope() {
    44                         vtable_instances.endScope();
    45                 }
    46 
    47                 ObjectDecl * insert( ObjectDecl * vtableDecl ) {
    48                         std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );
    49                         ObjectDecl *& value = vtable_instances[ mangledName ];
    50                         if ( value ) {
    51                                 if ( vtableDecl->storageClasses.is_extern ) {
    52                                         return nullptr;
    53                                 } else if ( ! value->storageClasses.is_extern ) {
    54                                         return value;
    55                                 }
    56                         }
    57                         value = vtableDecl;
    58                         return nullptr;
    59                 }
    60 
    61                 ObjectDecl * lookup( const Type * vtableType ) {
    62                         std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );
    63                         const auto it = vtable_instances.find( mangledName );
    64                         return ( vtable_instances.end() == it ) ? nullptr : it->second;
    65                 }
    66         };
    67 
    6834        /* Currently virtual depends on the rather brittle name matching between
    6935         * a (strict/explicate) virtual type, its vtable type and the vtable
     
    7238         * and use that information to create better error messages.
    7339         */
    74 
    75         namespace {
    7640
    7741        std::string get_vtable_name( std::string const & name ) {
     
    9155        }
    9256
     57        bool is_vtable_name( std::string const & name ) {
     58                return (name.substr( name.size() - 7 ) == "_vtable" );
     59        }
     60
    9361        bool is_vtable_inst_name( std::string const & name ) {
    9462                return 17 < name.size() &&
     
    9664        }
    9765
    98         } // namespace
     66        class VirtualCastCore {
     67        std::map<std::string, ObjectDecl *> vtable_instances;
     68        FunctionDecl *vcast_decl;
     69        StructDecl *pvt_decl;
    9970
    100         class VirtualCastCore {
    10171                Type * pointer_to_pvt(int level_of_indirection) {
    10272                        Type * type = new StructInstType(
     
    11080        public:
    11181                VirtualCastCore() :
    112                         indexer(), vcast_decl( nullptr ), pvt_decl( nullptr )
     82                        vtable_instances(), vcast_decl( nullptr ), pvt_decl( nullptr )
    11383                {}
    11484
     
    11888
    11989                Expression * postmutate( VirtualCastExpr * castExpr );
    120 
    121                 VirtualTableMap indexer;
    122         private:
    123                 FunctionDecl *vcast_decl;
    124                 StructDecl *pvt_decl;
    12590        };
    12691
     
    142107        void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
    143108                if ( is_vtable_inst_name( objectDecl->get_name() ) ) {
    144                         if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) {
    145                                 std::string msg = "Repeated instance of virtual table, original found at: ";
    146                                 msg += existing->location.filename;
    147                                 msg += ":" + toString( existing->location.first_line );
    148                                 SemanticError( objectDecl->location, msg );
    149                         }
     109                        vtable_instances[objectDecl->get_name()] = objectDecl;
    150110                }
    151111        }
    152112
    153         namespace {
    154 
    155         /// Better error locations for generated casts.
    156         CodeLocation castLocation( const VirtualCastExpr * castExpr ) {
    157                 if ( castExpr->location.isSet() ) {
    158                         return castExpr->location;
    159                 } else if ( castExpr->arg->location.isSet() ) {
    160                         return castExpr->arg->location;
    161                 } else if ( castExpr->result->location.isSet() ) {
    162                         return castExpr->result->location;
    163                 } else {
    164                         return CodeLocation();
    165                 }
    166         }
    167 
    168         [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {
    169                 SemanticError( castLocation( castExpr ), message );
    170         }
    171 
    172         /// Get the virtual table type used in a virtual cast.
    173         Type * getVirtualTableType( const VirtualCastExpr * castExpr ) {
    174                 const Type * objectType;
    175                 if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) {
    176                         objectType = target->base;
    177                 } else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) {
    178                         objectType = target->base;
    179                 } else {
    180                         castError( castExpr, "Virtual cast type must be a pointer or reference type." );
    181                 }
    182                 assert( objectType );
    183 
    184                 const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType );
    185                 if ( nullptr == structType ) {
    186                         castError( castExpr, "Virtual cast type must refer to a structure type." );
    187                 }
    188                 const StructDecl * structDecl = structType->baseStruct;
    189                 assert( structDecl );
    190 
    191                 const ObjectDecl * fieldDecl = nullptr;
    192                 if ( 0 < structDecl->members.size() ) {
    193                         const Declaration * memberDecl = structDecl->members.front();
    194                         assert( memberDecl );
    195                         fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
    196                         if ( fieldDecl && fieldDecl->name != "virtual_table" ) {
    197                                 fieldDecl = nullptr;
    198                         }
    199                 }
    200                 if ( nullptr == fieldDecl ) {
    201                         castError( castExpr, "Virtual cast type must have a leading virtual_table field." );
    202                 }
    203                 const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type );
    204                 if ( nullptr == fieldType ) {
    205                         castError( castExpr, "Virtual cast type virtual_table field is not a pointer." );
    206                 }
    207                 assert( fieldType->base );
    208                 auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base );
    209                 assert( virtualStructType );
    210 
    211                 // Here is the type, but if it is polymorphic it will have lost information.
    212                 // (Always a clone so that it may always be deleted.)
    213                 StructInstType * virtualType = virtualStructType->clone();
    214                 if ( ! structType->parameters.empty() ) {
    215                         deleteAll( virtualType->parameters );
    216                         virtualType->parameters.clear();
    217                         cloneAll( structType->parameters, virtualType->parameters );
    218                 }
    219                 return virtualType;
    220         }
    221 
    222         } // namespace
    223 
    224113        Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
    225                 assertf( castExpr->result, "Virtual Cast target not found before expansion." );
     114                assertf( castExpr->get_result(), "Virtual Cast target not found before expansion." );
    226115
    227116                assert( vcast_decl );
    228117                assert( pvt_decl );
    229118
    230                 const Type * vtable_type = getVirtualTableType( castExpr );
    231                 ObjectDecl * table = indexer.lookup( vtable_type );
    232                 if ( nullptr == table ) {
    233                         SemanticError( castLocation( castExpr ),
    234                                 "Could not find virtual table instance." );
     119                // May only cast to a pointer or reference type.
     120                // A earlier validation should give a syntax error, this is
     121                // just to make sure errors don't creep during translation.
     122                // Move to helper with more detailed error messages.
     123                PointerType * target_type =
     124                        dynamic_cast<PointerType *>( castExpr->get_result() );
     125                assert( target_type );
     126
     127                StructInstType * target_struct =
     128                        dynamic_cast<StructInstType *>( target_type->get_base() );
     129                assert( target_struct );
     130
     131                StructDecl * target_decl = target_struct->get_baseStruct();
     132
     133                std::map<std::string, ObjectDecl *>::iterator found =
     134                        vtable_instances.find(
     135                                get_vtable_inst_name( target_decl->get_name() ) );
     136                if ( vtable_instances.end() == found ) {
     137                        assertf( false, "virtual table instance not found." );
    235138                }
     139                ObjectDecl * table = found->second;
    236140
    237141                Expression * result = new CastExpr(
     142                        //new ApplicationExpr(
     143                                //new AddressExpr( new VariableExpr( vcast_decl ) ),
     144                                //new CastExpr( new VariableExpr( vcast_decl ),
     145                                //      new PointerType( noQualifiers,
     146                                //              vcast_decl->get_type()->clone()
     147                                //              )
     148                                //      ),
    238149                        new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
    239150                                        new CastExpr(
     
    252163                castExpr->set_result( nullptr );
    253164                delete castExpr;
    254                 delete vtable_type;
    255165                return result;
    256166        }
  • src/Virtual/module.mk

    reef8dfb rbdfc032  
    1515###############################################################################
    1616
    17 SRC += Virtual/ExpandCasts.cc Virtual/ExpandCasts.h \
    18         Virtual/Tables.cc Virtual/Tables.h
    19 
    20 SRCDEMANGLE += Virtual/Tables.cc
     17SRC += Virtual/ExpandCasts.cc
  • src/config.h.in

    reef8dfb rbdfc032  
    2727/* Location of cfa install. */
    2828#undef CFA_PREFIX
    29 
    30 /* Sets whether or not to use the new-ast, this is adefault value and can be
    31    overrided by --old-ast and --new-ast */
    32 #undef CFA_USE_NEW_AST
    3329
    3430/* Major.Minor */
  • src/main.cc

    reef8dfb rbdfc032  
    99// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Dec  7 15:29:00 2020
    13 // Update Count     : 639
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Dec 16 17:55:53 2019
     13// Update Count     : 627
    1414//
    1515
     
    3131using namespace std;
    3232
    33 #include "AST/Convert.hpp"
     33
    3434#include "CompilationState.h"
    3535#include "../config.h"                      // for CFA_LIBDIR
     
    4040#include "CodeTools/ResolvProtoDump.h"      // for dumpAsResolvProto
    4141#include "CodeTools/TrackLoc.h"             // for fillLocations
    42 #include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    4342#include "Common/CompilerError.h"           // for CompilerError
    4443#include "Common/Stats.h"
     
    106105
    107106static void backtrace( int start ) {                                    // skip first N stack frames
    108         enum { Frames = 50, };                                                          // maximum number of stack frames
     107        enum { Frames = 50 };
    109108        void * array[Frames];
    110         size_t size = ::backtrace( array, Frames );
     109        int size = ::backtrace( array, Frames );
    111110        char ** messages = ::backtrace_symbols( array, size ); // does not demangle names
    112111
     
    115114
    116115        // skip last 2 stack frames after main
    117         for ( unsigned int i = start; i < size - 2 && messages != nullptr; i += 1 ) {
     116        for ( int i = start; i < size - 2 && messages != nullptr; i += 1 ) {
    118117                char * mangled_name = nullptr, * offset_begin = nullptr, * offset_end = nullptr;
    119118
     
    181180} // sigSegvBusHandler
    182181
    183 static void sigFpeHandler( SIGPARMS ) {
    184         const char * msg;
    185 
    186         switch ( sfp->si_code ) {
    187           case FPE_INTDIV: case FPE_FLTDIV: msg = "divide by zero"; break;
    188           case FPE_FLTOVF: msg = "overflow"; break;
    189           case FPE_FLTUND: msg = "underflow"; break;
    190           case FPE_FLTRES: msg = "inexact result"; break;
    191           case FPE_FLTINV: msg = "invalid operation"; break;
    192           default: msg = "unknown";
    193         } // choose
    194         cerr << "Computation error " << msg << " at location " << sfp->si_addr << endl
    195                  << "Possible cause is constant-expression evaluation invalid." << endl;
    196         backtrace( 2 );                                                                         // skip first 2 stack frames
    197         abort();                                                                                        // cause core dump for debugging
    198 } // sigFpeHandler
    199 
    200182static void sigAbortHandler( SIGPARMS ) {
    201183        backtrace( 6 );                                                                         // skip first 6 stack frames
     
    211193        Signal( SIGSEGV, sigSegvBusHandler, SA_SIGINFO );
    212194        Signal( SIGBUS, sigSegvBusHandler, SA_SIGINFO );
    213         Signal( SIGFPE, sigFpeHandler, SA_SIGINFO );
    214195        Signal( SIGABRT, sigAbortHandler, SA_SIGINFO );
    215196
     
    313294                } // if
    314295
    315                 PASS( "Translate Throws", ControlStruct::translateThrows( translationUnit ) );
    316296                PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) );
    317297                PASS( "Fix Names", CodeGen::fixNames( translationUnit ) );
     
    341321                } // if
    342322
    343                 if( useNewAST ) {
    344                         if (Stats::Counters::enabled) {
    345                                 ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New");
    346                                 ast::pass_visitor_stats.max = Stats::Counters::build<Stats::Counters::MaxCounter<double>>("Max depth - New");
    347                         }
    348                         auto transUnit = convert( move( translationUnit ) );
    349                         PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
    350                         if ( exprp ) {
    351                                 translationUnit = convert( move( transUnit ) );
    352                                 dump( translationUnit );
    353                                 return EXIT_SUCCESS;
    354                         } // if
    355 
    356                         forceFillCodeLocations( transUnit );
    357 
    358                         PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
    359                         translationUnit = convert( move( transUnit ) );
    360                 } else {
    361                         PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
    362                         if ( exprp ) {
    363                                 dump( translationUnit );
    364                                 return EXIT_SUCCESS;
    365                         }
    366 
    367                         PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
    368                 }
     323                PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
     324                if ( exprp ) {
     325                        dump( translationUnit );
     326                        return EXIT_SUCCESS;
     327                } // if
    369328
    370329                // fix ObjectDecl - replaces ConstructorInit nodes
     330                PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
    371331                if ( ctorinitp ) {
    372332                        dump ( translationUnit );
     
    376336                PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    377337
    378                 PASS( "Translate Tries" , ControlStruct::translateTries( translationUnit ) );
     338                PASS( "Translate EHM" , ControlStruct::translateEHM( translationUnit ) );
    379339
    380340                PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) );
     
    465425
    466426
    467 static const char optstring[] = ":c:ghlLmNnpdOAP:S:twW:D:";
     427static const char optstring[] = ":c:ghlLmNnpP:S:twW:D:";
    468428
    469429enum { PreludeDir = 128 };
     
    478438        { "no-prelude", no_argument, nullptr, 'n' },
    479439        { "prototypes", no_argument, nullptr, 'p' },
    480         { "deterministic-out", no_argument, nullptr, 'd' },
    481         { "old-ast", no_argument, nullptr, 'O'},
    482         { "new-ast", no_argument, nullptr, 'A'},
    483440        { "print", required_argument, nullptr, 'P' },
    484441        { "prelude-dir", required_argument, nullptr, PreludeDir },
     
    492449
    493450static const char * description[] = {
    494         "diagnostic color: never, always, or auto.",            // -c
    495         "wait for gdb to attach",                                                       // -g
    496         "print help message",                                                           // -h
    497         "generate libcfa.c",                                                            // -l
    498         "generate line marks",                                                          // -L
    499         "do not replace main",                                                          // -m
    500         "do not generate line marks",                                           // -N
    501         "do not read prelude",                                                          // -n
     451        "diagnostic color: never, always, or auto.",          // -c
     452        "wait for gdb to attach",                             // -g
     453        "print help message",                                 // -h
     454        "generate libcfa.c",                                  // -l
     455        "generate line marks",                                // -L
     456        "do not replace main",                                // -m
     457        "do not generate line marks",                         // -N
     458        "do not read prelude",                                // -n
    502459        "generate prototypes for prelude functions",            // -p
    503         "only print deterministic output",                  // -d
    504         "Use the old-ast",                                                                      // -O
    505         "Use the new-ast",                                                                      // -A
    506         "print",                                                                                        // -P
     460        "print",                                              // -P
    507461        "<directory> prelude directory for debug/nodebug",      // no flag
    508462        "<option-list> enable profiling information:\n          counters,heap,time,all,none", // -S
    509         "building cfa standard lib",                                            // -t
    510         "",                                                                                                     // -w
    511         "",                                                                                                     // -W
    512         "",                                                                                                     // -D
     463        "building cfa standard lib",                          // -t
     464        "",                                                   // -w
     465        "",                                                   // -W
     466        "",                                                   // -D
    513467}; // description
    514468
     
    608562                        genproto = true;
    609563                        break;
    610                   case 'd':                                     // don't print non-deterministic output
    611                         deterministic_output = true;
    612                         break;
    613                   case 'O':                                     // don't print non-deterministic output
    614                         useNewAST = false;
    615                         break;
    616                   case 'A':                                     // don't print non-deterministic output
    617                         useNewAST = true;
    618                         break;
    619564                  case 'P':                                                                             // print options
    620565                        for ( int i = 0;; i += 1 ) {
  • tests/.expect/alloc.txt

    reef8dfb rbdfc032  
    22CFA malloc 0xdeadbeef
    33CFA alloc 0xdeadbeef
     4CFA array alloc, fill 0xde
    45CFA alloc, fill dededede
    56CFA alloc, fill 3
     
    14150xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede
    1516CFA array alloc, fill 0xef
    16 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
     170xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef
    1718CFA array alloc, fill from array
    18 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef, 0xdeadbeef 0xdeadbeef,
     190xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef, 0xefefefef 0xefefefef,
    1920
    2021C realloc
     220xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef
     23CFA realloc
     240xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101
     25
     26CFA resize array alloc
    21270xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    22 CFA realloc
     28CFA resize array alloc
    23290xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101
    24 
    25 CFA realloc array alloc
     30CFA resize array alloc
    26310xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    27 CFA realloc array alloc
    28 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101
    29 CFA realloc array alloc
     32CFA resize array alloc
     330xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede
     34CFA resize array alloc
    30350xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    31 CFA realloc array alloc, fill
    32 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede
    33 CFA realloc array alloc, fill
    34 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    35 CFA realloc array alloc, fill
    36 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede
     36CFA resize array alloc, fill
     370xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede
    3738
    3839C   memalign 42 42.5
  • tests/.expect/array.txt

    reef8dfb rbdfc032  
    1 array.cfa: In function '_X4mainFi___1':
    2 array.cfa:55:9: note: #pragma message: Compiled
  • tests/.expect/cast.txt

    reef8dfb rbdfc032  
    1 cast.cfa: In function '_X4mainFi_iPPKc__1':
    2 cast.cfa:18:9: note: #pragma message: Compiled
  • tests/.expect/copyfile.txt

    reef8dfb rbdfc032  
    88//
    99// Author           : Peter A. Buhr
    10 // Created On       : Fri Jun 19 13:44:05 2020
     10// Created On       : Tue Jul 16 16:47:22 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 19 17:58:03 2020
    13 // Update Count     : 4
     12// Last Modified On : Wed Jul 17 18:04:44 2019
     13// Update Count     : 26
    1414//
    1515
    1616#include <fstream.hfa>
    17 #include <exception.hfa>
     17#include <stdlib.hfa>                                                                   // new/delete
    1818
    1919int main( int argc, char * argv[] ) {
    20         ifstream in  = stdin;                                                           // copy default files
    21         ofstream out = stdout;
    22 
     20        ifstream * in  = &stdin;                                                        // default files
     21        ofstream * out = &stdout;
    2322        try {
    2423                choose ( argc ) {
    2524                  case 2, 3:
    26                         open( in, argv[1] );                                            // open input file first as output creates file
    27                         if ( argc == 3 ) open( out, argv[2] );          // do not create output unless input opens
    28                   case 1: ;                                                                             // use default files
     25                          in = new( (const char *)argv[1] );            // open input file first as output creates file
     26                          if ( argc == 3 ) out = new( (const char *)argv[2] ); // only open output if input opens as output created if nonexistent
     27                  case 1: ;                                     // use default files
    2928                  default:
    30                         exit | "Usage" | argv[0] | "[ input-file (default stdin) [ output-file (default stdout) ] ]";
     29                          exit | "Usage [ input-file (default stdin) [ output-file (default stdout) ] ]";
    3130                } // choose
    32         } catch( Open_Failure * ex ; ex->istream == &in ) {
    33                 exit | "Unable to open input file" | argv[1];
    34         } catch( Open_Failure * ex ; ex->ostream == &out ) {
    35                 close( in );                                                                    // optional
    36                 exit | "Unable to open output file" | argv[2];
     31
     32                char ch;
     33                *out | nlOff;                                                                   // turn off auto newline
     34                *in  | nlOn;                                                                    // turn on reading newline
     35
     36                for () {                                                                                // read all characters
     37                        *in | ch;
     38                  if ( eof( *in ) ) break;                                              // eof ?
     39                        *out | ch;
     40                } // for
     41        } finally {
     42                if ( in  != &stdin  ) delete( in );                             // close file, do not delete stdin!
     43                if ( out != &stdout ) delete( out );                    // close file, do not delete stdout!
    3744        } // try
    38 
    39         out | nlOff;                                                                            // turn off auto newline
    40         in  | nlOn;                                                                                     // turn on reading newline
    41 
    42         char ch;
    43         for () {                                                                                        // read all characters
    44                 in | ch;
    45           if ( eof( in ) ) break;                                                       // eof ?
    46                 out | ch;
    47         } //for
    4845} // main
    4946
  • tests/.expect/declarationSpecifier.x64.txt

    reef8dfb rbdfc032  
    11291129static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    11301130static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    1131 signed int _X13cfa_args_argci_1;
    1132 char **_X13cfa_args_argvPPc_1;
    1133 char **_X13cfa_args_envpPPc_1;
    11341131signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    11351132    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11361133    {
    1137         ((void)(_X13cfa_args_argci_1=_X4argci_1));
    1138     }
    1139 
    1140     {
    1141         ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
    1142     }
    1143 
    1144     {
    1145         ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
    1146     }
    1147 
    1148     {
    11491134        signed int _tmp_cp_ret4;
    11501135        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/declarationSpecifier.x86.txt

    reef8dfb rbdfc032  
    11291129static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    11301130static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    1131 signed int _X13cfa_args_argci_1;
    1132 char **_X13cfa_args_argvPPc_1;
    1133 char **_X13cfa_args_envpPPc_1;
    11341131signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    11351132    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11361133    {
    1137         ((void)(_X13cfa_args_argci_1=_X4argci_1));
    1138     }
    1139 
    1140     {
    1141         ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
    1142     }
    1143 
    1144     {
    1145         ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
    1146     }
    1147 
    1148     {
    11491134        signed int _tmp_cp_ret4;
    11501135        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/enum.txt

    reef8dfb rbdfc032  
    1 done
  • tests/.expect/expression.txt

    reef8dfb rbdfc032  
    1 expression.cfa: In function '_X4mainFi___1':
    2 expression.cfa:89:9: note: #pragma message: Compiled
  • tests/.expect/forall.txt

    reef8dfb rbdfc032  
    1 forall.cfa: In function '_X4mainFi___1':
    2 forall.cfa:218:9: note: #pragma message: Compiled
  • tests/.expect/gccExtensions.x64.txt

    reef8dfb rbdfc032  
    321321static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    322322static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    323 signed int _X13cfa_args_argci_1;
    324 char **_X13cfa_args_argvPPc_1;
    325 char **_X13cfa_args_envpPPc_1;
    326323signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    327324    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    328325    {
    329         ((void)(_X13cfa_args_argci_1=_X4argci_1));
    330     }
    331 
    332     {
    333         ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
    334     }
    335 
    336     {
    337         ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
    338     }
    339 
    340     {
    341326        signed int _tmp_cp_ret4;
    342327        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/gccExtensions.x86.txt

    reef8dfb rbdfc032  
    299299static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    300300static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    301 signed int _X13cfa_args_argci_1;
    302 char **_X13cfa_args_argvPPc_1;
    303 char **_X13cfa_args_envpPPc_1;
    304301signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    305302    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    306303    {
    307         ((void)(_X13cfa_args_argci_1=_X4argci_1));
    308     }
    309 
    310     {
    311         ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
    312     }
    313 
    314     {
    315         ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
    316     }
    317 
    318     {
    319304        signed int _tmp_cp_ret4;
    320305        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/heap.txt

    reef8dfb rbdfc032  
    1 done
  • tests/.expect/identFuncDeclarator.txt

    reef8dfb rbdfc032  
    1 identFuncDeclarator.cfa: In function '_X4mainFi___1':
    2 identFuncDeclarator.cfa:116:9: note: #pragma message: Compiled
  • tests/.expect/identParamDeclarator.txt

    reef8dfb rbdfc032  
    1 done
  • tests/.expect/labelledExit.txt

    reef8dfb rbdfc032  
    1 labelledExit.cfa: In function '_X4mainFi_iPPKc__1':
    2 labelledExit.cfa:183:9: note: #pragma message: Compiled
  • tests/.expect/limits.txt

    reef8dfb rbdfc032  
    1 limits.cfa: In function '_X4mainFi_iPPKc__1':
    2 limits.cfa:154:9: note: #pragma message: Compiled
  • tests/.expect/maybe.txt

    reef8dfb rbdfc032  
    1 done
  • tests/.expect/minmax.txt

    reef8dfb rbdfc032  
    11char                    z a     min a
    2 signed int              4 -3    min -3
     2signed int              4 3     min 3
    33unsigned int            4 3     min 3
    4 signed long int         4 -3    min -3
     4signed long int         4 3     min 3
    55unsigned long int       4 3     min 3
    6 signed long long int    4 -3    min -3
     6signed long long int    4 3     min 3
    77unsigned long long int  4 3     min 3
    88float                   4. 3.1  min 3.1
     
    1111
    1212char                    z a     max z
    13 signed int              4 -3    max 4
     13signed int              4 3     max 4
    1414unsigned int            4 3     max 4
    15 signed long int         4 -3    max 4
     15signed long int         4 3     max 4
    1616unsigned long int       4 3     max 4
    17 signed long long int    4 -3    max 4
     17signed long long int    4 3     max 4
    1818unsigned long long int  4 3     max 4
    1919float                   4. 3.1  max 4.
  • tests/.expect/nested-types-ERR1.txt

    reef8dfb rbdfc032  
    1 nested-types.cfa:83:1 error: Use of undefined type T
     1nested-types.cfa:70:1 error: Use of undefined type T
  • tests/.expect/nested-types-ERR2.txt

    reef8dfb rbdfc032  
    1 nested-types.cfa:86:1 error: Use of undefined global type Z
    2 nested-types.cfa:87:1 error: Qualified type requires an aggregate on the left, but has: signed int
    3 nested-types.cfa:88:1 error: Undefined type in qualified type: Qualified Type:
     1nested-types.cfa:73:1 error: Use of undefined global type Z
     2nested-types.cfa:74:1 error: Qualified type requires an aggregate on the left, but has: signed int
     3nested-types.cfa:75:1 error: Undefined type in qualified type: Qualified Type:
    44  instance of struct S with body 1
    55  instance of type Z (not function type)
  • tests/.expect/nested-types.txt

    reef8dfb rbdfc032  
    1 nested-types.cfa: In function '_X4mainFi___1':
    2 nested-types.cfa:102:9: note: #pragma message: Compiled
  • tests/.expect/numericConstants.txt

    reef8dfb rbdfc032  
    1 numericConstants.cfa: In function '_X4mainFi___1':
    2 numericConstants.cfa:68:9: note: #pragma message: Compiled
  • tests/.expect/operators.txt

    reef8dfb rbdfc032  
    1 done
  • tests/.expect/rational.txt

    reef8dfb rbdfc032  
    11constructor
    2 3/1 4/1 0/1 0/1 1/1
     23/1 4/1 0/1
    331/2 5/7
    442/3 -3/2
  • tests/.expect/result.txt

    reef8dfb rbdfc032  
    1 done
  • tests/.expect/stdincludes.txt

    reef8dfb rbdfc032  
    1 stdincludes.cfa: In function '_X4mainFi___1':
    2 stdincludes.cfa:52:9: note: #pragma message: Compiled
  • tests/.expect/switch.txt

    reef8dfb rbdfc032  
    1 switch.cfa: In function '_X4mainFi___1':
    2 switch.cfa:105:9: note: #pragma message: Compiled
  • tests/.expect/time.txt

    reef8dfb rbdfc032  
    1110800 2 3.375 12 1.00001
    2 0.125 0.0333333333333333 3.375 12000. 1000010.
    320 2 3.375
    437 7 7
  • tests/.expect/typedefRedef-ERR1.txt

    reef8dfb rbdfc032  
    11typedefRedef.cfa:4:1 error: Cannot redefine typedef: Foo
    2 typedefRedef.cfa:59:1 error: Cannot redefine typedef: ARR
     2typedefRedef.cfa:60:1 error: Cannot redefine typedef: ARR
  • tests/.expect/typedefRedef.txt

    reef8dfb rbdfc032  
    1 typedefRedef.cfa: In function '_X4mainFi___1':
    2 typedefRedef.cfa:71:9: note: #pragma message: Compiled
  • tests/.expect/typeof.txt

    reef8dfb rbdfc032  
    1 done
  • tests/.expect/variableDeclarator.txt

    reef8dfb rbdfc032  
    1 variableDeclarator.cfa: In function '_X4mainFi_iPPKc__1':
    2 variableDeclarator.cfa:182:9: note: #pragma message: Compiled
  • tests/.expect/voidPtr.txt

    reef8dfb rbdfc032  
    1 done
  • tests/.in/copyfile.txt

    reef8dfb rbdfc032  
    88//
    99// Author           : Peter A. Buhr
    10 // Created On       : Fri Jun 19 13:44:05 2020
     10// Created On       : Tue Jul 16 16:47:22 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 19 17:58:03 2020
    13 // Update Count     : 4
     12// Last Modified On : Wed Jul 17 18:04:44 2019
     13// Update Count     : 26
    1414//
    1515
    1616#include <fstream.hfa>
    17 #include <exception.hfa>
     17#include <stdlib.hfa>                                                                   // new/delete
    1818
    1919int main( int argc, char * argv[] ) {
    20         ifstream in  = stdin;                                                           // copy default files
    21         ofstream out = stdout;
    22 
     20        ifstream * in  = &stdin;                                                        // default files
     21        ofstream * out = &stdout;
    2322        try {
    2423                choose ( argc ) {
    2524                  case 2, 3:
    26                         open( in, argv[1] );                                            // open input file first as output creates file
    27                         if ( argc == 3 ) open( out, argv[2] );          // do not create output unless input opens
    28                   case 1: ;                                                                             // use default files
     25                          in = new( (const char *)argv[1] );            // open input file first as output creates file
     26                          if ( argc == 3 ) out = new( (const char *)argv[2] ); // only open output if input opens as output created if nonexistent
     27                  case 1: ;                                     // use default files
    2928                  default:
    30                         exit | "Usage" | argv[0] | "[ input-file (default stdin) [ output-file (default stdout) ] ]";
     29                          exit | "Usage [ input-file (default stdin) [ output-file (default stdout) ] ]";
    3130                } // choose
    32         } catch( Open_Failure * ex ; ex->istream == &in ) {
    33                 exit | "Unable to open input file" | argv[1];
    34         } catch( Open_Failure * ex ; ex->ostream == &out ) {
    35                 close( in );                                                                    // optional
    36                 exit | "Unable to open output file" | argv[2];
     31
     32                char ch;
     33                *out | nlOff;                                                                   // turn off auto newline
     34                *in  | nlOn;                                                                    // turn on reading newline
     35
     36                for () {                                                                                // read all characters
     37                        *in | ch;
     38                  if ( eof( *in ) ) break;                                              // eof ?
     39                        *out | ch;
     40                } // for
     41        } finally {
     42                if ( in  != &stdin  ) delete( in );                             // close file, do not delete stdin!
     43                if ( out != &stdout ) delete( out );                    // close file, do not delete stdout!
    3744        } // try
    38 
    39         out | nlOff;                                                                            // turn off auto newline
    40         in  | nlOn;                                                                                     // turn on reading newline
    41 
    42         char ch;
    43         for () {                                                                                        // read all characters
    44                 in | ch;
    45           if ( eof( in ) ) break;                                                       // eof ?
    46                 out | ch;
    47         } //for
    4845} // main
    4946
  • tests/.in/manipulatorsInput.txt

    reef8dfb rbdfc032  
    27273.5 3.5 3.456E+23.456E+2 -0x1.2p-3 3.5 0X1.23p3     3.5
    28283.5 3.5 3.456E+23.456E+2 -0x1.2p-3 3.5 0X1.23p3     3.5
    29 25 -25 42798
    30 1402432282 1505850196993244515
    31 394749758663249135511342
    32 12935154696204706112391834394
    33 
    34 423859149128410414395372834994551
    35 
    36 
    37 13889016598639747063234935497057631587
    38 170141183460469231731687303715884105727
    39 340282366920938463463374607431768211455
    40 -340282366920938463463374607431768211455
    41 340282366920938463463374607431768211455999
    42 1234567890123456789 -1234567890123456789
  • tests/Makefile.am

    reef8dfb rbdfc032  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Fri Oct  9 23:13:07 2020
    14 ## Update Count     : 86
     13## Last Modified On : Tue Nov 20 11:18:51 2018
     14## Update Count     : 68
    1515###############################################################################
    1616
     
    1818ACLOCAL_AMFLAGS  = -I automake
    1919
    20 include $(top_srcdir)/tools/build/cfa.make
    21 
    22 DEFAULT_INCLUDES = -I${abs_srcdir}
     20include $(top_srcdir)/src/cfa.make
    2321
    2422debug=yes
     
    3836# since automake doesn't have support for CFA we have to
    3937AM_CFLAGS = $(if $(test), 2> $(test), ) \
    40         -fdebug-prefix-map=$(abspath ${abs_srcdir})= \
    41         -fdebug-prefix-map=/tmp= \
    42         -fno-diagnostics-show-caret \
    4338        -g \
    4439        -Wall \
     
    4742        -DIN_DIR="${abs_srcdir}/.in/"
    4843
    49 AM_CFAFLAGS = -XCFA --deterministic-out
    50 
    5144# get the desired cfa to test
    5245TARGET_CFA = $(if $(filter $(installed),yes), @CFACC_INSTALL@, @CFACC@)
    5346
    5447# adjust CC to current flags
    55 CC = LC_ALL=C $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS} ${AST_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS} ${AST_FLAGS})
     48CC = $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
    5649CFACC = $(CC)
    5750
     
    6053
    6154# adjusted CC but without the actual distcc call
    62 CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS} ${AST_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS} ${AST_FLAGS})
    63 CFACCLINK = $(CFACCLOCAL) -quiet $(if $(test), 2> $(test), ) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g'))
     55CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
    6456
    6557PRETTY_PATH=mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
     
    6860.INTERMEDIATE: .validate .validate.cfa
    6961EXTRA_PROGRAMS = avl_test .dummy_hack # build but do not install
    70 EXTRA_DIST = test.py \
    71         pybin/__init__.py \
    72         pybin/print-core.gdb \
    73         pybin/settings.py \
    74         pybin/test_run.py \
    75         pybin/tools.py \
    76         long_tests.hfa \
    77         .in/io.data \
    78         avltree/avl.h \
    79         avltree/avl-private.h \
    80         concurrent/clib.c \
    81         exceptions/with-threads.hfa \
    82         exceptions/except-io.hfa
    83 
    84 dist-hook:
    85         echo "Gathering test files"
    86         for file in `${TEST_PY} --list-dist`; do \
    87                 if test -f ${srcdir}/$${file}; then \
    88                         $(MKDIR_P) $$(dirname ${distdir}/$${file}); \
    89                         cp -df ${srcdir}/$${file} ${distdir}/$${file}; \
    90                 fi; \
    91         done
    9262
    9363avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa
    9464# automake doesn't know we still need C/CPP rules so pretend like we have a C program
    95 nodist__dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp
     65_dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp
    9666
    9767#----------------------------------------------------------------------------------------------------------------
     
    10272        @+${TEST_PY} --debug=${debug} --install=${installed} --archive-errors=${archiveerrors} ${concurrent} ${timeouts} --all # '@' => do not echo command (SILENT), '+' => allows recursive make from within python program
    10373
    104 mostlyclean-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
     74clean-local :
    10875        rm -f ${EXTRA_PROGRAMS}
    109         rm -rf __pycache__
    110 
    111 distclean-local :
    112         find ${builddir} -path '*.Po' -delete
    11376
    11477list :
     
    143106% : %.cfa $(CFACCBIN)
    144107        $(CFACOMPILETEST) -c -o $(abspath ${@}).o
    145         $(CFACCLINK) ${@}.o -o $(abspath ${@})
    146         rm $(abspath ${@}).o
     108        $(CFACCLOCAL) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g')) $(abspath ${@}).o -o $(abspath ${@})
    147109
    148110# implicit rule for c++ test
     
    163125        $(CFACOMPILETEST) -CFA -XCFA -p -c -fsyntax-only -o $(abspath ${@})
    164126
     127# Use for tests where the make command is expected to succeed but the expected.txt should be compared to stderr
     128EXPECT_STDERR = builtins/sync warnings/self-assignment
     129$(EXPECT_STDERR): % : %.cfa $(CFACCBIN)
     130        $(CFACOMPILETEST) -c -fsyntax-only 2> $(abspath ${@})
     131
    165132#------------------------------------------------------------------------------
    166133# CUSTOM TARGET
    167134#------------------------------------------------------------------------------
    168 # tests that just validate syntax and compiler output should be compared to stderr
    169 CFACOMPILE_SYNTAX = $(CFACOMPILETEST) -Wno-unused-variable -Wno-unused-label -c -fsyntax-only -o $(abspath ${@})
    170 
    171 SYNTAX_ONLY_CODE = expression typedefRedef variableDeclarator switch numericConstants identFuncDeclarator forall \
    172         init1 limits nested-types stdincludes cast labelledExit array builtins/sync warnings/self-assignment
    173 $(SYNTAX_ONLY_CODE): % : %.cfa $(CFACCBIN)
    174         $(CFACOMPILE_SYNTAX)
    175         $(if $(test), cp $(test) $(abspath ${@}), )
    176 
    177135# expected failures
    178 # use custom target since they require a custom define *and* have a name that doesn't match the file
     136# use custom target since they require a custom define and custom dependencies
    179137alloc-ERROR : alloc.cfa $(CFACCBIN)
    180         $(CFACOMPILE_SYNTAX) -DERR1
    181         -cp $(test) $(abspath ${@})
    182 
    183 init1-ERROR : init1.cfa $(CFACCBIN)
    184         $(CFACOMPILE_SYNTAX) -DERR1
    185         -cp $(test) $(abspath ${@})
     138        $(CFACOMPILETEST) -DERR1 -c -fsyntax-only -o $(abspath ${@})
    186139
    187140typedefRedef-ERR1 : typedefRedef.cfa $(CFACCBIN)
    188         $(CFACOMPILE_SYNTAX) -DERR1
    189         -cp $(test) $(abspath ${@})
     141        $(CFACOMPILETEST) -DERR1 -c -fsyntax-only -o $(abspath ${@})
    190142
    191143nested-types-ERR1 : nested-types.cfa $(CFACCBIN)
    192         $(CFACOMPILE_SYNTAX) -DERR1
    193         -cp $(test) $(abspath ${@})
     144        $(CFACOMPILETEST) -DERR1 -c -fsyntax-only -o $(abspath ${@})
    194145
    195146nested-types-ERR2 : nested-types.cfa $(CFACCBIN)
    196         $(CFACOMPILE_SYNTAX) -DERR2
    197         -cp $(test) $(abspath ${@})
     147        $(CFACOMPILETEST) -DERR2 -c -fsyntax-only -o $(abspath ${@})
    198148
    199149raii/memberCtors-ERR1 : raii/memberCtors.cfa $(CFACCBIN)
    200         $(CFACOMPILE_SYNTAX) -DERR1
    201         -cp $(test) $(abspath ${@})
     150        $(CFACOMPILETEST) -DERR1 -c -fsyntax-only -o $(abspath ${@})
    202151
    203152raii/ctor-autogen-ERR1 : raii/ctor-autogen.cfa $(CFACCBIN)
    204         $(CFACOMPILE_SYNTAX) -DERR1
    205         -cp $(test) $(abspath ${@})
     153        $(CFACOMPILETEST) -DERR1 -c -fsyntax-only -o $(abspath ${@})
    206154
    207155raii/dtor-early-exit-ERR1 : raii/dtor-early-exit.cfa $(CFACCBIN)
    208         $(CFACOMPILE_SYNTAX) -DERR1
    209         -cp $(test) $(abspath ${@})
     156        $(CFACOMPILETEST) -DERR1 -c -fsyntax-only -o $(abspath ${@})
    210157
    211158raii/dtor-early-exit-ERR2 : raii/dtor-early-exit.cfa $(CFACCBIN)
    212         $(CFACOMPILE_SYNTAX) -DERR2
    213         -cp $(test) $(abspath ${@})
    214 
    215 # Exception Tests
    216 # Test with libcfathread; it changes how storage works.
    217 
    218 exceptions/%-threads : exceptions/%.cfa $(CFACCBIN)
    219         $(CFACOMPILETEST) -include exceptions/with-threads.hfa -c -o $(abspath ${@}).o
    220         $(CFACCLOCAL) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g')) $(abspath ${@}).o -o $(abspath ${@})
    221 
    222 # Linking tests
    223 # Meta tests to make sure we see linking errors (can't compile with -O2 since it may multiply number of calls)
    224 linking/linkerror : linking/linkerror.cfa $(CFACCBIN)
    225         $(CFACOMPILETEST) -O0 -c -o $(abspath ${@}).o
    226         $(CFACCLINK)  -O0 ${@}.o -o $(abspath ${@})
    227         rm $(abspath ${@}).o
     159        $(CFACOMPILETEST) -DERR2 -c -fsyntax-only -o $(abspath ${@})
    228160
    229161#------------------------------------------------------------------------------
  • tests/alloc.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed Feb  3 07:56:22 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Nov 12 10:02:18 2020
    13 // Update Count     : 432
     12// Last Modified On : Fri Nov 22 15:34:19 2019
     13// Update Count     : 404
    1414//
    1515
     
    2828        size_t dim = 10;
    2929        char fill = '\xde';
    30         int * ip, * ip1;
     30        int * p, * p1;
    3131
    3232        // allocation, non-array types
    3333
    34         ip = (int *)malloc( sizeof(*ip) );                                      // C malloc, type unsafe
    35         *ip = 0xdeadbeef;
    36         printf( "C   malloc %#x\n", *ip );
    37         free( ip );
    38 
    39         ip = malloc();                                                                          // CFA malloc, type safe
    40         *ip = 0xdeadbeef;
    41         printf( "CFA malloc %#x\n", *ip );
    42         free( ip );
    43 
    44         ip = alloc();                                                                           // CFA alloc, type safe
    45         *ip = 0xdeadbeef;
    46         printf( "CFA alloc %#x\n", *ip );
    47         free( ip );
    48 
    49         ip = alloc( fill`fill );                                                                // CFA alloc, fill
    50         printf( "CFA alloc, fill %08x\n", *ip );
    51         free( ip );
    52 
    53         ip = alloc( 3`fill );                                                           // CFA alloc, fill
    54         printf( "CFA alloc, fill %d\n", *ip );
    55         free( ip );
     34        p = (int *)malloc( sizeof(*p) );                                        // C malloc, type unsafe
     35        *p = 0xdeadbeef;
     36        printf( "C   malloc %#x\n", *p );
     37        free( p );
     38
     39        p = malloc();                                       // CFA malloc, type safe
     40        *p = 0xdeadbeef;
     41        printf( "CFA malloc %#x\n", *p );
     42        free( p );
     43
     44        p = alloc();                                        // CFA alloc, type safe
     45        *p = 0xdeadbeef;
     46        printf( "CFA alloc %#x\n", *p );
     47        free( p );
     48
     49        p = alloc_set( fill );                                                          // CFA alloc, fill
     50        printf( "CFA array alloc, fill %#hhx\n", fill );
     51        printf( "CFA alloc, fill %08x\n", *p );
     52        free( p );
     53
     54        p = alloc_set( 3 );                                                                     // CFA alloc, fill
     55        printf( "CFA alloc, fill %d\n", *p );
     56        free( p );
    5657
    5758
     
    5960        printf( "\n" );
    6061
    61         ip = (int *)calloc( dim, sizeof( *ip ) );                       // C array calloc, type unsafe
     62        p = (int *)calloc( dim, sizeof( *p ) );                         // C array calloc, type unsafe
    6263        printf( "C   array calloc, fill 0\n" );
    63         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    64         printf( "\n" );
    65         free( ip );
    66 
    67         ip = calloc( dim );                                                                     // CFA array calloc, type safe
     64        for ( i; dim ) { printf( "%#x ", p[i] ); }
     65        printf( "\n" );
     66        free( p );
     67
     68        p = calloc( dim );                                  // CFA array calloc, type safe
    6869        printf( "CFA array calloc, fill 0\n" );
    69         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    70         printf( "\n" );
    71         free( ip );
    72 
    73         ip = alloc( dim );                                                                      // CFA array alloc, type safe
    74         for ( i; dim ) { ip[i] = 0xdeadbeef; }
     70        for ( i; dim ) { printf( "%#x ", p[i] ); }
     71        printf( "\n" );
     72        free( p );
     73
     74        p = alloc( dim );                                   // CFA array alloc, type safe
     75        for ( i; dim ) { p[i] = 0xdeadbeef; }
    7576        printf( "CFA array alloc, no fill\n" );
    76         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    77         printf( "\n" );
    78         free( ip );
    79 
    80         ip = alloc( 2 * dim, fill`fill );                                       // CFA array alloc, fill
     77        for ( i; dim ) { printf( "%#x ", p[i] ); }
     78        printf( "\n" );
     79        free( p );
     80
     81        p = alloc_set( 2 * dim, fill );                                         // CFA array alloc, fill
    8182        printf( "CFA array alloc, fill %#hhx\n", fill );
    82         for ( i; 2 * dim ) { printf( "%#x ", ip[i] ); }
    83         printf( "\n" );
    84         free( ip );
    85 
    86         ip = alloc( 2 * dim, ((int)0xdeadbeef)`fill );                          // CFA array alloc, fill
     83        for ( i; 2 * dim ) { printf( "%#x ", p[i] ); }
     84        printf( "\n" );
     85        free( p );
     86
     87        p = alloc_set( 2 * dim, 0xdeadbeef );                           // CFA array alloc, fill
    8788        printf( "CFA array alloc, fill %#hhx\n", 0xdeadbeef );
    88         for ( i; 2 * dim ) { printf( "%#x ", ip[i] ); }
    89         printf( "\n" );
    90         // do not free
    91 
    92         ip1 = alloc( 2 * dim, [ip, 2 * dim]`fill );                             // CFA array alloc, fill
     89        for ( i; 2 * dim ) { printf( "%#x ", p[i] ); }
     90        printf( "\n" );
     91        // do not free
     92
     93        p1 = alloc_set( 2 * dim, p );                                           // CFA array alloc, fill
    9394        printf( "CFA array alloc, fill from array\n" );
    94         for ( i; 2 * dim ) { printf( "%#x %#x, ", ip[i], ip1[i] ); }
    95         free( ip1 );
    96         printf( "\n" );
    97 
    98 
    99         // realloc, non-array types
    100         printf( "\n" );
    101 
    102         ip = (int *)realloc( ip, dim * sizeof(*ip) );           // C realloc
     95        for ( i; 2 * dim ) { printf( "%#x %#x, ", p[i], p1[i] ); }
     96        free( p1 );
     97        printf( "\n" );
     98
     99
     100        // resize, non-array types
     101        printf( "\n" );
     102
     103        p = (int *)realloc( p, dim * sizeof(*p) );                      // C realloc
    103104        printf( "C realloc\n" );
    104         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    105         printf( "\n" );
    106         // do not free
    107 
    108         ip = realloc( ip, 2 * dim * sizeof(*ip) );                      // CFA realloc
    109         for ( i; dim ~ 2 * dim ) { ip[i] = 0x1010101; }
     105        for ( i; dim ) { printf( "%#x ", p[i] ); }
     106        printf( "\n" );
     107        // do not free
     108
     109        p = realloc( p, 2 * dim * sizeof(*p) );             // CFA realloc
     110        for ( i; dim ~ 2 * dim ) { p[i] = 0x1010101; }
    110111        printf( "CFA realloc\n" );
    111         for ( i; 2 * dim ) { printf( "%#x ", ip[i] ); }
    112         printf( "\n" );
    113         // do not free
    114 
    115 
    116         // realloc, array types
    117         printf( "\n" );
    118 
    119         ip = alloc( dim, ip`realloc );                                                          // CFA realloc array alloc
    120         for ( i; dim ) { ip[i] = 0xdeadbeef; }
    121         printf( "CFA realloc array alloc\n" );
    122         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    123         printf( "\n" );
    124         // do not free
    125 
    126         ip = alloc( 2 * dim, ip`realloc );                                                      // CFA realloc array alloc
    127         for ( i; dim ~ 2 * dim ) { ip[i] = 0x1010101; }         // fill upper part
    128         printf( "CFA realloc array alloc\n" );
    129         for ( i; 2 * dim ) { printf( "%#x ", ip[i] ); }
    130         printf( "\n" );
    131         // do not free
    132 
    133         ip = alloc( dim, ip`realloc );                                                          // CFA realloc array alloc
    134         printf( "CFA realloc array alloc\n" );
    135         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    136         printf( "\n" );
    137         // do not free
    138 
    139         ip = alloc( 3 * dim, ip`realloc, fill`fill );                           // CFA realloc array alloc, fill
    140         printf( "CFA realloc array alloc, fill\n" );
    141         for ( i; 3 * dim ) { printf( "%#x ", ip[i] ); }
    142         printf( "\n" );
    143         // do not free
    144 
    145         ip = alloc( dim, ip`realloc, fill`fill );                                       // CFA realloc array alloc, fill
    146         printf( "CFA realloc array alloc, fill\n" );
    147         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    148         printf( "\n" );
    149         // do not free
    150 
    151         ip = alloc( 3 * dim, ip`realloc, fill`fill );                           // CFA realloc array alloc, fill
    152         printf( "CFA realloc array alloc, fill\n" );
    153         for ( i; 3 * dim ) { printf( "%#x ", ip[i] ); }
    154         printf( "\n" );
    155         // do not free
    156 #if 0 // FIX ME
    157         ip = alloc( 5 * dim, ip`realloc, 5`fill );                                      // CFA realloc array alloc, 5
    158         printf( "CFA realloc array alloc, 5\n" );
    159         for ( i; 5 * dim ) { printf( "%#x ", ip[i] ); }
    160         printf( "\n" );
    161         // do not free
    162 
    163         ip = alloc( dim, ip`realloc, 5`fill );                                          // CFA realloc array alloc, 5
    164         printf( "CFA realloc array alloc, 5\n" );
    165         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    166         printf( "\n" );
    167         // do not free
    168 
    169         ip = alloc( 5 * dim, ip`realloc, 5`fill );                                      // CFA realloc array alloc, 5
    170         printf( "CFA realloc array alloc, 5\n" );
    171         for ( i; 5 * dim ) { printf( "%#x ", ip[i] ); }
    172         printf( "\n" );
    173 #endif // 0
    174         free( ip );
    175 
    176         // resize, non-array types
    177 
    178         struct S {
    179                 int a[5];
    180         };
    181 
    182     ip = alloc();
    183         *ip = 5;
    184     double * dp = alloc( ip`resize );
    185         *dp = 5.5;
    186     S * sp = alloc( dp`resize );
    187         *sp = (S){ {0, 1, 2, 3, 4} };
    188     ip = alloc( sp`resize );
    189         *ip = 3;
    190     free( ip );
     112        for ( i; 2 * dim ) { printf( "%#x ", p[i] ); }
     113        printf( "\n" );
     114        // do not free
    191115
    192116
    193117        // resize, array types
    194 
    195     ip = alloc( 5 );
    196         for ( i; 5 ) { ip[i] = 5; }
    197     dp = alloc( 5, ip`resize );
    198         for ( i; 5 ) { dp[i] = 5.5; }
    199     sp = alloc( 5, dp`resize );
    200         for ( i; 5 ) { sp[i] = (S){ {0, 1, 2, 3, 4} }; }
    201     ip = alloc( 3, sp`resize );
    202         for ( i; 3 ) { ip[i] = 3; }
    203     ip = alloc( 7, ip`realloc );
    204         for ( i; 7 ) { ip[i] = 7; }
    205     ip = alloc( 7, ip`resize );
    206         for ( i; 7 ) { ip[i] = 7; }
    207     free( ip );
    208 
    209 
    210         int const_count, dest_count;
     118        printf( "\n" );
     119
     120        p = alloc( p, dim );                                // CFA resize array alloc
     121        for ( i; dim ) { p[i] = 0xdeadbeef; }
     122        printf( "CFA resize array alloc\n" );
     123        for ( i; dim ) { printf( "%#x ", p[i] ); }
     124        printf( "\n" );
     125        // do not free
     126
     127        p = alloc( p, 2 * dim );                            // CFA resize array alloc
     128        for ( i; dim ~ 2 * dim ) { p[i] = 0x1010101; }          // fill upper part
     129        printf( "CFA resize array alloc\n" );
     130        for ( i; 2 * dim ) { printf( "%#x ", p[i] ); }
     131        printf( "\n" );
     132        // do not free
     133
     134        p = alloc( p, dim );                                // CFA resize array alloc
     135        printf( "CFA resize array alloc\n" );
     136        for ( i; dim ) { printf( "%#x ", p[i] ); }
     137        printf( "\n" );
     138        // do not free
     139
     140        p = alloc_set( p, 3 * dim, fill );                                      // CFA resize array alloc, fill
     141        printf( "CFA resize array alloc\n" );
     142        for ( i; 3 * dim ) { printf( "%#x ", p[i] ); }
     143        printf( "\n" );
     144        // do not free
     145
     146        p = alloc_set( p, dim, fill );                                          // CFA resize array alloc, fill
     147        printf( "CFA resize array alloc\n" );
     148        for ( i; dim ) { printf( "%#x ", p[i] ); }
     149        printf( "\n" );
     150        // do not free
     151
     152        p = alloc_set( p, 3 * dim, fill );                                      // CFA resize array alloc, fill
     153        printf( "CFA resize array alloc, fill\n" );
     154        for ( i; 3 * dim ) { printf( "%#x ", p[i] );; }
     155        printf( "\n" );
     156        free( p );
     157
     158
    211159        struct Struct { int x; double y; };
    212         void  ?{}( Struct & a ) {                                       // construct
    213                 a.[ x, y ] = [ -1, -1.0 ];
    214         }
    215         void  ?{}( Struct & a, int x, double y ) {      // initialize
    216                 a.[ x, y ] = [ x, y ];
    217                 const_count++;
    218         }
    219         void ^?{}( Struct & a ) {  dest_count++; }      // destruct
    220160        Struct st, st1, sta[dim], sta1[dim], * stp, * stp1;
    221161
     
    229169        free( stp );
    230170
    231         stp = &(*memalign( Alignment )){ 42, 42.5 };            // CFA memalign
     171        stp = &(*memalign( Alignment )){ 42, 42.5 };          // CFA memalign
    232172        assert( (uintptr_t)stp % Alignment == 0 );
    233173        printf( "CFA memalign %d %g\n", stp->x, stp->y );
     
    246186        free( stp );
    247187
    248         stp = &(*alloc( Alignment`align)){ 42, 42.5 };          // CFA alloc_align
     188        stp = &(*alloc_align( Alignment)){ 42, 42.5 };          // CFA alloc_align
    249189        assert( (uintptr_t)stp % Alignment == 0 );
    250190        printf( "CFA alloc_align %d %g\n", stp->x, stp->y );
    251191        free( stp );
    252192
    253         stp = &(*alloc( Alignment`align )){ 42, 42.5 };         // CFA alloc_align
     193        stp = &(*alloc_align( Alignment )){ 42, 42.5 };         // CFA alloc_align
    254194        assert( (uintptr_t)stp % Alignment == 0 );
    255195        printf( "CFA alloc_align %d %g\n", stp->x, stp->y );
    256196        free( stp );
    257197
    258         stp = alloc( Alignment`align, fill`fill );                      // CFA memalign, fill
     198        stp = alloc_align_set( Alignment, fill );                       // CFA memalign, fill
    259199        assert( (uintptr_t)stp % Alignment == 0 );
    260200        printf( "CFA alloc_align fill %#x %a\n", stp->x, stp->y );
    261201        free( stp );
    262202
    263         stp = alloc( Alignment`align, (Struct){ 42, 42.5 }`fill ); // CFA memalign, fill
     203        stp = alloc_align_set( Alignment, (Struct){ 42, 42.5 } ); // CFA memalign, fill
    264204        assert( (uintptr_t)stp % Alignment == 0 );
    265205        printf( "CFA alloc_align fill %d %g\n", stp->x, stp->y );
    266206        // do not free
    267207
    268         stp = &(*alloc( stp`realloc, 4096`align )){ 42, 42.5 };         // CFA realign
     208        stp = &(*alloc_align( stp, 4096 )){ 42, 42.5 };         // CFA realign
    269209        assert( (uintptr_t)stp % 4096 == 0 );
    270210        printf( "CFA alloc_align %d %g\n", stp->x, stp->y );
     
    275215        printf( "\n" );
    276216
    277         stp = alloc( dim, Alignment`align );                // CFA array memalign
     217        stp = alloc_align( Alignment, dim );                // CFA array memalign
    278218        assert( (uintptr_t)stp % Alignment == 0 );
    279219        for ( i; dim ) { stp[i] = (Struct){ 42, 42.5 }; }
     
    283223        free( stp );
    284224
    285         stp = alloc( dim, Alignment`align, fill`fill );         // CFA array memalign, fill
     225        stp = alloc_align_set( Alignment, dim, fill );          // CFA array memalign, fill
    286226        assert( (uintptr_t)stp % Alignment == 0 );
    287227        printf( "CFA array alloc_align, fill\n" );
     
    290230        free( stp );
    291231
    292         stp = alloc( dim, Alignment`align, ((Struct){ 42, 42.5 })`fill ); // CFA array memalign, fill
     232        stp = alloc_align_set( Alignment, dim, (Struct){ 42, 42.5 } ); // CFA array memalign, fill
    293233        assert( (uintptr_t)stp % Alignment == 0 );
    294234        printf( "CFA array alloc_align, fill\n" );
     
    297237        // do not free
    298238
    299         stp1 = alloc( dim, Alignment`align, [stp, dim]`fill );  // CFA array memalign, fill
     239        stp1 = alloc_align_set( Alignment, dim, stp );          // CFA array memalign, fill
    300240        assert( (uintptr_t)stp % Alignment == 0 );
    301241        printf( "CFA array alloc_align, fill array\n" );
     
    304244        free( stp1 );
    305245
    306         stp = alloc( dim, stp`realloc, 4096`align );                            // CFA aligned realloc array
     246        stp = alloc_align( stp, 4096, dim );                            // CFA aligned realloc array
    307247        assert( (uintptr_t)stp % 4096 == 0 );
    308248        for ( i; dim ) { stp[i] = (Struct){ 42, 42.5 }; }
     
    335275        printf( "\n" );
    336276
     277
    337278        // new, non-array types
    338279        printf( "\n" );
    339280
    340         const_count = dest_count = 0;
    341281        stp = new( 42, 42.5 );
    342         assert( const_count == 1 && dest_count == 0 );                                          // assertion for testing
    343282        stp1 = new( 42, 42.5 );
    344         assert( const_count == 2 && dest_count == 0 );                                          // assertion for testing
    345 
    346283        printf( "CFA new initialize\n%d %g %d %g\n", stp->x, stp->y, stp1->x, stp1->y );
    347284        delete( stp, stp1 );
    348         assert( const_count == 2 && dest_count == 2 );                                          // assertion for testing
    349285
    350286        // new, array types
    351287        stp = anew( dim, 42, 42.5 );
    352         assert( const_count == 2 + dim && dest_count == 2 );                            // assertion for testing
    353288        printf( "CFA array new initialize\n" );
    354289        for ( i; dim ) { printf( "%d %g, ", stp[i].x, stp[i].y ); }
    355290        printf( "\n" );
    356 
    357291        stp1 = anew( dim, 42, 42.5 );
    358         assert( const_count == 2 + 2 * dim && dest_count == 2 );                        // assertion for testing
    359292        for ( i; dim ) { printf( "%d %g, ", stp1[i].x, stp1[i].y ); }
    360293        printf( "\n" );
    361         adelete( stp, stp1 );
    362         assert( const_count == 2 + 2 * dim && dest_count == 2 + 2 * dim);       // assertion for testing
     294        adelete( dim, stp, dim, stp1 );
    363295
    364296        // extras
     
    369301        free( fp - 1 );
    370302
    371         ip = foo( bar( baz( malloc(), 0 ), 0 ), 0 );
    372         *ip = 0xdeadbeef;
    373         printf( "CFA deep malloc %#x\n", *ip );
    374 
    375         dp = alloc(5.0`fill); // just for testing multiple free
    376         assert(*dp == 5.0);
    377         free( ip, dp, 0p );
     303        p = foo( bar( baz( malloc(), 0 ), 0 ), 0 );
     304        *p = 0xdeadbeef;
     305        printf( "CFA deep malloc %#x\n", *p );
     306        free( p );
    378307
    379308#ifdef ERR1
    380309        stp = malloc();
    381310        printf( "\nSHOULD FAIL\n" );
    382         ip = realloc( stp, dim * sizeof( *stp ) );
    383         ip = memset( stp, 10 );
    384         ip = memcpy( &st1, &st );
    385 #endif // ERR1
     311        p = realloc( stp, dim * sizeof( *stp ) );
     312        p = alloc( stp, dim * sizeof( *stp ) );
     313        p = memset( stp, 10 );
     314        p = memcpy( &st1, &st );
     315#endif
    386316} // main
    387317
  • tests/array.cfa

    reef8dfb rbdfc032  
    1 //                               -*- Mode: C -*-
    2 //
     1//                               -*- Mode: C -*- 
     2// 
    33// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
    44//
    55// The contents of this file are covered under the licence agreement in the
    66// file "LICENCE" distributed with Cforall.
    7 //
     7// 
    88// array.cfa -- test array declarations
    9 //
     9// 
    1010// Author           : Peter A. Buhr
    1111// Created On       : Tue Feb 19 21:18:06 2019
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Sun Sep 27 09:05:40 2020
    14 // Update Count     : 4
    15 //
     13// Last Modified On : Tue Feb 19 21:18:46 2019
     14// Update Count     : 1
     15// 
    1616
    17 int a1[0];
     17int a1[];
    1818//int a2[*];
    1919//double a4[3.0];
    2020
    21 int m1[0][3];
     21int m1[][3];
    2222//int m2[*][*];
    2323int m4[3][3];
     
    4949}
    5050
    51 int main() {
    52         #if !defined(NO_COMPILED_PRAGMA)
    53                 #pragma message( "Compiled" )   // force non-empty .expect file
    54         #endif
    55 }
     51int main() {}
    5652
    5753// Local Variables: //
  • tests/avltree/avl1.cfa

    reef8dfb rbdfc032  
    2424tree(K, V) * create(K key, V value) {
    2525  // infinite loop trying to resolve ... t = malloc();
    26   tree(K, V) * t = ( tree(K, V) * ) malloc(sizeof(tree(K,V)));
     26  tree(K, V) * t = malloc(sizeof(tree(K,V)));
    2727  (*t){ key, value };
    2828  return t;
  • tests/builtins/.expect/sync.txt

    reef8dfb rbdfc032  
    1 builtins/sync.cfa: In function '_X4mainFi___1':
    2 builtins/sync.cfa:358:9: note: #pragma message: Compiled
  • tests/builtins/sync.cfa

    reef8dfb rbdfc032  
    6666        #if defined(__SIZEOF_INT128__)
    6767        { __int128 ret; ret = __sync_fetch_and_nand(vplll, vlll); }
     68        { __int128 ret; ret = __sync_fetch_and_nand_16(vplll, vlll); }
    6869        #endif
    6970
     
    354355
    355356int main() {
    356         #pragma message( "Compiled" )                   // force non-empty .expect file
     357        return 0;
    357358}
  • tests/cast.cfa

    reef8dfb rbdfc032  
    1313
    1414//Dummy main
    15 int main( int argc, char const * argv[] ) {
    16         #pragma message( "Compiled" )                   // force non-empty .expect file
     15int main(int argc, char const *argv[])
     16{
     17        return 0;
    1718}
  • tests/castError.cfa

    reef8dfb rbdfc032  
    1414//
    1515
    16 forall(otype T) struct S { T p; };
    1716int f;
    18 S(int) sint;
    1917
    2018void f() {
     
    2725        short int v;
    2826        3, v;           // implicit void cast
    29 
    30         (S(char)) sint;
    3127}
    3228
  • tests/complex.cfa

    reef8dfb rbdfc032  
    1414//
    1515
     16#include <stdio.h>
    1617#include <complex.h>
    1718#ifdef __CFA__
  • tests/concurrent/.expect/monitor.txt

    reef8dfb rbdfc032  
    1 3000000
     14000000
  • tests/concurrent/coroutineYield.cfa

    reef8dfb rbdfc032  
    3333                        sout | "Coroutine 2";
    3434                #endif
    35                 suspend;
     35                suspend();
    3636        }
    3737}
  • tests/concurrent/examples/.expect/datingService.txt

    reef8dfb rbdfc032  
    1 done
     1Girl:17 is dating Boy at 2 with ccode 17
     2 Boy:2 is dating Girl 17 with ccode 17
     3 Boy:14 is dating Girl 5 with ccode 5
     4Girl:5 is dating Boy at 14 with ccode 5
     5 Boy:9 is dating Girl 10 with ccode 10
     6Girl:10 is dating Boy at 9 with ccode 10
     7 Boy:1 is dating Girl 18 with ccode 18
     8Girl:18 is dating Boy at 1 with ccode 18
     9 Boy:16 is dating Girl 3 with ccode 3
     10Girl:3 is dating Boy at 16 with ccode 3
     11 Boy:5 is dating Girl 14 with ccode 14
     12Girl:14 is dating Boy at 5 with ccode 14
     13 Boy:15 is dating Girl 4 with ccode 4
     14Girl:4 is dating Boy at 15 with ccode 4
     15Girl:0 is dating Boy at 19 with ccode 0
     16 Boy:19 is dating Girl 0 with ccode 0
     17Girl:9 is dating Boy at 10 with ccode 9
     18 Boy:10 is dating Girl 9 with ccode 9
     19Girl:11 is dating Boy at 8 with ccode 11
     20 Boy:8 is dating Girl 11 with ccode 11
     21 Boy:12 is dating Girl 7 with ccode 7
     22Girl:7 is dating Boy at 12 with ccode 7
     23 Boy:11 is dating Girl 8 with ccode 8
     24Girl:8 is dating Boy at 11 with ccode 8
     25Girl:16 is dating Boy at 3 with ccode 16
     26 Boy:3 is dating Girl 16 with ccode 16
     27Girl:15 is dating Boy at 4 with ccode 15
     28 Boy:4 is dating Girl 15 with ccode 15
     29Girl:19 is dating Boy at 0 with ccode 19
     30 Boy:0 is dating Girl 19 with ccode 19
     31Girl:2 is dating Boy at 17 with ccode 2
     32 Boy:17 is dating Girl 2 with ccode 2
     33 Boy:13 is dating Girl 6 with ccode 6
     34Girl:6 is dating Boy at 13 with ccode 6
     35 Boy:7 is dating Girl 12 with ccode 12
     36Girl:12 is dating Boy at 7 with ccode 12
     37Girl:13 is dating Boy at 6 with ccode 13
     38 Boy:6 is dating Girl 13 with ccode 13
     39Girl:1 is dating Boy at 18 with ccode 1
     40 Boy:18 is dating Girl 1 with ccode 1
  • tests/concurrent/examples/boundedBufferEXT.cfa

    reef8dfb rbdfc032  
    11//
    22// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
    3 //
     3// 
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
     
    8787}
    8888
    89 enum { Prods = 4, Cons = 5 };
    90 Producer * prods[Prods];
    91 Consumer * cons[Cons];
    92 
    9389int main() {
    9490        Buffer(int) buffer;
     91        enum { Prods = 4, Cons = 5 };
     92        Producer * prods[Prods];
     93        Consumer * cons[Cons];
    9594        int sums[Cons];
    9695        int i;
  • tests/concurrent/examples/datingService.cfa

    reef8dfb rbdfc032  
    11//
    22// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    3 //
     3// 
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
     
    1010// Created On       : Mon Oct 30 12:56:20 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 15:42:25 2020
    13 // Update Count     : 40
     12// Last Modified On : Fri Jun 21 11:32:34 2019
     13// Update Count     : 38
    1414//
    1515
     
    3535                signal_block( Boys[ccode] );                                    // restart boy to set phone number
    3636        } // if
    37         // sout | "Girl:" | PhoneNo | "is dating Boy at" | BoyPhoneNo | "with ccode" | ccode;
     37        sout | "Girl:" | PhoneNo | "is dating Boy at" | BoyPhoneNo | "with ccode" | ccode;
    3838        return BoyPhoneNo;
    3939} // DatingService girl
     
    4747                signal_block( Girls[ccode] );                                   // restart girl to set phone number
    4848        } // if
    49         // sout | " Boy:" | PhoneNo | "is dating Girl" | GirlPhoneNo | "with ccode" | ccode;
     49        sout | " Boy:" | PhoneNo | "is dating Girl" | GirlPhoneNo | "with ccode" | ccode;
    5050        return GirlPhoneNo;
    5151} // DatingService boy
     
    108108                if ( girlck[ boyck[i] ] != boyck[ girlck[i] ] ) abort();
    109109        } // for
    110 
    111         printf( "done\n" );                                                                     // non-empty .expect file
    112110} // main
    113111
  • tests/concurrent/examples/quickSort.cfa

    reef8dfb rbdfc032  
    1111// Created On       : Wed Dec  6 12:15:52 2017
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Wed Feb 12 18:24:47 2020
    14 // Update Count     : 177
     13// Last Modified On : Thu Oct 10 13:58:18 2019
     14// Update Count     : 176
    1515//
    1616
     
    2727
    2828void ?{}( Quicksort & qs, int values[], int size, int depth ) {
    29         qs.[values, low, high, depth] = [values, 0, size, depth];
     29        qs.values = values;  qs.low = 0;  qs.high = size;  qs.depth = depth;
    3030} // Quicksort
    3131
     
    167167                        values[counter] = size - counter;                       // descending values
    168168                } // for
    169                 for ( i; 200 ) {                                                                // random shuffle a few values
     169                for ( int i = 0; i < 200; i +=1 ) {                             // random shuffle a few values
    170170                        swap( values[rand() % size], values[rand() % size] );
    171171                } // for
  • tests/concurrent/monitor.cfa

    reef8dfb rbdfc032  
    2929
    3030void main( MyThread & this ) {
    31         for(int i = 0; i < 750_000; i++) {
     31        for(int i = 0; i < 1_000_000; i++) {
    3232                increment( global );
    3333        }
  • tests/concurrent/multi-monitor.cfa

    reef8dfb rbdfc032  
    1111
    1212void increment( monitor_t & mutex p1, monitor_t & mutex p2, int & value ) {
    13         assert(active_thread() == get_monitor(p1)->owner);
    14         assert(active_thread() == get_monitor(p2)->owner);
    1513        value += 1;
    16         assert(active_thread() == get_monitor(p1)->owner);
    17         assert(active_thread() == get_monitor(p2)->owner);
    1814}
    1915
  • tests/concurrent/signal/block.cfa

    reef8dfb rbdfc032  
    3333
    3434monitor global_data_t {
    35         $thread * last_thread;
    36         $thread * last_signaller;
     35        thread_desc * last_thread;
     36        thread_desc * last_signaller;
    3737};
    3838
     
    8282        if( !is_empty( cond ) ) {
    8383
    84                 $thread * next = ( $thread * ) front( cond );
     84                thread_desc * next = front( cond );
    8585
    8686                if( ! signal_block( cond ) ) {
  • tests/concurrent/signal/disjoint.cfa

    reef8dfb rbdfc032  
    2121#endif
    2222
    23 // This tests checks what happens when someone barges in the midle of the release
    24 // of a bulk of monitors.
    25 
    2623enum state_t { WAIT, SIGNAL, BARGE };
    2724
    2825monitor global_t {};
     26global_t mut;
    2927
    3028monitor global_data_t;
     
    3533        int counter;
    3634        state_t state;
    37 };
    38 
    39 // Use a global struct because the order needs to match with Signaller thread
    40 struct {
    41         global_t mut;
    42         global_data_t data;
    43 } globals;
     35} data;
    4436
    4537condition cond;
     
    4840
    4941void ?{}( global_data_t & this ) {
    50         this.counter = 0;
     42        this.counter == 0;
    5143        this.state = BARGE;
    5244}
     
    6153
    6254thread Barger {};
    63 void ?{}( Barger & this ) {
    64         ((thread&)this){ "Barger Thread" };
    65 }
    6655
    6756void main( Barger & this ) {
    6857        while( !all_done ) {
    69                 barge( globals.data );
     58                barge( data );
    7059                yield();
    7160        }
     
    8978
    9079thread Waiter {};
    91 void ?{}( Waiter & this ) {
    92         ((thread&)this){ "Waiter Thread" };
    93 }
    9480
    9581void main( Waiter & this ) {
    96         while( wait( globals.mut, globals.data ) ) { KICK_WATCHDOG; yield(); }
     82        while( wait( mut, data ) ) { KICK_WATCHDOG; yield(); }
    9783}
    9884
     
    10692
    10793void logic( global_t & mutex a ) {
    108         signal( cond, a, globals.data );
     94        signal( cond, a, data );
    10995
    11096        yield( random( 10 ) );
    11197
    11298        //This is technically a mutual exclusion violation but the mutex monitor protects us
    113         bool running = TEST(globals.data.counter < N) && globals.data.counter > 0;
    114         if( globals.data.state != SIGNAL && running ) {
    115                 sout | "ERROR Eager signal" | globals.data.state;
     99        bool running = TEST(data.counter < N) && data.counter > 0;
     100        if( data.state != SIGNAL && running ) {
     101                sout | "ERROR Eager signal" | data.state;
    116102        }
    117103}
    118104
    119105thread Signaller {};
    120 void ?{}( Signaller & this ) {
    121         ((thread&)this){ "Signaller Thread" };
    122 }
    123106
    124107void main( Signaller & this ) {
    125108        while( !all_done ) {
    126                 logic( globals.mut );
     109                logic( mut );
    127110                yield();
    128111        }
  • tests/concurrent/waitfor/when.cfa

    reef8dfb rbdfc032  
    5757
    5858void arbiter( global_t & mutex this ) {
    59         // There is a race at start where callers can get in before the arbiter.
    60         // It doesn't really matter here so just restart the loop correctly and move on
    61         this.last_call = 6;
    62 
    6359        for( int i = 0; i < N; i++ ) {
    6460                   when( this.last_call == 6 ) waitfor( call1 : this ) { if( this.last_call != 1) { serr | "Expected last_call to be 1 got" | this.last_call; } }
  • tests/config.py.in

    reef8dfb rbdfc032  
    99HOSTARCH = "@host_cpu@"
    1010DISTRIBUTE = @HAS_DISTCC@
    11 NEWAST = @DEFAULT_NEW_AST@
  • tests/copyfile.cfa

    reef8dfb rbdfc032  
    88//
    99// Author           : Peter A. Buhr
    10 // Created On       : Fri Jun 19 13:44:05 2020
     10// Created On       : Tue Jul 16 16:47:22 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 15 15:00:48 2020
    13 // Update Count     : 6
     12// Last Modified On : Wed Jul 17 18:04:44 2019
     13// Update Count     : 26
    1414//
    1515
    1616#include <fstream.hfa>
    17 #include <exception.hfa>
     17#include <stdlib.hfa>                                                                   // new/delete
    1818
    1919int main( int argc, char * argv[] ) {
    20         ifstream in  = stdin;                                                           // copy default files
    21         ofstream out = stdout;
     20        ifstream * in  = &stdin;                                                        // default files
     21        ofstream * out = &stdout;
     22        try {
     23                choose ( argc ) {
     24                  case 2, 3:
     25                          in = new( (const char *)argv[1] );            // open input file first as output creates file
     26                          if ( argc == 3 ) out = new( (const char *)argv[2] ); // only open output if input opens as output created if nonexistent
     27                  case 1: ;                                     // use default files
     28                  default:
     29                          exit | "Usage [ input-file (default stdin) [ output-file (default stdout) ] ]";
     30                } // choose
    2231
    23         try {
    24                 choose ( argc ) {                                                               // terminate if command-line errors
    25                   case 2, 3:
    26                         open( in, argv[1] );                                            // open input file first as output creates file
    27                         if ( argc == 3 ) open( out, argv[2] );          // do not create output unless input opens
    28                   case 1: ;                                                                             // use default files
    29                   default:                                                                              // wrong number of options
    30                         exit | "Usage" | argv[0] | "[ input-file (default stdin) [ output-file (default stdout) ] ]";
    31                 } // choose
    32         } catch( Open_Failure * ex ; ex->istream == &in ) {
    33                 exit | "Unable to open input file" | argv[1];
    34         } catch( Open_Failure * ex ; ex->ostream == &out ) {
    35                 close( in );                                                                    // optional
    36                 exit | "Unable to open output file" | argv[2];
     32                char ch;
     33                *out | nlOff;                                                                   // turn off auto newline
     34                *in  | nlOn;                                                                    // turn on reading newline
     35
     36                for () {                                                                                // read all characters
     37                        *in | ch;
     38                  if ( eof( *in ) ) break;                                              // eof ?
     39                        *out | ch;
     40                } // for
     41        } finally {
     42                if ( in  != &stdin  ) delete( in );                             // close file, do not delete stdin!
     43                if ( out != &stdout ) delete( out );                    // close file, do not delete stdout!
    3744        } // try
    38 
    39         out | nlOff;                                                                            // turn off auto newline
    40         in  | nlOn;                                                                                     // turn on reading newline
    41 
    42         char ch;
    43         for () {                                                                                        // read all characters
    44                 in | ch;
    45           if ( eof( in ) ) break;                                                       // eof ?
    46                 out | ch;
    47         } // for
    4845} // main
    4946
  • tests/coroutine/.expect/fmtLines.txt

    reef8dfb rbdfc032  
    4848{                                                         // f  or n  ewli 
    4949ne c  hara  cter  s                                     su 
    50 spen  d;                                        i  f (   fmt. 
    51 ch !  = '\  n' )   bre  ak;      
    52         //   igno  re n  ewli  ne                
    53                 }   // f  or                            so  ut | 
    54  fmt  .ch;                                                      /  / pr 
    55 int   char  acte  r                       } // 
    56  for                    s  out   | "    ";       
    57                                                         /  / pr  int   bloc 
    58 k se  para  tor         } /  / fo 
    59 r               s  out   | nl  ;                                                         
    60                 //   pri  nt g  roup   sep 
    61 arat  or        }   //   for}   //  
    62 main  void   prt  ( Fo  rmat 
    63  & f  mt,   char   ch   ) {   
    64    f  mt.c  h =   ch;      r 
    65 esum  e( f  mt )  ;} /  / pr 
    66 tint   mai  n()   {     Fo  rmat 
    67  fmt  ; ch  ar c  h;    f  or ( 
    68  ;;   ) {               sin   | c  h;            
    69                                                                   // r  ead   one  
    70 char  acte  r       if (   eof 
    71 ( si  n )   ) br  eak;                                   
    72                         /  / eo  f ?            prt  ( fm 
    73 t, c  h );      } /  / fo  r} / 
    74 / ma  in//   Loc  al V  aria 
    75 bles  : //  // t  ab-w  idth 
    76 : 4   ////   com  pile  -com 
    77 mand  : "c  fa f  mtLi  nes. 
    78 cfa"   ///  / En  d: /  /
     50spen  d();                                      if   ( fm 
     51t.ch   !=   '\n'   ) b  reak 
     52;               /  / ig  nore   new  line 
     53                                  } //   for                              sout 
     54 | f  mt.c  h;                                                  //  
     55prin  t ch  arac  ter                   }  
     56// f  or                        sou  t |   "  " 
     57;                                                               //   prin  t bl 
     58ock   sepa  rato  r             }   //  
     59for             sou  t |   nl;                                   
     60                                  // p  rint   gro  up s 
     61epar  ator      } /  / fo  r} / 
     62/ ma  invo  id p  rt(   Form 
     63at &   fmt  , ch  ar c  h )   
     64{      fmt  .ch   = ch  ;    
     65 res  ume(   fmt   );}   //  
     66prti  nt m  ain(  ) {     Form 
     67at f  mt;         char   ch;    for 
     68 ( ;  ; )   {           s  in |   ch; 
     69                                                                                //   rea  d on 
     70e ch  arac  ter     if   ( e 
     71of(   sin   ) )   brea  k;               
     72                                        //   eof   ?            p  rt(  
     73fmt,   ch   );  }   //   for} 
     74 //   main  // L  ocal   Var 
     75iabl  es:   ////   tab  -wid 
     76th:   4 //  // c  ompi  le-c 
     77omma  nd:   "cfa   fmt  Line 
     78s.cf  a" /  ///   End:   //
  • tests/coroutine/.in/fmtLines.txt

    reef8dfb rbdfc032  
    3535                        for ( fmt.b = 0; fmt.b < 4; fmt.b += 1 ) {      // blocks of 4 characters
    3636                                for ( ;; ) {                                                    // for newline characters
    37                                         suspend;
     37                                        suspend();
    3838                                        if ( fmt.ch != '\n' ) break;            // ignore newline
    3939                                } // for
  • tests/coroutine/cntparens.cfa

    reef8dfb rbdfc032  
    1 //
     1// 
    22// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    33//
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    6 //
     6// 
    77// cntparens.cfa -- match left/right parenthesis
    8 //
     8// 
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Apr 20 11:04:45 2019
     
    1212// Last Modified On : Sat Apr 20 11:06:21 2019
    1313// Update Count     : 1
    14 //
     14// 
    1515
    1616#include <fstream.hfa>
     
    2626void main( CntParens & cpns ) with( cpns ) {
    2727        for ( ; ch == '('; cnt += 1 ) {                                         // left parenthesis
    28                 suspend;
     28                suspend();
    2929        }
    3030        for ( ; ch == ')' && cnt > 1; cnt -= 1 ) {                      // right parenthesis
    31                 suspend;
     31                suspend();
    3232        }
    3333        status = ch == ')' ? Match : Error;
    3434} // main
    35 
     35       
    3636void ?{}( CntParens & cpns ) with( cpns ) { status = Cont; cnt = 0; }
    3737
  • tests/coroutine/devicedriver.cfa

    reef8dfb rbdfc032  
    1 //
     1// 
    22// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    33//
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    6 //
    7 // devicedriver.cfa --
    8 //
     6// 
     7// devicedriver.cfa -- 
     8// 
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Mar 16 15:30:34 2019
     
    1212// Last Modified On : Sat Apr 20 09:07:19 2019
    1313// Update Count     : 90
    14 //
     14// 
    1515
    1616#include <fstream.hfa>
     
    2929
    3030void checkCRC( Driver & d, unsigned int sum ) with( d ) {
    31         suspend;
     31        suspend();
    3232        unsigned short int crc = byte << 8;                                     // sign extension over written
    33         suspend;
     33        suspend();
    3434        // prevent sign extension for signed char
    3535        status = (crc | (unsigned char)byte) == sum ? MSG : ECRC;
     
    4141                status = CONT;
    4242                unsigned int lnth = 0, sum = 0;
    43                 while ( byte != STX ) suspend;
     43                while ( byte != STX ) suspend();
    4444          emsg: for () {
    45                         suspend;
     45                        suspend();
    4646                        choose ( byte ) {                                                       // process byte
    4747                          case STX:
    48                                 status = ESTX; suspend; continue msg;
     48                                status = ESTX; suspend(); continue msg;
    4949                          case ETX:
    5050                                break emsg;
    5151                          case ESC:
    52                                 suspend;
     52                                suspend();
    5353                        } // choose
    5454                        if ( lnth >= MaxMsg ) {                                         // buffer full ?
    55                                 status = ELNTH; suspend; continue msg;
     55                                status = ELNTH; suspend(); continue msg;
    5656                        } // if
    5757                        msg[lnth++] = byte;
     
    6060                msg[lnth] = '\0';                                                               // terminate string
    6161                checkCRC( d, sum );                                                             // refactor CRC check
    62                 suspend;
     62                suspend();
    6363        } // for
    6464} // main
  • tests/coroutine/fibonacci.cfa

    reef8dfb rbdfc032  
    2222        int fn1, fn2;                                                                           // retained between resumes
    2323        fn = 0;  fn1 = fn;                                                                      // 1st case
    24         suspend;                                                                                        // restart last resume
     24        suspend();                                                                                      // restart last resume
    2525        fn = 1;  fn2 = fn1;  fn1 = fn;                                          // 2nd case
    26         suspend;                                                                                        // restart last resume
     26        suspend();                                                                                      // restart last resume
    2727        for () {
    2828                fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;                  // general case
    29                 suspend;                                                                                // restart last resume
     29                suspend();                                                                              // restart last resume
    3030        } // for
    3131}
  • tests/coroutine/fibonacci_1.cfa

    reef8dfb rbdfc032  
    1212// Last Modified On : Thu Mar 21 08:10:45 2019
    1313// Update Count     : 25
    14 //
     14// 
    1515
    1616#include <fstream.hfa>
     
    2323        [fn1, fn] = [0, 1];                                                                     // precompute first two states
    2424        for () {
    25                 suspend;                                                                                // restart last resume
     25                suspend();                                                                              // restart last resume
    2626                [fn1, fn] = [fn, fn1 + fn];                                             // general case
    2727        } // for
  • tests/coroutine/fmtLines.cfa

    reef8dfb rbdfc032  
    2727                        for ( b = 0; b < 4; b += 1 ) {                          // blocks of 4 characters
    2828                                for () {                                                                // for newline characters
    29                                         suspend;
     29                                        suspend();
    3030                                  if ( ch != '\n' ) break;                              // ignore newline
    3131                                } // for
  • tests/coroutine/raii.cfa

    reef8dfb rbdfc032  
    3939        Raii raii = { "Coroutine" };
    4040        sout | "Before Suspend";
    41         suspend;
     41        suspend();
    4242        sout | "After Suspend";
    4343}
  • tests/coroutine/runningTotal.cfa

    reef8dfb rbdfc032  
    2525void update( RunTotal & rntl, int input ) with( rntl ) { // helper
    2626        total += input;                                                                         // remember between activations
    27         suspend;                                                                                        // inactivate on stack
     27        suspend();                                                                                      // inactivate on stack
    2828}
    2929
  • tests/coroutine/suspend_then.cfa

    reef8dfb rbdfc032  
    1515
    1616#include <fstream.hfa>
     17#include <coroutine.hfa>
    1718
    18 generator Fibonacci {
    19         int fn;                                                                         // used for communication
    20         int fn1, fn2;                                                           // retained between resumes
    21 };
     19void then() {
     20        sout | "Then!";
     21}
     22
     23coroutine Fibonacci { int fn; };                                                // used for communication
    2224
    2325void main( Fibonacci & fib ) with( fib ) {                              // called on first resume
     26        int fn1, fn2;                                                           // retained between resumes
    2427        fn = 0;  fn1 = fn;                                                      // 1st case
    25         suspend { sout | "Then!"; }                                             // restart last resume
     28        suspend_then(then);                                                     // restart last resume
    2629        fn = 1;  fn2 = fn1;  fn1 = fn;                                  // 2nd case
    27         suspend { sout | "Then!"; }                                             // restart last resume
     30        suspend_then(then);                                                     // restart last resume
    2831        for () {
    2932                fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;                  // general case
    30                 suspend { sout | "Then!"; }                                     // restart last resume
     33                suspend_then(then);                                             // restart last resume
    3134        } // for
    3235}
  • tests/enum.cfa

    reef8dfb rbdfc032  
    2626//Dummy main
    2727int main(int argc, char const *argv[]) {
    28         printf( "done\n" );                             // non-empty .expect file
    2928}
  • tests/expression.cfa

    reef8dfb rbdfc032  
    88
    99int main() {
    10         int a[3] = { 0, 0, 0 };
    11         S s = { 3 }, * ps = &s;
    12         [int] t = { 3 };
    13         * [int] pt = &t;
    14         int i = 1, j = 2;
     10    int a[3] = { 0, 0, 0 };
     11    S s = { 3 }, * ps = &s;
     12    [int] t = { 3 };
     13    * [int] pt = &t;
     14    int i = 1, j = 2;
    1515
    16         // operators
     16    // operators
    1717
    18         !i;
    19         ~i;
    20         +i;
    21         -i;
    22         *ps;
    23         ++ps;
    24         --ps;
    25         ps++;
    26         ps--;
     18    !i;
     19    ~i;
     20    +i;
     21    -i;
     22    *ps;
     23    ++ps;
     24    --ps;
     25    ps++;
     26    ps--;
    2727
    28         i + j;
    29         i - j;
    30         i * j;
     28    i + j;
     29    i - j;
     30    i * j;
    3131
    32         i / j;
    33         i % j;
    34         i ^ j;
    35         i & j;
    36         i | j;
    37         i < j;
    38         i > j;
    39         i = j;
     32    i / j;
     33    i % j;
     34    i ^ j;
     35    i & j;
     36    i | j;
     37    i < j;
     38    i > j;
     39    i = j;
    4040
    41         i == j;
    42         i != j;
    43         i << j;
    44         i >> j;
    45         i <= j;
    46         i >= j;
    47         i && j;
    48         i || j;
    49         ps->i;
     41    i == j;
     42    i != j;
     43    i << j;
     44    i >> j;
     45    i <= j;
     46    i >= j;
     47    i && j;
     48    i || j;
     49    ps->i;
    5050
    51         i *= j;
    52         i /= j;
    53         i %= j;
    54         i += j;
    55         i -= j;
    56         i &= j;
    57         i |= j;
    58         i ^= j;
    59         i <<= j;
    60         i >>= j;
     51    i *= j;
     52    i /= j;
     53    i %= j;
     54    i += j;
     55    i -= j;
     56    i &= j;
     57    i |= j;
     58    i ^= j;
     59    i <<= j;
     60    i >>= j;
    6161
    62         i ? i : j;
     62    i ? i : j;
    6363
    64         // postfix function call
     64    // postfix function call
    6565
    66         (3 + 4)`mary;
    67         ({3 + 4;})`mary;
    68         [3, 4]`mary;
    69         3`mary;
    70         a[0]`mary;
    71         a[0]`mary`mary;
    72         s{0}`mary;
    73         a[3]`jane++;
    74         jack(3)`mary;
    75         s.i`mary;
    76         t.0`mary;
    77         s.[i]`mary;
    78         ps->i`mary;
    79         pt->0`mary;
    80         ps->[i]`mary;
    81         i++`mary;
    82         i--`mary;
    83         (S){2}`mary;
    84         (S)@{2}`mary;
    85 
    86         #if !defined(NO_COMPILED_PRAGMA)
    87                 #pragma message( "Compiled" )   // force non-empty .expect file
    88         #endif
     66    (3 + 4)`mary;
     67    ({3 + 4;})`mary;
     68    [3, 4]`mary;
     69    3`mary;
     70    a[0]`mary;
     71    a[0]`mary`mary;
     72    s{0}`mary;
     73    a[3]`jane++;
     74    jack(3)`mary;
     75    s.i`mary;
     76    t.0`mary;
     77    s.[i]`mary;
     78    ps->i`mary;
     79    pt->0`mary;
     80    ps->[i]`mary;
     81    i++`mary;
     82    i--`mary;
     83    (S){2}`mary;
     84    (S)@{2}`mary;
    8985} // main
  • tests/forall.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed May  9 08:48:15 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 08:43:20 2020
    13 // Update Count     : 35
     12// Last Modified On : Tue Mar 19 08:29:38 2019
     13// Update Count     : 32
    1414//
    1515
     
    158158}
    159159forall( otype T ) inline static {
    160         int RT9( T ) { T t; return 3; }
     160        int RT9( T ) { T t; }
    161161}
    162162
     
    213213// w3 g3;
    214214
    215 int main( void ) {
    216         #pragma message( "Compiled" )                   // force non-empty .expect file
    217 }
     215int main( void ) {}
    218216
    219217// Local Variables: //
  • tests/heap.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Nov  6 17:54:56 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec 15 12:11:51 2020
    13 // Update Count     : 79
     12// Last Modified On : Sun Nov 24 12:34:51 2019
     13// Update Count     : 28
    1414//
    1515
     
    2727// }
    2828
    29 size_t default_heap_expansion() {
    30         return 10 * 1024 * 1024;
    31 } // default_heap_expansion
    32 
    33 size_t default_mmap_start() {
    34         return 512 * 1024 + 1;
     29#define __U_DEFAULT_MMAP_START__ (512 * 1024 + 1)
     30size_t default_mmap_start() __attribute__(( weak )) {
     31        return __U_DEFAULT_MMAP_START__;
    3532} // default_mmap_start
    3633
     
    7875                size_t s = (i + 1) * 20;
    7976                char * area = (char *)malloc( s );
     77                if ( area == 0p ) abort( "malloc/free out of memory" );
    8078                area[0] = '\345'; area[s - 1] = '\345';                 // fill first/last
    8179                area[malloc_usable_size( area ) - 1] = '\345';  // fill ultimate byte
     
    8684                size_t s = i + 1;                                                               // +1 to make initialization simpler
    8785                locns[i] = (char *)malloc( s );
     86                if ( locns[i] == 0p ) abort( "malloc/free out of memory" );
    8887                locns[i][0] = '\345'; locns[i][s - 1] = '\345'; // fill first/last
    8988                locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte
     
    101100                size_t s = i + default_mmap_start();                    // cross over point
    102101                char * area = (char *)malloc( s );
     102                if ( area == 0p ) abort( "malloc/free out of memory" );
    103103                area[0] = '\345'; area[s - 1] = '\345';                 // fill first/last
    104104                area[malloc_usable_size( area ) - 1] = '\345';  // fill ultimate byte
     
    109109                size_t s = i + default_mmap_start();                    // cross over point
    110110                locns[i] = (char *)malloc( s );
     111                if ( locns[i] == 0p ) abort( "malloc/free out of memory" );
    111112                locns[i][0] = '\345'; locns[i][s - 1] = '\345'; // fill first/last
    112113                locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte
     
    124125                size_t s = (i + 1) * 20;
    125126                char * area = (char *)calloc( 5, s );
     127                if ( area == 0p ) abort( "calloc/free out of memory" );
    126128                if ( area[0] != '\0' || area[s - 1] != '\0' ||
    127                          area[malloc_size( area ) - 1] != '\0' ||
     129                         area[malloc_usable_size( area ) - 1] != '\0' ||
    128130                         ! malloc_zero_fill( area ) ) abort( "calloc/free corrupt storage1" );
    129131                area[0] = '\345'; area[s - 1] = '\345';                 // fill first/last
     
    135137                size_t s = i + 1;
    136138                locns[i] = (char *)calloc( 5, s );
     139                if ( locns[i] == 0p ) abort( "calloc/free out of memory" );
    137140                if ( locns[i][0] != '\0' || locns[i][s - 1] != '\0' ||
    138                          locns[i][malloc_size( locns[i] ) - 1] != '\0' ||
     141                         locns[i][malloc_usable_size( locns[i] ) - 1] != '\0' ||
    139142                         ! malloc_zero_fill( locns[i] ) ) abort( "calloc/free corrupt storage2" );
    140143                locns[i][0] = '\345'; locns[i][s - 1] = '\345'; // fill first/last
     
    153156                size_t s = i + default_mmap_start();                    // cross over point
    154157                char * area = (char *)calloc( 1, s );
     158                if ( area == 0p ) abort( "calloc/free out of memory" );
    155159                if ( area[0] != '\0' || area[s - 1] != '\0' ) abort( "calloc/free corrupt storage4.1" );
    156                 if ( area[malloc_size( area ) - 1] != '\0' ) abort( "calloc/free corrupt storage4.2" );
     160                if ( area[malloc_usable_size( area ) - 1] != '\0' ) abort( "calloc/free corrupt storage4.2" );
    157161                if ( ! malloc_zero_fill( area ) ) abort( "calloc/free corrupt storage4.3" );
    158162                area[0] = '\345'; area[s - 1] = '\345';                 // fill first/last
     
    164168                size_t s = i + default_mmap_start();                    // cross over point
    165169                locns[i] = (char *)calloc( 1, s );
     170                if ( locns[i] == 0p ) abort( "calloc/free out of memory" );
    166171                if ( locns[i][0] != '\0' || locns[i][s - 1] != '\0' ||
    167                          locns[i][malloc_size( locns[i] ) - 1] != '\0' ||
     172                         locns[i][malloc_usable_size( locns[i] ) - 1] != '\0' ||
    168173                         ! malloc_zero_fill( locns[i] ) ) abort( "calloc/free corrupt storage5" );
    169174                locns[i][0] = '\345'; locns[i][s - 1] = '\345'; // fill first/last
     
    183188                for ( s; 1 ~ NoOfAllocs ) {                                             // allocation of size 0 can return null
    184189                        char * area = (char *)memalign( a, s );
     190                        if ( area == 0p ) abort( "memalign/free out of memory" );
    185191                        //sout | i | area;
    186192                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
     
    200206                        size_t s = i + default_mmap_start();            // cross over point
    201207                        char * area = (char *)memalign( a, s );
     208                        if ( area == 0p ) abort( "memalign/free out of memory" );
    202209                        //sout | i | area;
    203210                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
     
    210217        } // for
    211218
    212         // check malloc/resize/free (sbrk)
    213 
    214         for ( i; 2 ~ NoOfAllocs ~ 12 ) {
    215                 // initial N byte allocation
    216                 char * area = (char *)malloc( i );
    217                 area[0] = '\345'; area[i - 1] = '\345';                 // fill first/penultimate byte
    218 
    219                 // Do not start this loop index at 0 because resize of 0 bytes frees the storage.
    220                 int prev = i;
    221                 for ( s; i ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    222                         if ( area[0] != '\345' || area[prev - 1] != '\345' ) abort( "malloc/resize/free corrupt storage" );
    223                         area = (char *)resize( area, s );                       // attempt to reuse storage
    224                         area[0] = area[s - 1] = '\345';                         // fill last byte
    225                         prev = s;
    226                 } // for
    227                 free( area );
    228         } // for
    229 
    230         // check malloc/resize/free (mmap)
    231 
    232         for ( i; 2 ~ NoOfAllocs ~ 12 ) {
    233                 // initial N byte allocation
    234                 size_t s = i + default_mmap_start();                    // cross over point
    235                 char * area = (char *)malloc( s );
    236                 area[0] = '\345'; area[s - 1] = '\345';                 // fill first/penultimate byte
    237 
    238                 // Do not start this loop index at 0 because resize of 0 bytes frees the storage.
    239                 int prev = s;
    240                 for ( r; s ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    241                         if ( area[0] != '\345' || area[prev - 1] != '\345' ) abort( "malloc/resize/free corrupt storage" );
    242                         area = (char *)resize( area, s );                       // attempt to reuse storage
    243                         area[0] = area[r - 1] = '\345';                         // fill last byte
    244                         prev = r;
    245                 } // for
    246                 free( area );
    247         } // for
    248 
    249         // check malloc/realloc/free (sbrk)
    250 
    251         for ( i; 2 ~ NoOfAllocs ~ 12 ) {
    252                 // initial N byte allocation
    253                 char * area = (char *)malloc( i );
    254                 area[0] = '\345'; area[i - 1] = '\345';                 // fill first/penultimate byte
    255 
    256                 // Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
    257                 int prev = i;
    258                 for ( s; i ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    259                         if ( area[0] != '\345' || area[prev - 1] != '\345' ) abort( "malloc/realloc/free corrupt storage" );
    260                         area = (char *)realloc( area, s );                      // attempt to reuse storage
    261                         area[s - 1] = '\345';                                           // fill last byte
    262                         prev = s;
    263                 } // for
    264                 free( area );
    265         } // for
    266 
    267         // check malloc/realloc/free (mmap)
    268 
    269         for ( i; 2 ~ NoOfAllocs ~ 12 ) {
    270                 // initial N byte allocation
    271                 size_t s = i + default_mmap_start();                    // cross over point
    272                 char * area = (char *)malloc( s );
    273                 area[0] = '\345'; area[s - 1] = '\345';                 // fill first/penultimate byte
    274 
    275                 // Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
    276                 int prev = s;
    277                 for ( r; s ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    278                         if ( area[0] != '\345' || area[prev - 1] != '\345' ) abort( "malloc/realloc/free corrupt storage" );
    279                         area = (char *)realloc( area, s );                      // attempt to reuse storage
    280                         area[r - 1] = '\345';                                           // fill last byte
    281                         prev = r;
    282                 } // for
    283                 free( area );
    284         } // for
    285 
    286219        // check calloc/realloc/free (sbrk)
    287220
     
    289222                // initial N byte allocation
    290223                char * area = (char *)calloc( 5, i );
     224                if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    291225                if ( area[0] != '\0' || area[i - 1] != '\0' ||
    292                          area[malloc_size( area ) - 1] != '\0' ||
     226                         area[malloc_usable_size( area ) - 1] != '\0' ||
    293227                         ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage1" );
    294228
     
    296230                for ( s; i ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    297231                        area = (char *)realloc( area, s );                      // attempt to reuse storage
     232                        if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    298233                        if ( area[0] != '\0' || area[s - 1] != '\0' ||
    299                                  area[malloc_size( area ) - 1] != '\0' ||
     234                                 area[malloc_usable_size( area ) - 1] != '\0' ||
    300235                                 ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage2" );
    301236                } // for
     
    309244                size_t s = i + default_mmap_start();                    // cross over point
    310245                char * area = (char *)calloc( 1, s );
     246                if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    311247                if ( area[0] != '\0' || area[s - 1] != '\0' ||
    312                          area[malloc_size( area ) - 1] != '\0' ||
    313                          ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage3" );
     248                         area[malloc_usable_size( area ) - 1] != '\0' ||
     249                         ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage1" );
    314250
    315251                // Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
    316252                for ( r; i ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    317253                        area = (char *)realloc( area, r );                      // attempt to reuse storage
     254                        if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    318255                        if ( area[0] != '\0' || area[r - 1] != '\0' ||
    319                                  area[malloc_size( area ) - 1] != '\0' ||
    320                                  ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage4" );
     256                                 area[malloc_usable_size( area ) - 1] != '\0' ||
     257                                 ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage2" );
    321258                } // for
    322259                free( area );
     
    329266                // initial N byte allocation
    330267                char * area = (char *)memalign( a, amount );    // aligned N-byte allocation
     268                if ( area == 0p ) abort( "memalign/realloc/free out of memory" ); // no storage ?
    331269                //sout | alignments[a] | area;
    332270                if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
     
    339277                        if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "memalign/realloc/free corrupt storage" );
    340278                        area = (char *)realloc( area, s );                      // attempt to reuse storage
     279                        if ( area == 0p ) abort( "memalign/realloc/free out of memory" ); // no storage ?
    341280                        //sout | i | area;
    342281                        if ( (size_t)area % a != 0 ) {                          // check for initial alignment
     
    354293                for ( s; 1 ~ limit ) {                                                  // allocation of size 0 can return null
    355294                        char * area = (char *)cmemalign( a, 1, s );
     295                        if ( area == 0p ) abort( "cmemalign/free out of memory" );
    356296                        //sout | i | area;
    357297                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
     
    359299                        } // if
    360300                        if ( area[0] != '\0' || area[s - 1] != '\0' ||
    361                                  area[malloc_size( area ) - 1] != '\0' ||
     301                                 area[malloc_usable_size( area ) - 1] != '\0' ||
    362302                                 ! malloc_zero_fill( area ) ) abort( "cmemalign/free corrupt storage" );
    363303                        area[0] = '\345'; area[s - 1] = '\345';         // fill first/last byte
     
    372312                // initial N byte allocation
    373313                char * area = (char *)cmemalign( a, 1, amount ); // aligned N-byte allocation
     314                if ( area == 0p ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
    374315                //sout | alignments[a] | area;
    375316                if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
     
    377318                } // if
    378319                if ( area[0] != '\0' || area[amount - 1] != '\0' ||
    379                          area[malloc_size( area ) - 1] != '\0' ||
     320                         area[malloc_usable_size( area ) - 1] != '\0' ||
    380321                         ! malloc_zero_fill( area ) ) abort( "cmemalign/realloc/free corrupt storage1" );
    381322                area[0] = '\345'; area[amount - 2] = '\345';    // fill first/penultimate byte
     
    385326                        if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "cmemalign/realloc/free corrupt storage2" );
    386327                        area = (char *)realloc( area, s );                      // attempt to reuse storage
     328                        if ( area == 0p ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
    387329                        //sout | i | area;
    388330                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    389331                                abort( "cmemalign/realloc/free bad alignment %p", area );
    390332                        } // if
    391                         if ( area[0] != '\345' || area[s - 1] != '\0' ||
    392                                  area[malloc_size( area ) - 1] != '\0' ||
     333                        if ( area[s - 1] != '\0' || area[s - 1] != '\0' ||
     334                                 area[malloc_usable_size( area ) - 1] != '\0' ||
    393335                                 ! malloc_zero_fill( area ) ) abort( "cmemalign/realloc/free corrupt storage3" );
    394336                        area[s - 1] = '\345';                                           // fill last byte
     
    397339        } // for
    398340
    399         // check memalign/resize with align/free
     341        // check memalign/realloc with align/free
    400342
    401343        amount = 2;
     
    403345                // initial N byte allocation
    404346                char * area = (char *)memalign( a, amount );    // aligned N-byte allocation
    405                 //sout | alignments[a] | area | endl;
    406                 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    407                         abort( "memalign/resize with align/free bad alignment : memalign(%d,%d) = %p", (int)a, (int)amount, area );
    408                 } // if
    409                 area[0] = '\345'; area[amount - 2] = '\345';    // fill first/penultimate byte
    410 
    411                 // Do not start this loop index at 0 because resize of 0 bytes frees the storage.
    412                 for ( s; amount ~ 256 * 1024 ) {                                // start at initial memory request
    413                         area = (char *)resize( area, a * 2, s );        // attempt to reuse storage
    414                         //sout | i | area | endl;
    415                         if ( (size_t)area % a * 2 != 0 ) {                      // check for initial alignment
    416                                 abort( "memalign/resize with align/free bad alignment %p", area );
    417                         } // if
    418                         area[s - 1] = '\345';                                           // fill last byte
    419                 } // for
    420                 free( area );
    421         } // for
    422 
    423         // check memalign/realloc with align/free
    424 
    425         amount = 2;
    426         for ( a; libAlign() ~= limit ~ a ) {                            // generate powers of 2
    427                 // initial N byte allocation
    428                 char * area = (char *)memalign( a, amount );    // aligned N-byte allocation
     347                if ( area == 0p ) abort( "memalign/realloc with align/free out of memory" ); // no storage ?
    429348                //sout | alignments[a] | area | endl;
    430349                if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
     
    437356                        if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "memalign/realloc/free corrupt storage" );
    438357                        area = (char *)realloc( area, a * 2, s );       // attempt to reuse storage
     358                        if ( area == 0p ) abort( "memalign/realloc with align/free out of memory" ); // no storage ?
    439359                        //sout | i | area | endl;
    440360                        if ( (size_t)area % a * 2 != 0 ) {                      // check for initial alignment
     
    451371        for ( size_t a = libAlign() + libAlign(); a <= limit; a += a ) { // generate powers of 2
    452372                // initial N byte allocation
    453                 char * area = (char *)cmemalign( a, 1, amount ); // aligned N-byte allocation
     373                char *area = (char *)cmemalign( a, 1, amount ); // aligned N-byte allocation
     374                if ( area == 0p ) abort( "cmemalign/realloc with align/free out of memory" ); // no storage ?
    454375                //sout | alignments[a] | area | endl;
    455376                if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
     
    457378                } // if
    458379                if ( area[0] != '\0' || area[amount - 1] != '\0' ||
    459                          area[malloc_size( area ) - 1] != '\0' ||
     380                         area[malloc_usable_size( area ) - 1] != '\0' ||
    460381                         ! malloc_zero_fill( area ) ) abort( "cmemalign/realloc with align/free corrupt storage1" );
    461382                area[0] = '\345'; area[amount - 2] = '\345';    // fill first/penultimate byte
     
    465386                        if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "cmemalign/realloc with align/free corrupt storage2" );
    466387                        area = (char *)realloc( area, a * 2, s );       // attempt to reuse storage
     388                        if ( area == 0p ) abort( "cmemalign/realloc with align/free out of memory" ); // no storage ?
    467389                        //sout | i | area | endl;
    468390                        if ( (size_t)area % a * 2 != 0 || malloc_alignment( area ) != a * 2 ) { // check for initial alignment
    469                                 abort( "cmemalign/realloc with align/free bad alignment %p %zd %zd", area, malloc_alignment( area ), a * 2 );
     391                                abort( "cmemalign/realloc with align/free bad alignment %p %jd %jd", area, malloc_alignment( area ), a * 2 );
    470392                        } // if
    471393                        if ( area[s - 1] != '\0' || area[s - 1] != '\0' ||
    472                                  area[malloc_size( area ) - 1] != '\0' ||
     394                                 area[malloc_usable_size( area ) - 1] != '\0' ||
    473395                                 ! malloc_zero_fill( area ) ) abort( "cmemalign/realloc/free corrupt storage3" );
    474396                        area[s - 1] = '\345';                                           // fill last byte
     
    488410        // checkFreeOn();
    489411        // malloc_stats();
    490         printf( "done\n" );                                                                     // non-empty .expect file
    491412}
    492413
  • tests/identFuncDeclarator.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed Aug 17 08:36:34 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 08:20:46 2020
    13 // Update Count     : 5
     12// Last Modified On : Tue Nov  6 17:56:33 2018
     13// Update Count     : 3
    1414//
    1515
     
    111111        int (* (* const f80)(int))();
    112112        int (* const(* const f81)(int))();
    113 
    114         #pragma message( "Compiled" )                   // force non-empty .expect file
    115113}
    116114
  • tests/identParamDeclarator.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed Aug 17 08:37:56 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Sep 25 14:31:08 2020
    13 // Update Count     : 4
     12// Last Modified On : Tue Nov  6 17:56:44 2018
     13// Update Count     : 3
    1414//
    1515
     
    158158
    159159int main( int argc, char const *argv[] ) {                              // dummy main
    160         printf( "done\n" );                                                                     // non-empty .expect file
     160        return 0;
    161161}
    162162
  • tests/io2.cfa

    reef8dfb rbdfc032  
    121121
    122122        [int, int, const char *, double] t3 = { 3, 4, "a", 7.2 };
    123         sout | [ 3, 4, (const char*)"a", 7.2 ];             // workaround trac#207: the const cast should not be needed
     123        sout | [ 3, 4, "a", 7.2 ];
    124124        sout | t3;
    125125        sepSetTuple( sout, " " );
  • tests/labelledExit.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed Aug 10 07:29:39 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 09:01:34 2020
    13 // Update Count     : 12
     12// Last Modified On : Fri Oct 25 17:41:51 2019
     13// Update Count     : 7
    1414//
    1515
     
    162162
    163163        // computed goto
    164         {
    165                 void *array[] = { &&foo, &&bar, &&hack };
    166           foo: bar: hack:
    167                 &&foo;
    168                 &&bar;
    169                 goto *array[i];
    170         }
     164        // {
     165        //      void *array[] = { &&foo, &&bar, &&hack };
     166        //   foo: bar: hack:
     167        //      &&foo;
     168        //      &&bar;
     169        //      goto *array[i];
     170        // }
    171171
    172172  Q: if ( i > 5 ) {
     
    179179
    180180int main( int argc, char const *argv[] ) {
    181         #pragma message( "Compiled" )                                           // force non-empty .expect file
     181        /* code */
    182182}
    183183
  • tests/limits.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue May 10 20:44:20 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 08:45:43 2020
    13 // Update Count     : 10
     12// Last Modified On : Tue Nov  6 17:57:55 2018
     13// Update Count     : 8
    1414//
    15 
    16 // Note: For testing the ability to load the constants defined in libcfa/src/limits.cfa,
    17 // see discussion in test const-init.
    1815
    1916#include <limits.hfa>
     
    150147
    151148int main(int argc, char const *argv[]) {
    152         #pragma message( "Compiled" )                                           // force non-empty .expect file
     149        //DUMMY
     150        return 0;
    153151}
    154152
  • tests/linking/withthreads.cfa

    reef8dfb rbdfc032  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // withthreads.cfa --
     7// nothreads.cfa --
    88//
    99// Author           : Thierry Delisle
  • tests/literals.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Sat Sep  9 16:34:38 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 29 10:57:56 2020
    13 // Update Count     : 226
     12// Last Modified On : Tue Feb 12 08:07:39 2019
     13// Update Count     : 224
    1414//
    1515
     
    151151        -0X0123456789.0123456789P-09;  -0X0123456789.0123456789P-09f;  -0X0123456789.0123456789P-09l;  -0X0123456789.0123456789P-09F;  -0X0123456789.0123456789P-09L;
    152152
    153 #if defined( __i386 ) || defined( __x86_64 )
    154153#if defined(__GNUC__) && __GNUC_PREREQ(7,0)                             // gcc version >= 7
    155154// floating with length, gcc f16/f128x unsupported and no prelude code for any _FloatXXx, so they work by conversion to long double
     
    195194        /* -0x123456789.0123456789P-09F16; */  -0x123456789.0123456789P-09F32;  -0x123456789.0123456789P-09F32x;  -0x123456789.0123456789P-09F64;  -0x123456789.0123456789P-09F64x;  -0x123456789.0123456789P-09W;  -0x123456789.0123456789P-09F128;  -0x123456789.0123456789P-09q;  /* -0x123456789.0123456789P-09q; */
    196195#endif // __GNUC_PREREQ(7,0)
    197 #endif // __i386 ) || __x86_64
    198196
    199197#ifdef __CFA__
     
    216214        -01234567_l8;  -01234567_l16;  -01234567_l32;  -01234567_l64;  -01234567_l8u;  -01234567_ul16;  -01234567_l32u;  -01234567_ul64;
    217215
    218 #if defined( __SIZEOF_INT128__ )
     216#ifdef __LP64__ // 64-bit processor
    219217        01234567_l128;   01234567_ul128;
    220218        +01234567_l128;  +01234567_ul128;
    221219        -01234567_l128;  -01234567_ul128;
    222 #endif // __SIZEOF_INT128__
     220#endif // __LP64__
    223221
    224222        // decimal
     
    227225        -1234567890L8;  -1234567890L16;  -1234567890l32;  -1234567890l64;  -1234567890UL8;  -1234567890L16U;  -1234567890Ul32;  -1234567890l64u;
    228226
    229 #if defined( __SIZEOF_INT128__ )
     227#ifdef __LP64__ // 64-bit processor
    230228        1234567890l128;   1234567890l128u;
    231229        +1234567890l128;  +1234567890l128u;
    232230        -1234567890l128;  -1234567890l128u;
    233     1234567890123456789_L128u; 1234567890123456789_L128u;
    234         18446708753438544741_l64u; 18446708753438544741_Ul64;
    235 #endif // __SIZEOF_INT128__
     231#endif // __LP64__
    236232
    237233        // hexadecimal
  • tests/manipulatorsInput.cfa

    reef8dfb rbdfc032  
    77// Created On       : Sat Jun  8 17:58:54 2019
    88// Last Modified By : Peter A. Buhr
    9 // Last Modified On : Wed Jul 15 15:56:03 2020
    10 // Update Count     : 47
     9// Last Modified On : Thu Jun 13 17:41:43 2019
     10// Update Count     : 37
    1111//
    1212
     
    152152                sin | ignore( wdi( 8, ldc ) );                  sout | ldc;
    153153        }
    154 #if defined( __SIZEOF_INT128__ )
    155         {
    156                 int128 val;
    157                 for ( 15 ) {
    158                         sin | val;
    159                         sout | val;
    160                 }
    161         }
    162 #endif // __SIZEOF_INT128__
    163154} // main
    164155
  • tests/manipulatorsOutput1.cfa

    reef8dfb rbdfc032  
    77// Created On       : Sat Jun  8 18:04:11 2019
    88// Last Modified By : Peter A. Buhr
    9 // Last Modified On : Fri May  1 11:51:44 2020
    10 // Update Count     : 9
     9// Last Modified On : Mon Jun 10 12:37:28 2019
     10// Update Count     : 8
    1111//
    1212
     
    1717        signed char sc = -12;
    1818        printf( "%hhd %2hhd %5.2hhd %-5.2hhd %hho %#hho %hhx %#hhx %#8hhx %#8.10hhx %#8.3hhX %+-8.3hhd %08hhd\n", sc, sc, sc, sc, sc, sc, sc, sc, sc, sc, sc, sc, sc );
    19         sout | sc | wd(2,sc) | wd(5,2,sc) | left(wd(5,2,sc)) | nobase(oct(sc)) | oct(sc) | nonl;
    20         sout | nobase(hex(sc)) | hex(sc) | wd(8,hex(sc)) | wd(8,10,hex(sc)) | upcase(wd(8,3,hex(sc))) | nonl;
    21         sout | left(sign(upcase(wd(8,3,sc)))) | pad0(wd(8,sc));
     19        sout | sc | wd(2,sc) | wd(5,2,sc) | left(wd(5,2,sc)) | nobase(oct(sc)) | oct(sc) | nobase(hex(sc)) | hex(sc) | wd(8,hex(sc)) | wd(8,10,hex(sc)) | upcase(wd(8,3,hex(sc))) | left(sign(upcase(wd(8,3,sc)))) | pad0(wd(8,sc));
    2220
    2321        sout | "unsigned char";
    2422        unsigned char usc = 12;
    2523        printf( "%hhu %2hhu %5.2hhu %-5.2hhu %hho %#hho %hhx %#hhx %#8hhx %#8.10hhx %#8.3hhX %-8.3hhu %08hhu\n", usc, usc, usc, usc, usc, usc, usc, usc, usc, usc, usc, usc, usc );
    26         sout | usc | wd(2,usc) | wd(5,2,usc) | left(wd(5,2,usc)) | nobase(oct(usc)) | oct(usc) | nonl;
    27         sout | nobase(hex(usc)) | hex(usc) | wd(8,hex(usc)) | wd(8,10,hex(usc)) | upcase(wd(8,3,hex(usc))) | nonl;
    28         sout | left(upcase(wd(8,3,usc))) | pad0(wd(8,usc));
     24        sout | usc | wd(2,usc) | wd(5,2,usc) | left(wd(5,2,usc)) | nobase(oct(usc)) | oct(usc) | nobase(hex(usc)) | hex(usc) | wd(8,hex(usc)) | wd(8,10,hex(usc)) | upcase(wd(8,3,hex(usc))) | left(upcase(wd(8,3,usc))) | pad0(wd(8,usc));
    2925
    3026        sout | "signed short int";
    3127        signed short int si = -12;
    3228        printf( "%hd %2hd %5.2hd %-5.2hd %ho %#ho %hx %#hx %#8hx %#8.10hx %#8.3hX %+-8.3hd %08hd\n", si, si, si, si, si, si, si, si, si, si, si, si, si );
    33         sout | si | wd(2,si) | wd(5,2,si) | left(wd(5,2,si)) | nobase(oct(si)) | oct(si) | nonl;
    34         sout | nobase(hex(si)) | hex(si) | wd(8,hex(si)) | wd(8,10,hex(si)) | upcase(wd(8,3,hex(si))) | nonl;
    35         sout | left(sign(upcase(wd(8,3,si)))) | pad0(wd(8,si));
     29        sout | si | wd(2,si) | wd(5,2,si) | left(wd(5,2,si)) | nobase(oct(si)) | oct(si) | nobase(hex(si)) | hex(si) | wd(8,hex(si)) | wd(8,10,hex(si)) | upcase(wd(8,3,hex(si))) | left(sign(upcase(wd(8,3,si)))) | pad0(wd(8,si));
    3630
    3731        sout | "unsigned short int";
    3832        unsigned short int usi = 12;
    3933        printf( "%hu %2hu %5.2hu %-5.2hu %ho %#ho %hx %#hx %#8hx %#8.10hx %#8.3hX %-8.3hu %08hu\n", usi, usi, usi, usi, usi, usi, usi, usi, usi, usi, usi, usi, usi );
    40         sout | usi | wd(2,usi) | wd(5,2,usi) | left(wd(5,2,usi)) | nobase(oct(usi)) | oct(usi) | nonl;
    41         sout | nobase(hex(usi)) | hex(usi) | wd(8,hex(usi)) | wd(8,10,hex(usi)) | upcase(wd(8,3,hex(usi))) | nonl;
    42         sout | left(upcase(wd(8,3,usi))) | pad0(wd(8,usi));
     34        sout | usi | wd(2,usi) | wd(5,2,usi) | left(wd(5,2,usi)) | nobase(oct(usi)) | oct(usi) | nobase(hex(usi)) | hex(usi) | wd(8,hex(usi)) | wd(8,10,hex(usi)) | upcase(wd(8,3,hex(usi))) | left(upcase(wd(8,3,usi))) | pad0(wd(8,usi));
    4335
    4436        sout | "signed int";
    4537        signed int i = -12;
    4638        printf( "%d %2d %5.2d %-5.2d %o %#o %x %#x %#8x %#8.10x %#8.3X %+-8.3d %08d\n", i, i, i, i, i, i, i, i, i, i, i, i, i );
    47         sout | i | wd(2,i) | wd(5,2,i) | left(wd(5,2,i)) | nobase(oct(i)) | oct(i) | nonl;
    48         sout | nobase(hex(i)) | hex(i) | wd(8,hex(i)) | wd(8,10,hex(i)) | upcase(wd(8,3,hex(i))) | nonl;
    49         sout | left(sign(upcase(wd(8,3,i)))) | pad0(wd(8,i));
     39        sout | i | wd(2,i) | wd(5,2,i) | left(wd(5,2,i)) | nobase(oct(i)) | oct(i) | nobase(hex(i)) | hex(i) | wd(8,hex(i)) | wd(8,10,hex(i)) | upcase(wd(8,3,hex(i))) | left(sign(upcase(wd(8,3,i)))) | pad0(wd(8,i));
    5040
    5141        sout | "unsigned int";
    5242        unsigned int ui = 12;
    5343        printf( "%u %2u %5.2u %-5.2u %o %#o %x %#x %#8x %#8.10x %#8.3X %-8.3u %08u\n", ui, ui, ui, ui, ui, ui, ui, ui, ui, ui, ui, ui, ui );
    54         sout | ui | wd(2,ui) | wd(5,2,ui) | left(wd(5,2,ui)) | nobase(oct(ui)) | oct(ui) | nonl;
    55         sout | nobase(hex(ui)) | hex(ui) | wd(8,hex(ui)) | wd(8,10,hex(ui)) | upcase(wd(8,3,hex(ui))) | nonl;
    56         sout | left(upcase(wd(8,3,ui))) | pad0(wd(8,ui));
     44        sout | ui | wd(2,ui) | wd(5,2,ui) | left(wd(5,2,ui)) | nobase(oct(ui)) | oct(ui) | nobase(hex(ui)) | hex(ui) | wd(8,hex(ui)) | wd(8,10,hex(ui)) | upcase(wd(8,3,hex(ui))) | left(upcase(wd(8,3,ui))) | pad0(wd(8,ui));
    5745
    5846        sout | "signed long long int";
    5947        signed long long int lli = -12;
    6048        printf( "%lld %2lld %5.2lld %-5.2lld %llo %#llo %llx %#llx %#8llx %#8.10llx %#8.3llX %+-8.3lld %08lld\n", lli, lli, lli, lli, lli, lli, lli, lli, lli, lli, lli, lli, lli );
    61         sout | lli | wd(2,lli) | wd(5,2,lli) | left(wd(5,2,lli)) | nobase(oct(lli)) | oct(lli) | nonl;
    62         sout | nobase(hex(lli)) | hex(lli) | wd(8,hex(lli)) | wd(8,10,hex(lli)) | upcase(wd(8,3,hex(lli))) | nonl;
    63         sout | left(sign(upcase(wd(8,3,lli)))) | pad0(wd(8,lli));
     49        sout | lli | wd(2,lli) | wd(5,2,lli) | left(wd(5,2,lli)) | nobase(oct(lli)) | oct(lli) | nobase(hex(lli)) | hex(lli) | wd(8,hex(lli)) | wd(8,10,hex(lli)) | upcase(wd(8,3,hex(lli))) | left(sign(upcase(wd(8,3,lli)))) | pad0(wd(8,lli));
    6450
    6551        sout | "unsigned long long int";
    6652        unsigned long long int ulli = 12;
    6753        printf( "%llu %2llu %5.2llu %-5.2llu %llo %#llo %llx %#llx %#8llx %#8.10llx %#8.3llX %-8.3llu %08llu\n", ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli, ulli );
    68         sout | ulli | wd(2,ulli) | wd(5,2,ulli) | left(wd(5,2,ulli)) | nobase(oct(ulli)) | oct(ulli) | nonl;
    69         sout | nobase(hex(ulli)) | hex(ulli) | wd(8,hex(ulli)) | wd(8,10,hex(ulli)) | upcase(wd(8,3,hex(ulli))) | nonl;
    70         sout | left(upcase(wd(8,3,ulli))) | pad0(wd(8,ulli));
     54        sout | ulli | wd(2,ulli) | wd(5,2,ulli) | left(wd(5,2,ulli)) | nobase(oct(ulli)) | oct(ulli) | nobase(hex(ulli)) | hex(ulli) | wd(8,hex(ulli)) | wd(8,10,hex(ulli)) | upcase(wd(8,3,hex(ulli))) | left(upcase(wd(8,3,ulli))) | pad0(wd(8,ulli));
    7155
    7256        sout | nl | "binary integral";
    73         sout | bin(0) | bin(13) | upcase(bin(13)) | nobase(bin(13)) | left(wd(8,bin(13))) | wd(8,bin(13)) | nonl;
    74         sout | pad0(left(wd(8,bin(13)))) | pad0(wd(8,bin(13))) | pad0(wd(8,10,bin(13))) | pad0(wd(8,6,bin(13)));
     57        sout | bin(0) | bin(13) | upcase(bin(13)) | nobase(bin(13)) | left(wd(8,bin(13))) | wd(8,bin(13)) | pad0(left(wd(8,bin(13)))) | pad0(wd(8,bin(13))) | pad0(wd(8,10,bin(13))) | pad0(wd(8,6,bin(13)));
    7558
    7659
     
    7962        printf( "%g  %8g %#8g %g %8g %8.0g %#8.0g %8.2g %#8.2g %-8.2g %-8.2g %-#8.2g %-+8.2g %-+#8.2g %08.2g %8.2E %8.2a %#8.2A %#8.2e\n",
    8063                    0.0,3.0F,3.0F, f,  f,    f,     f,    f,     f,  3.0F,      f,      f,      f,       f,     f,    f,    f,     f,     f );
    81         sout | 0.0 | wd(8, 3.0F) | nodp(wd(8, 3.0F)) | f | wd(8, f) | ws(8,0, f) | nodp(ws(8,0, f)) | ws(8,2, f) | nodp(ws(8,2, f)) | nonl;
    82         sout | left(ws(8,2, 3.0F)) | left(ws(8,2, f)) | left(nodp(ws(8,2, f))) | left(sign(ws(8,2, f))) | left(sign(nodp(ws(8,2, f)))) | nonl;
    83         sout | pad0(ws(8,2, f)) | upcase(wd(8,2, sci(f))) | wd(8,2, hex(f)) | upcase(wd(8,2, hex(f))) | nodp(wd(8,2, sci(f)));
     64        sout | 0.0 | wd(8, 3.0F) | nodp(wd(8, 3.0F)) | f | wd(8, f) | ws(8,0, f) | nodp(ws(8,0, f)) | ws(8,2, f) | nodp(ws(8,2, f)) | left(ws(8,2, 3.0F)) | left(ws(8,2, f)) | left(nodp(ws(8,2, f))) | left(sign(ws(8,2, f))) | left(sign(nodp(ws(8,2, f)))) | pad0(ws(8,2, f)) | upcase(wd(8,2, sci(f))) | wd(8,2, hex(f)) | upcase(wd(8,2, hex(f))) | nodp(wd(8,2, sci(f)));
    8465
    8566        sout | "double";
     
    8768        printf( "%g  %#8f %g %8f %#8.0f %8.0f %8.2f %-8.2f %-+#8.2f %08.2F %8.2E %8.2a %8.2A %8.2e\n",
    8869                        0.0,  3.0, d,  d,     d,    d,    d,     d,       d,     d,    d,    d,    d,    d );
    89         sout | 0.0 | wd(8, 3.0) | d | wd(8, d) | nodp(wd(8,0, d)) | wd(8,0, d) | wd(8,2, d) | nonl;
    90         sout | left(wd(8,2, d)) | left(sign(wd(8,2, d))) | pad0(upcase(wd(8,2, d))) | upcase(wd(8,2, sci(d))) | wd(8,2, hex(d)) | upcase(wd(8,2, hex(d))) | wd(8,2, sci(d));
     70        sout | 0.0 | wd(8, 3.0) | d | wd(8, d) | nodp(wd(8,0, d)) | wd(8,0, d) | wd(8,2, d) | left(wd(8,2, d)) | left(sign(wd(8,2, d))) | pad0(upcase(wd(8,2, d))) | upcase(wd(8,2, sci(d))) | wd(8,2, hex(d)) | upcase(wd(8,2, hex(d))) | wd(8,2, sci(d));
    9171
    9272        sout | "long double";
     
    9474        printf( "%Lg  %#8Lf %Lg %8Lf %#8.0Lf %8.0Lf %8.2Lf %-8.2Lf %-+#8.2Lf %08.2LF %8.2LE %8.2La %8.2LA %8.2Le\n",
    9575                        0.0L,  3.0L, ld,  ld,     ld,    ld,    ld,     ld,       ld,     ld,    ld,    ld,    ld,    ld );
    96         sout | 0.0L | wd(8, 3.0L) | ld | wd(8, ld) | nodp(wd(8,0, ld)) | wd(8,0, ld) | wd(8,2, ld) | nonl;
    97         sout | left(wd(8,2, ld)) | left(sign(wd(8,2, ld))) | pad0(upcase(wd(8,2, ld))) | upcase(wd(8,2, sci(ld))) | wd(8,2, hex(ld)) | upcase(wd(8,2, hex(ld))) | wd(8,2, sci(ld));
     76        sout | 0.0L | wd(8, 3.0L) | ld | wd(8, ld) | nodp(wd(8,0, ld)) | wd(8,0, ld) | wd(8,2, ld) | left(wd(8,2, ld)) | left(sign(wd(8,2, ld))) | pad0(upcase(wd(8,2, ld))) | upcase(wd(8,2, sci(ld))) | wd(8,2, hex(ld)) | upcase(wd(8,2, hex(ld))) | wd(8,2, sci(ld));
    9877
    9978
     
    10180        char c = 'a';
    10281        printf( "%c %2c %5c %-5c %hho %#hho %hhx %#hhx %#8hhx %#8hhX %-8c %8c\n", c, c, c, c, c, c, c, c, c, c, c, c );
    103         sout | c | ' ' | wd(2,c) | wd(5,c) | left(wd(5,c)) | nobase(oct(c)) | oct(c) | nonl;
    104         sout | nobase(hex(c)) | hex(c) | wd(8,hex(c)) | upcase(wd(8,hex(c))) | left(wd(8,c)) | wd(8,c);
     82        sout | c | ' ' | wd(2,c) | wd(5,c) | left(wd(5,c)) | nobase(oct(c)) | oct(c) | nobase(hex(c)) | hex(c) | wd(8,hex(c)) | upcase(wd(8,hex(c))) | left(wd(8,c)) | wd(8,c);
    10583
    10684        sout | nl | "string";
  • tests/manipulatorsOutput2.cfa

    reef8dfb rbdfc032  
    77// Created On       : Sat Jun  8 18:04:11 2019
    88// Last Modified By : Peter A. Buhr
    9 // Last Modified On : Sun Nov 15 08:11:53 2020
    10 // Update Count     : 9
     9// Last Modified On : Mon Jun 10 12:37:57 2019
     10// Update Count     : 8
    1111//
    1212
     
    5252// Local Variables: //
    5353// tab-width: 4 //
    54 // compile-command: "cfa -Wall -Wextra manipulatorsOutput2.cfa" //
     54// compile-command: "cfa -Wall -Wextra amanipulatorsOutput2.cfa" //
    5555// End: //
  • tests/math4.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Thu May 24 20:56:54 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Aug 25 17:56:45 2020
    13 // Update Count     : 7
     12// Last Modified On : Tue Dec  4 18:15:01 2018
     13// Update Count     : 4
    1414//
    1515
     
    1818
    1919int main( void ) {
    20         signed char sc, scr1, scr2, scr3;
    21         unsigned char uc, ucr1, ucr2, ucr3;
    22         short int si, sir1, sir2, sir3;
    23         unsigned short int usi, usir1, usir2, usir3;
    24         int i, ir1, ir2, ir3;
    25         unsigned int ui, uir1, uir2, uir3;
    26         long int li, lir1, lir2, lir3;
    27         unsigned long int uli, ulir1, ulir2, ulir3;
    28         long long int lli, llir1, llir2, llir3;
    29         unsigned long long int ulli, ullir1, ullir2, ullir3;
    30 
    3120        float f;
    3221        double d;
     
    3423
    3524        //---------------------- Nearest Integer ----------------------
    36 
    37         //============================================================
    38 #if 1
    39         sout | nl | "floor" | nl | nl;
    40 
    41         printf( "signed char\n" );
    42         for ( sc = 1; sc != 0; sc <<= 1 ) {
    43                 scr1 = floor( sc, sc ); scr2 = floor( sc + 2hh, sc ); scr3 = floor( -sc - 2hh, sc );
    44                 printf( "floor(%hhd, %hhd) = %hhd, floor(%hhd, %hhd) = %hhd, floor(%hhd, %hhd) = %hhd\n", sc, sc, scr1, sc + 2hh, sc, scr2, -sc - 2hh, sc, scr3 );
    45         } // for
    46         printf( "\n" );
    47 
    48         printf( "unsigned char\n" );
    49         for ( uc = 1; uc != 0; uc <<= 1 ) {
    50                 ucr1 = floor( uc, uc ); ucr2 = floor( uc + 2hh, uc ); ucr3 = floor( -uc - 2hh, uc );
    51                 printf( "floor(%hhu, %hhu) = %hhu, floor(%hhu, %hhu) = %hhu, floor(%hhu, %hhu) = %hhu\n", uc, uc, ucr1, uc + 2uhh, uc, ucr2, -uc - 2uhh, uc, ucr3 );
    52         } // for
    53         printf( "\n" );
    54 
    55         printf( "short int\n" );
    56         for ( si = 1; si != 0; si <<= 1 ) {
    57                 sir1 = floor( si, si ); sir2 = floor( si + 2hh, si ); sir3 = floor( -si - 2hh, si );
    58                 printf( "floor(%hd, %hd) = %hd, floor(%hd, %hd) = %hd, floor(%hd, %hd) = %hd\n", si, si, sir1, si + 2h, si, sir2, -si - 2h, si, sir3 );
    59         } // for
    60         printf( "\n" );
    61 
    62         printf( "unsigned short int\n" );
    63         for ( usi = 1; usi != 0; usi <<= 1 ) {
    64                 usir1 = floor( usi, usi ); usir2 = floor( usi + 2hh, usi ); usir3 = floor( -usi - 2hh, usi );
    65                 printf( "floor(%hu, %hu) = %hu, floor(%hu, %hu) = %hu, floor(%hu, %hu) = %hu\n", usi, usi, usir1, usi + 2uh, usi, usir2, -usi - 2uh, usi, usir3 );
    66         } // for
    67         printf( "\n" );
    68 
    69         printf( "int\n" );
    70         for ( i = 1; i != 0; i <<= 1 ) {
    71                 ir1 = floor( i, i ); ir2 = floor( i + 2hh, i ); ir3 = floor( -i - 2hh, i );
    72                 printf( "floor(%d, %d) = %d, floor(%d, %d) = %d, floor(%d, %d) = %d\n", i, i, ir1, i + 2h, i, ir2, -i - 2h, i, ir3 );
    73         } // for
    74         printf( "\n" );
    75 
    76         printf( "unsigned int\n" );
    77         for ( ui = 1; ui != 0; ui <<= 1 ) {
    78                 uir1 = floor( ui, ui ); uir2 = floor( ui + 2hh, ui ); uir3 = floor( -ui - 2hh, ui );
    79                 printf( "floor(%u, %u) = %u, floor(%u, %u) = %u, floor(%u, %u) = %u\n", ui, ui, uir1, ui + 2h, ui, uir2, -ui - 2h, ui, uir3 );
    80         } // for
    81         printf( "\n" );
    82 
    83         printf( "long int\n" );
    84         for ( li = 1; li != 0; li <<= 1 ) {
    85                 lir1 = floor( li, li ); lir2 = floor( li + 2hh, li ); lir3 = floor( -li - 2hh, li );
    86                 printf( "floor(%ld, %ld) = %ld, floor(%ld, %ld) = %ld, floor(%ld, %ld) = %ld\n", li, li, lir1, li + 2h, li, lir2, -li - 2h, li, lir3 );
    87         } // for
    88         printf( "\n" );
    89 
    90         printf( "unsigned long int\n" );
    91         for ( uli = 1; uli != 0; uli <<= 1 ) {
    92                 ulir1 = floor( uli, uli ); ulir2 = floor( uli + 2hh, uli ); ulir3 = floor( -uli - 2hh, uli );
    93                 printf( "floor(%lu, %lu) = %lu, floor(%lu, %lu) = %lu, floor(%lu, %lu) = %lu\n", uli, uli, ulir1, uli + 2h, uli, ulir2, -uli - 2h, uli, ulir3 );
    94         } // for
    95         printf( "\n" );
    96 
    97         printf( "long long int\n" );
    98         for ( lli = 1; lli != 0; lli <<= 1 ) {
    99                 llir1 = floor( lli, lli ); llir2 = floor( lli + 2hh, lli ); llir3 = floor( -lli - 2hh, lli );
    100                 printf( "floor(%lld, %lld) = %lld, floor(%lld, %lld) = %lld, floor(%lld, %lld) = %lld\n", lli, lli, llir1, lli + 2h, lli, llir2, -lli - 2h, lli, llir3 );
    101         } // for
    102         printf( "\n" );
    103 
    104         printf( "unsigned long long int\n" );
    105         for ( ulli = 1; ulli != 0; ulli <<= 1 ) {
    106                 ullir1 = floor( ulli, ulli ); ullir2 = floor( ulli + 2hh, ulli ); ullir3 = floor( -ulli - 2hh, ulli );
    107                 printf( "floor(%llu, %llu) = %llu, floor(%llu, %llu) = %llu, floor(%llu, %llu) = %llu\n", ulli, ulli, ullir1, ulli + 2h, ulli, ullir2, -ulli - 2h, ulli, ullir3 );
    108         } // for
    109         printf( "\n" );
    110 #endif // 0
    111         //============================================================
    112 #if 1
    113         sout | nl | "ceiling_div" | nl | nl;
    114 
    115         printf( "signed char\n" );
    116         for ( sc = 1; sc != 0; sc <<= 1 ) {
    117                 scr1 = ceiling_div( sc, sc ); scr2 = ceiling_div( sc + 2hh, sc ); scr3 = ceiling_div( -sc - 2hh, sc );
    118                 printf( "ceiling_div(%hhd, %hhd) = %hhd, ceiling_div(%hhd, %hhd) = %hhd, ceiling_div(%hhd, %hhd) = %hhd\n", sc, sc, scr1, sc + 2hh, sc, scr2, -sc - 2hh, sc, scr3 );
    119         } // for
    120         printf( "\n" );
    121 
    122         printf( "unsigned char\n" );
    123         for ( uc = 1; uc != 0; uc <<= 1 ) {
    124                 ucr1 = ceiling_div( uc, uc ); ucr2 = ceiling_div( uc + 2hh, uc ); ucr3 = ceiling_div( -uc - 2hh, uc );
    125                 printf( "ceiling_div(%hhu, %hhu) = %hhu, ceiling_div(%hhu, %hhu) = %hhu, ceiling_div(%hhu, %hhu) = %hhu\n", uc, uc, ucr1, uc + 2uhh, uc, ucr2, -uc - 2uhh, uc, ucr3 );
    126         } // for
    127         printf( "\n" );
    128 
    129         printf( "short int\n" );
    130         for ( si = 1; si != 0; si <<= 1 ) {
    131                 sir1 = ceiling_div( si, si ); sir2 = ceiling_div( si + 2hh, si ); sir3 = ceiling_div( -si - 2hh, si );
    132                 printf( "ceiling_div(%hd, %hd) = %hd, ceiling_div(%hd, %hd) = %hd, ceiling_div(%hd, %hd) = %hd\n", si, si, sir1, si + 2h, si, sir2, -si - 2h, si, sir3 );
    133         } // for
    134         printf( "\n" );
    135 
    136         printf( "unsigned short int\n" );
    137         for ( usi = 1; usi != 0; usi <<= 1 ) {
    138                 usir1 = ceiling_div( usi, usi ); usir2 = ceiling_div( usi + 2hh, usi ); usir3 = ceiling_div( -usi - 2hh, usi );
    139                 printf( "ceiling_div(%hu, %hu) = %hu, ceiling_div(%hu, %hu) = %hu, ceiling_div(%hu, %hu) = %hu\n", usi, usi, usir1, usi + 2uh, usi, usir2, -usi - 2uh, usi, usir3 );
    140         } // for
    141         printf( "\n" );
    142 
    143         printf( "int\n" );
    144         for ( i = 1; i != 0; i <<= 1 ) {
    145                 ir1 = ceiling_div( i, i ); ir2 = ceiling_div( i + 2hh, i ); ir3 = ceiling_div( -i - 2hh, i );
    146                 printf( "ceiling_div(%d, %d) = %d, ceiling_div(%d, %d) = %d, ceiling_div(%d, %d) = %d\n", i, i, ir1, i + 2h, i, ir2, -i - 2h, i, ir3 );
    147         } // for
    148         printf( "\n" );
    149 
    150         printf( "unsigned int\n" );
    151         for ( ui = 1; ui != 0; ui <<= 1 ) {
    152                 uir1 = ceiling_div( ui, ui ); uir2 = ceiling_div( ui + 2hh, ui ); uir3 = ceiling_div( -ui - 2hh, ui );
    153                 printf( "ceiling_div(%u, %u) = %u, ceiling_div(%u, %u) = %u, ceiling_div(%u, %u) = %u\n", ui, ui, uir1, ui + 2h, ui, uir2, -ui - 2h, ui, uir3 );
    154         } // for
    155         printf( "\n" );
    156 
    157         printf( "long int\n" );
    158         for ( li = 1; li != 0; li <<= 1 ) {
    159                 lir1 = ceiling_div( li, li ); lir2 = ceiling_div( li + 2hh, li ); lir3 = ceiling_div( -li - 2hh, li );
    160                 printf( "ceiling_div(%ld, %ld) = %ld, ceiling_div(%ld, %ld) = %ld, ceiling_div(%ld, %ld) = %ld\n", li, li, lir1, li + 2h, li, lir2, -li - 2h, li, lir3 );
    161         } // for
    162         printf( "\n" );
    163 
    164         printf( "unsigned long int\n" );
    165         for ( uli = 1; uli != 0; uli <<= 1 ) {
    166                 ulir1 = ceiling_div( uli, uli ); ulir2 = ceiling_div( uli + 2hh, uli ); ulir3 = ceiling_div( -uli - 2hh, uli );
    167                 printf( "ceiling_div(%lu, %lu) = %lu, ceiling_div(%lu, %lu) = %lu, ceiling_div(%lu, %lu) = %lu\n", uli, uli, ulir1, uli + 2h, uli, ulir2, -uli - 2h, uli, ulir3 );
    168         } // for
    169         printf( "\n" );
    170 
    171         printf( "long long int\n" );
    172         for ( lli = 1; lli != 0; lli <<= 1 ) {
    173                 llir1 = ceiling_div( lli, lli ); llir2 = ceiling_div( lli + 2hh, lli ); llir3 = ceiling_div( -lli - 2hh, lli );
    174                 printf( "ceiling_div(%lld, %lld) = %lld, ceiling_div(%lld, %lld) = %lld, ceiling_div(%lld, %lld) = %lld\n", lli, lli, llir1, lli + 2h, lli, llir2, -lli - 2h, lli, llir3 );
    175         } // for
    176         printf( "\n" );
    177 
    178         printf( "unsigned long long int\n" );
    179         for ( ulli = 1; ulli != 0; ulli <<= 1 ) {
    180                 ullir1 = ceiling_div( ulli, ulli ); ullir2 = ceiling_div( ulli + 2hh, ulli ); ullir3 = ceiling_div( -ulli - 2hh, ulli );
    181                 printf( "ceiling_div(%llu, %llu) = %llu, ceiling_div(%llu, %llu) = %llu, ceiling_div(%llu, %llu) = %llu\n", ulli, ulli, ullir1, ulli + 2h, ulli, ullir2, -ulli - 2h, ulli, ullir3 );
    182         } // for
    183         printf( "\n" );
    184 #endif // 0
    185         //============================================================
    186 #if 1
    187         sout | nl | "ceiling" | nl | nl;
    188 
    189         printf( "signed char\n" );
    190         for ( sc = 1; sc != 0; sc <<= 1 ) {
    191                 scr1 = ceiling( sc, sc ); scr2 = ceiling( sc + 2hh, sc ); scr3 = ceiling( -sc - 2hh, sc );
    192                 printf( "ceiling(%hhd, %hhd) = %hhd, ceiling(%hhd, %hhd) = %hhd, ceiling(%hhd, %hhd) = %hhd\n", sc, sc, scr1, sc + 2hh, sc, scr2, -sc - 2hh, sc, scr3 );
    193         } // for
    194         printf( "\n" );
    195 
    196         printf( "unsigned char\n" );
    197         for ( uc = 1; uc != 0; uc <<= 1 ) {
    198                 ucr1 = ceiling( uc, uc ); ucr2 = ceiling( uc + 2hh, uc ); ucr3 = ceiling( -uc - 2hh, uc );
    199                 printf( "ceiling(%hhu, %hhu) = %hhu, ceiling(%hhu, %hhu) = %hhu, ceiling(%hhu, %hhu) = %hhu\n", uc, uc, ucr1, uc + 2uhh, uc, ucr2, -uc - 2uhh, uc, ucr3 );
    200         } // for
    201         printf( "\n" );
    202 
    203         printf( "short int\n" );
    204         for ( si = 1; si != 0; si <<= 1 ) {
    205                 sir1 = ceiling( si, si ); sir2 = ceiling( si + 2hh, si ); sir3 = ceiling( -si - 2hh, si );
    206                 printf( "ceiling(%hd, %hd) = %hd, ceiling(%hd, %hd) = %hd, ceiling(%hd, %hd) = %hd\n", si, si, sir1, si + 2h, si, sir2, -si - 2h, si, sir3 );
    207         } // for
    208         printf( "\n" );
    209 
    210         printf( "unsigned short int\n" );
    211         for ( usi = 1; usi != 0; usi <<= 1 ) {
    212                 usir1 = ceiling( usi, usi ); usir2 = ceiling( usi + 2hh, usi ); usir3 = ceiling( -usi - 2hh, usi );
    213                 printf( "ceiling(%hu, %hu) = %hu, ceiling(%hu, %hu) = %hu, ceiling(%hu, %hu) = %hu\n", usi, usi, usir1, usi + 2uh, usi, usir2, -usi - 2uh, usi, usir3 );
    214         } // for
    215         printf( "\n" );
    216 
    217         printf( "int\n" );
    218         for ( i = 1; i != 0; i <<= 1 ) {
    219                 ir1 = ceiling( i, i ); ir2 = ceiling( i + 2hh, i ); ir3 = ceiling( -i - 2hh, i );
    220                 printf( "ceiling(%d, %d) = %d, ceiling(%d, %d) = %d, ceiling(%d, %d) = %d\n", i, i, ir1, i + 2h, i, ir2, -i - 2h, i, ir3 );
    221         } // for
    222         printf( "\n" );
    223 
    224         printf( "unsigned int\n" );
    225         for ( ui = 1; ui != 0; ui <<= 1 ) {
    226                 uir1 = ceiling( ui, ui ); uir2 = ceiling( ui + 2hh, ui ); uir3 = ceiling( -ui - 2hh, ui );
    227                 printf( "ceiling(%u, %u) = %u, ceiling(%u, %u) = %u, ceiling(%u, %u) = %u\n", ui, ui, uir1, ui + 2h, ui, uir2, -ui - 2h, ui, uir3 );
    228         } // for
    229         printf( "\n" );
    230 
    231         printf( "long int\n" );
    232         for ( li = 1; li != 0; li <<= 1 ) {
    233                 lir1 = ceiling( li, li ); lir2 = ceiling( li + 2hh, li ); lir3 = ceiling( -li - 2hh, li );
    234                 printf( "ceiling(%ld, %ld) = %ld, ceiling(%ld, %ld) = %ld, ceiling(%ld, %ld) = %ld\n", li, li, lir1, li + 2h, li, lir2, -li - 2h, li, lir3 );
    235         } // for
    236         printf( "\n" );
    237 
    238         printf( "unsigned long int\n" );
    239         for ( uli = 1; uli != 0; uli <<= 1 ) {
    240                 ulir1 = ceiling( uli, uli ); ulir2 = ceiling( uli + 2hh, uli ); ulir3 = ceiling( -uli - 2hh, uli );
    241                 printf( "ceiling(%lu, %lu) = %lu, ceiling(%lu, %lu) = %lu, ceiling(%lu, %lu) = %lu\n", uli, uli, ulir1, uli + 2h, uli, ulir2, -uli - 2h, uli, ulir3 );
    242         } // for
    243         printf( "\n" );
    244 
    245         printf( "long long int\n" );
    246         for ( lli = 1; lli != 0; lli <<= 1 ) {
    247                 llir1 = ceiling( lli, lli ); llir2 = ceiling( lli + 2hh, lli ); llir3 = ceiling( -lli - 2hh, lli );
    248                 printf( "ceiling(%lld, %lld) = %lld, ceiling(%lld, %lld) = %lld, ceiling(%lld, %lld) = %lld\n", lli, lli, llir1, lli + 2h, lli, llir2, -lli - 2h, lli, llir3 );
    249         } // for
    250         printf( "\n" );
    251 
    252         printf( "unsigned long long int\n" );
    253         for ( ulli = 1; ulli != 0; ulli <<= 1 ) {
    254                 ullir1 = ceiling( ulli, ulli ); ullir2 = ceiling( ulli + 2hh, ulli ); ullir3 = ceiling( -ulli - 2hh, ulli );
    255                 printf( "ceiling(%llu, %llu) = %llu, ceiling(%llu, %llu) = %llu, ceiling(%llu, %llu) = %llu\n", ulli, ulli, ullir1, ulli + 2h, ulli, ullir2, -ulli - 2h, ulli, ullir3 );
    256         } // for
    257         printf( "\n" );
    258 #endif // 0
    25925
    26026        sout | "floor:" | floor( 1.2F ) | floor( 1.2D ) | floor( 1.2L );
     
    30369// Local Variables: //
    30470// tab-width: 4 //
    305 // compile-command: "cfa math4.cfa" //
     71// compile-command: "cfa math3.cfa" //
    30672// End: //
  • tests/maybe.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Thr May 25 16:02:00 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Sep 25 15:13:28 2020
    13 // Update Count     : 2
     12// Last Modified On : Thu Jul 20 15:24:07 2017
     13// Update Count     : 1
    1414//
    1515
     
    6565        //checkNamedConstructors();
    6666        checkSetters();
    67         printf( "done\n" );                             // non-empty .expect file
    6867}
  • tests/minmax.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 15 08:28:01 2020
    13 // Update Count     : 54
     12// Last Modified On : Tue Dec  4 21:45:31 2018
     13// Update Count     : 52
    1414//
    1515
     
    2323
    2424        sout | "char\t\t\t"                                     | 'z' | ' ' | 'a' | "\tmin " | min( 'z', 'a' );
    25         sout | "signed int\t\t"                         | 4 | -3 | "\tmin" | min( 4, -3 );
     25        sout | "signed int\t\t"                         | 4 | 3 | "\tmin" | min( 4, 3 );
    2626        sout | "unsigned int\t\t"                       | 4u | 3u | "\tmin" | min( 4u, 3u );
    27         sout | "signed long int\t\t"            | 4l | -3l | "\tmin" | min( 4l, -3l );
     27        sout | "signed long int\t\t"            | 4l | 3l | "\tmin" | min( 4l, 3l );
    2828        sout | "unsigned long int\t"            | 4ul | 3ul | "\tmin" | min( 4ul, 3ul );
    29         sout | "signed long long int\t"         | 4ll | -3ll | "\tmin" | min( 4ll, -3ll );
     29        sout | "signed long long int\t"         | 4ll | 3ll | "\tmin" | min( 4ll, 3ll );
    3030        sout | "unsigned long long int\t"       | 4ull | 3ull | "\tmin" | min( 4ull, 3ull );
    3131        sout | "float\t\t\t"                            | 4.0f | 3.1f | "\tmin" | min( 4.0f, 3.1f );
     
    3636
    3737        sout | "char\t\t\t"                                     | 'z' | ' ' | 'a' | "\tmax " | max( 'z', 'a' );
    38         sout | "signed int\t\t"                         | 4 | -3 | "\tmax" | max( 4, -3 );
     38        sout | "signed int\t\t"                         | 4 | 3 | "\tmax" | max( 4, 3 );
    3939        sout | "unsigned int\t\t"                       | 4u | 3u | "\tmax" | max( 4u, 3u );
    40         sout | "signed long int\t\t"            | 4l | -3l | "\tmax" | max( 4l, -3l );
     40        sout | "signed long int\t\t"            | 4l | 3l | "\tmax" | max( 4l, 3l );
    4141        sout | "unsigned long int\t"            | 4ul | 3ul | "\tmax" | max( 4ul, 3ul );
    42         sout | "signed long long int\t"         | 4ll | -3ll | "\tmax" | max( 4ll, -3ll );
     42        sout | "signed long long int\t"         | 4ll | 3ll | "\tmax" | max( 4ll, 3ll );
    4343        sout | "unsigned long long int\t"       | 4ull | 3ull | "\tmax" | max( 4ull, 3ull );
    4444        sout | "float\t\t\t"                            | 4.0f | 3.1f | "\tmax" | max( 4.0f, 3.1f );
  • tests/nested-types.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Mon Jul 9 10:20:03 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 08:48:59 2020
    13 // Update Count     : 6
     12// Last Modified On : Tue Nov  6 17:59:40 2018
     13// Update Count     : 2
    1414//
    1515
    1616typedef int N;
    1717struct A {
    18         forall(otype T)
    19         struct N {
    20                 T x;
    21         };
     18  forall(otype T)
     19  struct N {
     20    T x;
     21  };
    2222};
    2323
    2424struct S {
    25         struct T {
    26                 int i;
    27                 typedef int Bar;
    28         };
    29         T x;
     25  struct T {
     26    int i;
     27    typedef int Bar;
     28  };
     29  T x;
    3030
    31         // struct U;
    32         typedef T Bar;
    33         typedef int Baz;
     31  // struct U;
     32  typedef T Bar;
     33  typedef int Baz;
    3434};
    3535
     
    5151// };
    5252
    53 // struct S {
    54 //     enum C { R, G, B };
    55 //     int i;
    56 //     struct T {
    57 //      int i;
    58 //     };
    59 //     T t;
    60 // };
     53int main() {
     54  // access nested struct
     55  S.T x;
    6156
    62 // S s;
    63 // S.C c;
    64 // S.T t;
     57  {
     58    struct S {
     59      int i;
     60      struct Z {
     61        double d;
     62      };
     63    };
    6564
    66 int main() {
    67         // access nested struct
    68         S.T x;
     65    S.Z z;   // gets local S
     66    .S.T y;  // lookup at global scope only
    6967
    70         {
    71                 struct S {
    72                   int i;
    73                   struct Z {
    74                     double d;
    75                   };
    76                 };
    77 
    78                 S.Z z;                                                                                  // gets local S
    79                 .S.T y;                                                                                 // lookup at global scope only
    80 
    81                 const volatile .S.T q;
     68    const volatile .S.T q;
    8269#if ERR1
    83                 T err1;                                                                                 // error: no T in scope
     70    T err1;           // error: no T in scope
    8471#endif
    8572#if ERR2
    86                 .Z err2;                                                                                // error: no Z in global scope
    87                 .S.Baz.Bar err3;                                                                // error: .S.Baz => int, int is not aggregate and should not appear left of the dot
    88                 .S.Z err4;                                                                              // error: no Z in global S
     73    .Z err2;          // error: no Z in global scope
     74    .S.Baz.Bar err3;  // error: .S.Baz => int, int is not aggregate and should not appear left of the dot
     75    .S.Z err4;        // error: no Z in global S
    8976#endif
    90         }
     77  }
    9178
    92         // U.S un;
     79  // U.S un;
    9380
    94         S.Bar y;
    95         S.Baz x;
    96         S.T.Bar z;
     81  S.Bar y;
     82  S.Baz x;
     83  S.T.Bar z;
    9784
    98         // A.N(int) x;  // xxx - should not be an error, but currently is.
    99 
    100         #pragma message( "Compiled" )                   // force non-empty .expect file
     85  // A.N(int) x;  // xxx - should not be an error, but currently is.
    10186}
    10287
  • tests/numericConstants.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed May 24 22:10:36 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 07:55:22 2020
    13 // Update Count     : 7
     12// Last Modified On : Tue Feb  5 08:58:16 2019
     13// Update Count     : 5
    1414//
    1515
     
    6363        0x_ff.ffp0;                                     // hex real
    6464        0x_1.ffff_ffff_p_128_l;
    65 
    66         #pragma message( "Compiled" )   // force non-empty .expect file
    6765} // main
    6866
  • tests/operators.cfa

    reef8dfb rbdfc032  
    3131int main(int argc, char const *argv[]) {
    3232        /* code */
    33         printf( "done\n" );                             // non-empty .expect file
     33        return 0;
    3434}
    3535
  • tests/pybin/settings.py

    reef8dfb rbdfc032  
    2323class Architecture:
    2424        KnownArchitectures = {
    25                 'x64'         : 'x64',
    26                 'x86-64'      : 'x64',
    27                 'x86_64'      : 'x64',
    28                 'x86'         : 'x86',
    29                 'aarch64'     : 'arm64',
    30                 'arm64'       : 'arm64',
    31                 'ARM64'       : 'arm64',
    32                 'i386'        : 'x86',
    33                 'i486'        : 'x86',
    34                 'i686'        : 'x86',
    35                 'Intel 80386' : 'x86',
    36                 'arm'         : 'arm32',
    37                 'ARM'         : 'arm32',
    38                 'arm32'       : 'arm32',
    39                 'ARM32'       : 'arm32',
     25                'x64'           : 'x64',
     26                'x86-64'        : 'x64',
     27                'x86_64'        : 'x64',
     28                'x86'           : 'x86',
     29                'aarch64'       : 'arm',
     30                'i386'          : 'x86',
     31                'i486'          : 'x86',
     32                'i686'          : 'x86',
     33                'Intel 80386'   : 'x86',
     34                'arm'           : 'arm',
     35                'ARM'           : 'arm',
    4036        }
    4137
    4238        CrossCompileFlags = {
    43                 'x64'  : 'ARCH_FLAGS=-m64',
    44                 'x86'  : 'ARCH_FLAGS=-m32',
    45                 'arm64': 'ARCH_FLAGS=',
    46                 'arm32': 'ARCH_FLAGS=',
     39                'x64' : 'ARCH_FLAGS=-m64',
     40                'x86' : 'ARCH_FLAGS=-m32',
    4741        }
    4842
     
    8377                        print("updated to %s" % self.target)
    8478
    85         def filter(self, tests):
    86                 return [test for test in tests if not test.arch or self.target == test.arch]
     79        def match(self, arch):
     80                return True if not arch else self.target == arch
    8781
    88         @staticmethod
    89         def make_canonical(arch):
     82        @classmethod
     83        def make_canonical(_, arch):
    9084                return Architecture.KnownArchitectures[arch]
    9185
     
    9690                self.flags  = """DEBUG_FLAGS=%s""" % ("-debug -O0" if value else "-nodebug -O2")
    9791                self.path   = "debug" if value else "nodebug"
    98 
    99 class AST:
    100         def __init__(self, ast):
    101                 if ast == "new":
    102                         self.target = ast
    103                         self.string = "New AST"
    104                         self.flags  = """AST_FLAGS=-XCFA,--new-ast"""
    105                 elif ast == "old":
    106                         self.target = ast
    107                         self.string = "Old AST"
    108                         self.flags  = """AST_FLAGS=-XCFA,--old-ast"""
    109                 elif ast == None:
    110                         self.target = "new" if config.NEWAST else "old"
    111                         self.string = "Default AST (%s)" % self.target
    112                         self.flags  = """AST_FLAGS="""
    113                 else:
    114                         print("""ERROR: Invalid ast configuration, must be "old", "new" or left unspecified, was %s""" % (value), file=sys.stderr)
    115                         sys.exit(1)
    116 
    117         def filter(self, tests):
    118 
    119                 return [test for test in tests if not test.astv or self.target == test.astv]
    12092
    12193class Install:
     
    132104                self.total  = Timeouts.check(tg)
    133105
    134         @staticmethod
    135         def check(value):
     106        @classmethod
     107        def check(_, value):
    136108                if value < 1:
    137109                        print("Timeouts must be at least 1 second", file=sys.stderr)
     
    141113
    142114def init( options ):
    143         global all_ast
    144         global all_arch
    145         global all_debug
    146         global all_install
    147         global ast
    148115        global arch
     116        global archive
    149117        global debug
    150         global archive
    151         global install
    152 
    153         global continue_
     118        global distcc
    154119        global dry_run
    155120        global generating
     121        global install
    156122        global make
    157123        global output_width
    158124        global timeout
    159         global timeout2gdb
    160125
    161         all_ast      = [AST(o)          for o in list(dict.fromkeys(options.ast    ))] if options.ast  else [AST(None)]
    162         all_arch     = [Architecture(o) for o in list(dict.fromkeys(options.arch   ))] if options.arch else [Architecture(None)]
    163         all_debug    = [Debug(o)        for o in list(dict.fromkeys(options.debug  ))]
    164         all_install  = [Install(o)      for o in list(dict.fromkeys(options.install))]
     126        arch         = Architecture(options.arch)
    165127        archive      = os.path.abspath(os.path.join(original_path, options.archive_errors)) if options.archive_errors else None
    166         continue_    = options.continue_
     128        debug        = Debug(options.debug)
    167129        dry_run      = options.dry_run # must be called before tools.config_hash()
     130        distcc       = "DISTCC_CFA_PATH=~/.cfadistcc/%s/cfa" % tools.config_hash()
    168131        generating   = options.regenerate_expected
     132        install      = Install(options.install)
    169133        make         = ['make']
    170134        output_width = 24
    171135        timeout      = Timeouts(options.timeout, options.global_timeout)
    172         timeout2gdb  = options.timeout_with_gdb
    173136
    174137        # if we distribute, distcc errors will fail tests, use log file for distcc
     
    183146
    184147def validate():
    185         """Validate the current configuration and update globals"""
    186 
    187         global distcc
    188         distcc       = "DISTCC_CFA_PATH=~/.cfadistcc/%s/cfa" % tools.config_hash()
    189148        errf = os.path.join(BUILDDIR, ".validate.err")
    190149        make_ret, out = tools.make( ".validate", error_file = errf, output_file=subprocess.DEVNULL, error=subprocess.DEVNULL )
  • tests/pybin/test_run.py

    reef8dfb rbdfc032  
    1111                self.path = ''
    1212                self.arch = ''
    13                 self.astv = ''
    1413
    1514        def toString(self):
    16                 return "{:25s} ({:5s} arch, {:s} ast: {:s})".format( self.name, self.arch if self.arch else "Any", self.astv if self.astv else "Any", self.target() )
     15                return "{:25s} ({:5s} {:s})".format( self.name, self.arch if self.arch else "Any", self.target() )
    1716
    1817        def prepare(self):
     
    2120
    2221        def expect(self):
    23                 arch = '' if not self.arch else ".%s" % self.arch
    24                 astv = '' if not self.astv else ".nast" if self.astv == "new" else ".oast"
    25                 return os.path.normpath( os.path.join(settings.SRCDIR  , self.path, ".expect", "%s%s%s.txt" % (self.name,astv,arch)) )
     22                return os.path.normpath( os.path.join(settings.SRCDIR  , self.path, ".expect", "%s%s.txt" % (self.name,'' if not self.arch else ".%s" % self.arch)) )
    2623
    2724        def error_log(self):
     
    4340                return os.path.normpath( os.path.join(settings.BUILDDIR, self.path, self.name) )
    4441
    45         @staticmethod
    46         def valid_name(name):
     42        @classmethod
     43        def valid_name(_, name):
    4744                return not name.endswith( ('.c', '.cc', '.cpp', '.cfa') )
    4845
    49         @staticmethod
    50         def new_target(target, arch, astv):
     46        @classmethod
     47        def from_target(_, target):
    5148                test = Test()
    5249                test.name = os.path.basename(target)
    5350                test.path = os.path.relpath (os.path.dirname(target), settings.SRCDIR)
    54                 test.arch = arch.target if arch else ''
    55                 test.astv = astv.target if astv else ''
     51                test.arch = settings.arch.target if settings.arch.cross_compile else ''
    5652                return test
    5753
     
    7369                        else :                                          text = "FAILED with code %d" % retcode
    7470
    75                 text += "    C%s - R%s" % (fmtDur(duration[0]), fmtDur(duration[1]))
     71                text += "    C%s - R%s" % (cls.fmtDur(duration[0]), cls.fmtDur(duration[1]))
    7672                return text
     73
     74        @classmethod
     75        def fmtDur( cls, duration ):
     76                if duration :
     77                        hours, rem = divmod(duration, 3600)
     78                        minutes, rem = divmod(rem, 60)
     79                        seconds, millis = divmod(rem, 1)
     80                        return "%2d:%02d.%03d" % (minutes, seconds, millis * 1000)
     81                return " n/a"
  • tests/pybin/tools.py

    reef8dfb rbdfc032  
    7373                                        )
    7474
    75                                         return proc.returncode, out.decode("latin-1") if out else None
     75                                        return proc.returncode, out.decode("utf-8") if out else None
    7676                                except subprocess.TimeoutExpired:
    77                                         if settings.timeout2gdb:
    78                                                 print("Process {} timeout".format(proc.pid))
    79                                                 proc.communicate()
    80                                                 return 124, str(None)
    81                                         else:
    82                                                 proc.send_signal(signal.SIGABRT)
    83                                                 proc.communicate()
    84                                                 return 124, str(None)
     77                                        proc.send_signal(signal.SIGABRT)
     78                                        proc.communicate()
     79                                        return 124, str(None)
    8580
    8681        except Exception as ex:
     
    8883                raise
    8984
    90 def is_empty(fname):
    91         if not os.path.isfile(fname):
    92                 return True
    93 
    94         if os.stat(fname).st_size == 0:
    95                 return True
    96 
    97         return False
    98 
    9985def is_ascii(fname):
    10086        if settings.dry_run:
    10187                print("is_ascii: %s" % fname)
    102                 return (True, "")
     88                return True
    10389
    10490        if not os.path.isfile(fname):
    105                 return (False, "No file")
    106 
    107         code, out = sh("file", fname, output_file=subprocess.PIPE)
     91                return False
     92
     93        code, out = sh("file %s" % fname, output_file=subprocess.PIPE)
    10894        if code != 0:
    109                 return (False, "'file EXPECT' failed with code {}".format(code))
     95                return False
    11096
    11197        match = re.search(".*: (.*)", out)
    11298
    11399        if not match:
    114                 return (False, "Unreadable file type: '{}'".format(out))
    115 
    116         if "ASCII text" in match.group(1):
    117                 return (True, "")
    118 
    119         return (False, "File type should be 'ASCII text', was '{}'".format(match.group(1)))
     100                return False
     101
     102        return match.group(1).startswith("ASCII text")
    120103
    121104def is_exe(fname):
     
    132115                return None
    133116
    134         file = open(file, mode, encoding="latin-1") # use latin-1 so all chars mean something.
     117        file = open(file, mode)
    135118        exitstack.push(file)
    136119        return file
     
    181164                '-s' if silent else None,
    182165                test_param,
    183                 settings.ast.flags,
    184166                settings.arch.flags,
    185167                settings.debug.flags,
     
    192174        return sh(*cmd, output_file=output_file, error=error)
    193175
    194 def make_recon(target):
    195         cmd = [
    196                 *settings.make,
    197                 '-W',
    198                 os.path.abspath(os.path.join(settings.BUILDDIR, '../driver/cfa')),
    199                 '--recon',
    200                 target
    201         ]
    202         cmd = [s for s in cmd if s]
    203         return sh(*cmd, output_file=subprocess.PIPE)
    204 
    205176def which(program):
    206         fpath, fname = os.path.split(program)
    207         if fpath:
    208                 if is_exe(program):
    209                         return program
    210         else:
    211                 for path in os.environ["PATH"].split(os.pathsep):
    212                         exe_file = os.path.join(path, program)
    213                         if is_exe(exe_file):
    214                                 return exe_file
    215         return None
     177    fpath, fname = os.path.split(program)
     178    if fpath:
     179        if is_exe(program):
     180            return program
     181    else:
     182        for path in os.environ["PATH"].split(os.pathsep):
     183            exe_file = os.path.join(path, program)
     184            if is_exe(exe_file):
     185                return exe_file
     186
     187    return None
    216188
    217189@contextlib.contextmanager
     
    262234# helper function to check if a files contains only a specific string
    263235def file_contains_only(file, text) :
    264         with open(file, encoding="latin-1") as f: # use latin-1 so all chars mean something.
     236        with open(file) as f:
    265237                ff = f.read().strip()
    266238                result = ff == text.strip()
     
    270242# transform path to canonical form
    271243def canonical_path(path):
    272         abspath = os.path.abspath(os.path.realpath(__main__.__file__))
     244        abspath = os.path.abspath(__main__.__file__)
    273245        dname = os.path.dirname(abspath)
    274246        return os.path.join(dname, os.path.normpath(path) )
     
    351323        raise argparse.ArgumentTypeError(msg)
    352324
    353 # Convert a function that converts a string to one that converts comma separated string.
    354 def comma_separated(elements):
    355     return lambda string: [elements(part) for part in string.split(',')]
    356 
    357325def fancy_print(text):
    358326        column = which('column')
     
    397365
    398366class Timed:
    399         def __enter__(self):
    400                 self.start = time.time()
    401                 return self
    402 
    403         def __exit__(self, *args):
    404                 self.end = time.time()
    405                 self.duration = self.end - self.start
     367    def __enter__(self):
     368        self.start = time.time()
     369        return self
     370
     371    def __exit__(self, *args):
     372        self.end = time.time()
     373        self.duration = self.end - self.start
    406374
    407375def timed(src, timeout):
    408376        expire = time.time() + timeout
    409377        i = iter(src)
    410         with contextlib.suppress(StopIteration):
    411                 while True:
    412                         yield i.next(max(expire - time.time(), 0))
    413 
    414 def fmtDur( duration ):
    415         if duration :
    416                 hours, rem = divmod(duration, 3600)
    417                 minutes, rem = divmod(rem, 60)
    418                 seconds, millis = divmod(rem, 1)
    419                 return "%2d:%02d.%03d" % (minutes, seconds, millis * 1000)
    420         return " n/a"
     378        while True:
     379                yield i.next(max(expire - time.time(), 0))
  • tests/quotedKeyword.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:07:07 2020
    13 // Update Count     : 25
     12// Last Modified On : Sat Feb  1 00:02:22 2020
     13// Update Count     : 24
    1414//
    1515
     
    1717
    1818struct {
    19         int ``otype;
    20         int ``struct;
     19        int ``otype``;
     20        int ``struct``;
    2121} st = { 10, 10 };
    2222
    23 typedef int ``forall;
    24 ``forall xxx = 10;
     23typedef int ``forall``;
     24``forall`` xxx = 10;
    2525
    26 int ``_Alignas, ``_Alignof, ``__alignof, ``__alignof__, ``asm, ``__asm, ``__asm__, ``_At, ``_Atomic, ``__attribute,
    27         ``__attribute__, ``auto, ``_Bool, ``break, ``case, ``catch, ``catchResume, ``char, ``choose, ``_Complex, ``__complex,
    28         ``__complex__, ``const, ``__const, ``__const__, ``continue, ``default, ``disable, ``do, ``double, ``dtype, ``else,
    29         ``enable, ``enum, ``__extension__, ``extern, ``fallthru, ``finally, ``float, ``__float128, ``for, ``forall, ``fortran,
    30         ``ftype, ``_Generic, ``goto, ``if, ``_Imaginary, ``__imag, ``__imag__, ``inline, ``__inline, ``__inline__, ``int,
    31         ``__int128, ``__label__, ``long, ``lvalue, ``_Noreturn, ``__builtin_offsetof, ``otype, ``register, ``restrict,
    32         ``__restrict, ``__restrict__, ``return, ``short, ``signed, ``__signed, ``__signed__, ``sizeof, ``static,
    33         ``_Static_assert, ``struct, ``switch, ``_Thread_local, ``throw, ``throwResume, ``trait, ``try, ``typedef,
    34         ``typeof, ``__typeof, ``__typeof__, ``union, ``unsigned, ``__builtin_va_list, ``void, ``volatile, ``__volatile,
    35         ``__volatile__, ``while;
     26int ``_Alignas``, ``_Alignof``, ``__alignof``, ``__alignof__``, ``asm``, ``__asm``, ``__asm__``, ``_At``, ``_Atomic``, ``__attribute``,
     27        ``__attribute__``, ``auto``, ``_Bool``, ``break``, ``case``, ``catch``, ``catchResume``, ``char``, ``choose``, ``_Complex``, ``__complex``,
     28        ``__complex__``, ``const``, ``__const``, ``__const__``, ``continue``, ``default``, ``disable``, ``do``, ``double``, ``dtype``, ``else``,
     29        ``enable``, ``enum``, ``__extension__``, ``extern``, ``fallthru``, ``finally``, ``float``, ``__float128``, ``for``, ``forall``, ``fortran``,
     30        ``ftype``, ``_Generic``, ``goto``, ``if``, ``_Imaginary``, ``__imag``, ``__imag__``, ``inline``, ``__inline``, ``__inline__``, ``int``,
     31        ``__int128``, ``__label__``, ``long``, ``lvalue``, ``_Noreturn``, ``__builtin_offsetof``, ``otype``, ``register``, ``restrict``,
     32        ``__restrict``, ``__restrict__``, ``return``, ``short``, ``signed``, ``__signed``, ``__signed__``, ``sizeof``, ``static``,
     33        ``_Static_assert``, ``struct``, ``switch``, ``_Thread_local``, ``throw``, ``throwResume``, ``trait``, ``try``, ``typedef``,
     34        ``typeof``, ``__typeof``, ``__typeof__``, ``union``, ``unsigned``, ``__builtin_va_list``, ``void``, ``volatile``, ``__volatile``,
     35        ``__volatile__``, ``while``;
    3636
    3737int main() {
    38         int ``if = 0;
    39         ``catch = 1;
    40         st.``otype = 2;
    41         st.``struct = 3;
    42         ``throw = 4;
    43         sout | ``catch + st.``otype + st.``struct + ``throw;
     38        int ``if`` = 0;
     39        ``catch`` = 1;
     40        st.``otype`` = 2;
     41        st.``struct`` = 3;
     42        ``throw`` = 4;
     43        sout | ``catch`` + st.``otype`` + st.``struct`` + ``throw``;
    4444}
    4545
  • tests/raii/.expect/ctor-autogen.txt

    reef8dfb rbdfc032  
    1 done
  • tests/raii/.expect/init_once.txt

    reef8dfb rbdfc032  
    1 done
  • tests/raii/ctor-autogen.cfa

    reef8dfb rbdfc032  
    151151        identity(gcs);
    152152        identity(gcu);
    153         printf( "done\n" );                             // non-empty .expect file
    154153}
  • tests/raii/init_once.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Jun 14 15:43:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Sep 25 15:36:39 2020
    13 // Update Count     : 5
     12// Last Modified On : Fri Mar 22 13:41:26 2019
     13// Update Count     : 4
    1414//
    1515
     
    188188                static_variable();
    189189        }
    190         printf( "done\n" );                                                                     // non-empty .expect file
    191190}
    192191
  • tests/rational.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Mon Mar 28 08:43:12 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb  8 18:46:23 2020
    13 // Update Count     : 86
     12// Last Modified On : Wed Mar 27 07:37:17 2019
     13// Update Count     : 80
    1414//
    1515
     
    1919#include <fstream.hfa>
    2020
    21 typedef Rational(int) RatInt;
    22 double convert( int i ) { return (double)i; }                   // used by narrow/widen
     21double convert( int i ) { return (double)i; }
    2322int convert( double d ) { return (int)d; }
    2423
    2524int main() {
    2625        sout | "constructor";
    27         RatInt a = { 3 }, b = { 4 }, c, d = 0, e = 1;
    28         sout | a | b | c | d | e;
     26        Rational(int) a = { 3 }, b = { 4 }, c;
     27        sout | a | b | c;
    2928
    30         a = (RatInt){ 4, 8 };
    31         b = (RatInt){ 5, 7 };
     29        a = (Rational(int)){ 4, 8 };
     30        b = (Rational(int)){ 5, 7 };
    3231        sout | a | b;
    33         a = (RatInt){ -2, -3 };
    34         b = (RatInt){ 3, -2 };
     32        a = (Rational(int)){ -2, -3 };
     33        b = (Rational(int)){ 3, -2 };
    3534        sout | a | b;
    36         a = (RatInt){ -2, 3 };
    37         b = (RatInt){ 3, 2 };
     35        a = (Rational(int)){ -2, 3 };
     36        b = (Rational(int)){ 3, 2 };
    3837        sout | a | b;
    3938
    4039        sout | "logical";
    41         a = (RatInt){ -2 };
    42         b = (RatInt){ -3, 2 };
     40        a = (Rational(int)){ -2 };
     41        b = (Rational(int)){ -3, 2 };
    4342        sout | a | b;
    4443//      sout | a == 1; // FIX ME
     
    5958
    6059        sout | "conversion";
    61         a = (RatInt){ 3, 4 };
     60        a = (Rational(int)){ 3, 4 };
    6261        sout | widen( a );
    63         a = (RatInt){ 1, 7 };
     62        a = (Rational(int)){ 1, 7 };
    6463        sout | widen( a );
    65         a = (RatInt){ 355, 113 };
     64        a = (Rational(int)){ 355, 113 };
    6665        sout | widen( a );
    6766        sout | narrow( 0.75, 4 );
     
    7574
    7675        sout | "more tests";
    77         RatInt x = { 1, 2 }, y = { 2 };
     76        Rational(int) x = { 1, 2 }, y = { 2 };
    7877        sout | x - y;
    7978        sout | x > y;
     
    8180        sout | y | denominator( y, -2 ) | y;
    8281
    83         RatInt z = { 0, 5 };
     82        Rational(int) z = { 0, 5 };
    8483        sout | z;
    8584
    8685        sout | x | numerator( x, 0 ) | x;
    8786
    88         x = (RatInt){ 1, MAX } + (RatInt){ 1, MAX };
     87        x = (Rational(int)){ 1, MAX } + (Rational(int)){ 1, MAX };
    8988        sout | x;
    90         x = (RatInt){ 3, MAX } + (RatInt){ 2, MAX };
     89        x = (Rational(int)){ 3, MAX } + (Rational(int)){ 2, MAX };
    9190        sout | x;
    9291
  • tests/references.cfa

    reef8dfb rbdfc032  
    124124                int *p = &a;
    125125                asm (
    126                         #if defined( __i386 ) || defined( __x86_64 )
    127                                 "incl %[p]\n\t"
    128                                 : [p] "+m" (*p)
    129                         #elif defined( __aarch64__ )
    130                                 "ldr     w1, %[p]\n\t"
    131                                 "add     w1, w1, 1\n\t"
    132                                 "str     w1, %[p]\n\t"
    133                                 : [p] "+m" (*p) ::"w1"
    134                         #endif
     126                        "incl %[p]\n\t"
     127                        : [p] "+m" (*p)
    135128                );
    136129                printf("%d\n", a);
  • tests/result.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Thr May 25 16:50:00 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Sep 25 15:22:59 2020
    13 // Update Count     : 2
     12// Last Modified On : Thu Jul 20 15:24:12 2017
     13// Update Count     : 1
    1414//
    1515
     
    6666        checkGetters();
    6767        checkSetters();
    68         printf( "done\n" );                             // non-empty .expect file
    6968}
  • tests/searchsort.cfa

    reef8dfb rbdfc032  
    3838        } // for
    3939        sout | nl;
    40         for ( i; 0 ~ size ) {           // C version, returns void*
     40        for ( i; 0 ~ size ) {           // C version
    4141                int key = size - i;
    42                 int * v = ( int * ) bsearch( &key, iarr, size, sizeof( iarr[0] ), comp );
     42                int * v = bsearch( &key, iarr, size, sizeof( iarr[0] ), comp );
    4343                sout | key | ':' | *v | ", ";
    4444        } // for
  • tests/stdincludes.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Aug 29 08:26:14 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 08:51:38 2020
    13 // Update Count     : 8
     12// Last Modified On : Tue Nov  6 18:00:53 2018
     13// Update Count     : 6
    1414//
    1515
     
    4747#include <wctype.h>
    4848
    49 int main() {
    50         #pragma message( "Compiled" )                   // force non-empty .expect file
    51 }
     49int main() {}
    5250
    5351// Local Variables: //
  • tests/switch.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Jul 12 06:50:22 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 08:35:02 2020
    13 // Update Count     : 43
     12// Last Modified On : Tue Nov  6 18:01:34 2018
     13// Update Count     : 37
    1414//
    1515
     
    100100                j = 5;
    101101        } // choose
    102 
    103         #pragma message( "Compiled" )                                           // force non-empty .expect file
    104102} // main
    105103
  • tests/test.py

    reef8dfb rbdfc032  
    66
    77import argparse
    8 import itertools
    98import re
    109import sys
     
    2423
    2524        def match_test(path):
    26                 match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.nast|\.oast)?(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path)
     25                match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path)
    2726                if match :
    2827                        test = Test()
    2928                        test.name = match.group(2)
    3029                        test.path = match.group(1)
    31                         test.arch = match.group(4)[1:] if match.group(4) else None
    32 
    33                         astv = match.group(3)[1:] if match.group(3) else None
    34                         if astv == 'oast':
    35                                 test.astv = 'old'
    36                         elif astv == 'nast':
    37                                 test.astv = 'new'
    38                         elif astv:
    39                                 print('ERROR: "%s", expect file has astv but it is not "nast" or "oast"' % testname, file=sys.stderr)
    40                                 sys.exit(1)
    41 
    42                         expected.append(test)
     30                        test.arch = match.group(3)[1:] if match.group(3) else None
     31                        if settings.arch.match(test.arch):
     32                                expected.append(test)
    4333
    4434        path_walk( match_test )
     
    6353                ]
    6454
    65         # sort the test alphabetically for convenience
    66         test_list.sort(key=lambda t: ('~' if t.arch else '') + t.target() + (t.arch if t.arch else ''))
    67 
    6855        return test_list
    6956
     
    7663        if options.regenerate_expected :
    7764                for testname in options.tests :
    78                         testname = os.path.normpath( os.path.join(settings.SRCDIR, testname) )
    79 
    80                         # first check if this is a valid name to regenerate
     65                        testname = canonical_path( testname )
    8166                        if Test.valid_name(testname):
    82                                 # this is a valid name, let's check if it already exists
    8367                                found = [test for test in all_tests if canonical_path( test.target() ) == testname]
    84                                 setup = itertools.product(settings.all_arch if options.arch else [None], settings.all_ast if options.ast else [None])
    85                                 if not found:
    86                                         # it's a new name, create it according to the name and specified architecture/ast version
    87                                         tests.extend( [Test.new_target(testname, arch, ast) for arch, ast in setup] )
    88                                 elif len(found) == 1 and not found[0].arch:
    89                                         # we found a single test, the user better be wanting to create a cross platform test
    90                                         if options.arch:
    91                                                 print('ERROR: "%s", test has no specified architecture but --arch was specified, ignoring it' % testname, file=sys.stderr)
    92                                         elif options.ast:
    93                                                 print('ERROR: "%s", test has no specified ast version but --ast was specified, ignoring it' % testname, file=sys.stderr)
    94                                         else:
    95                                                 tests.append( found[0] )
    96                                 else:
    97                                         # this test is already cross platform, just add a test for each platform the user asked
    98                                         tests.extend( [Test.new_target(testname, arch, ast) for arch, ast in setup] )
    99 
    100                                         # print a warning if it users didn't ask for a specific architecture
    101                                         found_arch = [f.arch for f in found if f.arch]
    102                                         if found_arch and not options.arch:
    103                                                 print('WARNING: "%s", test has architecture specific expected files but --arch was not specified, regenerating only for current host' % testname, file=sys.stderr)
    104 
    105 
    106                                         # print a warning if it users didn't ask for a specific ast version
    107                                         found_astv = [f.astv for f in found if f.astv]
    108                                         if found_astv and not options.ast:
    109                                                 print('WARNING: "%s", test has ast version specific expected files but --ast was not specified, regenerating only for current ast' % testname, file=sys.stderr)
    110 
     68                                tests.append( found[0] if len(found) == 1 else Test.from_target(testname) )
    11169                        else :
    11270                                print('ERROR: "%s", tests are not allowed to end with a C/C++/CFA extension, ignoring it' % testname, file=sys.stderr)
     
    11876
    11977                        if test :
    120                                 tests.extend( test )
     78                                tests.append( test[0] )
    12179                        else :
    12280                                print('ERROR: No expected file for test %s, ignoring it' % testname, file=sys.stderr)
     
    12886        # create a parser with the arguments for the tests script
    12987        parser = argparse.ArgumentParser(description='Script which runs cforall tests')
    130         parser.add_argument('--ast', help='Test for specific ast', type=comma_separated(str), default=None)
    131         parser.add_argument('--arch', help='Test for specific architecture', type=comma_separated(str), default=None)
    132         parser.add_argument('--debug', help='Run all tests in debug or release', type=comma_separated(yes_no), default='yes')
    133         parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=comma_separated(yes_no), default='no')
    134         parser.add_argument('--continue', help='When multiple specifications are passed (debug/install/arch), sets whether or not to continue if the last specification failed', type=yes_no, default='yes', dest='continue_')
    135         parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=120)
     88        parser.add_argument('--debug', help='Run all tests in debug or release', type=yes_no, default='yes')
     89        parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=yes_no, default='no')
     90        parser.add_argument('--arch', help='Test for specific architecture', type=str, default='')
     91        parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=60)
    13692        parser.add_argument('--global-timeout', help='Maximum cumulative duration in seconds after the ALL tests are considered to have timed out', type=int, default=7200)
    137         parser.add_argument('--timeout-with-gdb', help='Instead of killing the command when it times out, orphan it and print process id to allow gdb to attach', type=yes_no, default="no")
    13893        parser.add_argument('--dry-run', help='Don\'t run the tests, only output the commands', action='store_true')
    13994        parser.add_argument('--list', help='List all test available', action='store_true')
     
    14398        parser.add_argument('-j', '--jobs', help='Number of tests to run simultaneously', type=int)
    14499        parser.add_argument('--list-comp', help='List all valide arguments', action='store_true')
    145         parser.add_argument('--list-dist', help='List all tests for distribution', action='store_true')
    146100        parser.add_argument('-I','--include', help='Directory of test to include, can be used multiple time, All  if omitted', action='append')
    147101        parser.add_argument('-E','--exclude', help='Directory of test to exclude, can be used multiple time, None if omitted', action='append')
     
    156110
    157111        # script must have at least some tests to run or be listing
    158         listing    = options.list or options.list_comp or options.list_dist
     112        listing    = options.list or options.list_comp
    159113        all_tests  = options.all
    160114        some_tests = len(options.tests) > 0
     
    191145        test.prepare()
    192146
    193         # ----------
    194         # MAKE
    195         # ----------
    196147        # build, skipping to next test on error
    197148        with Timed() as comp_dur:
    198149                make_ret, _ = make( test.target(), output_file=subprocess.DEVNULL, error=out_file, error_file = err_file )
    199150
    200         # ----------
    201         # RUN
    202         # ----------
     151        run_dur = None
    203152        # run everything in a temp directory to make sure core file are handled properly
    204         run_dur = None
    205153        with tempdir():
    206                 # if the make command succeeds continue otherwise skip to diff
     154                # if the make command succeds continue otherwise skip to diff
    207155                if success(make_ret):
    208156                        with Timed() as run_dur:
     
    218166                if success(retcode):
    219167                        if settings.generating :
    220                                 # if we are only generating the output we still need to check that the test actually exists
     168                                # if we are ounly generating the output we still need to check that the test actually exists
    221169                                if no_rule(out_file, test.target()) :
    222170                                        retcode = 1
     
    230178
    231179                else:
    232                         if os.stat(out_file).st_size < 1048576:
    233                                 with open (out_file, "r", encoding='latin-1') as myfile:  # use latin-1 so all chars mean something.
    234                                         error = myfile.read()
    235                         else:
    236                                 error = "Output log can't be read, file is bigger than 1MB, see {} for actual error\n".format(out_file)
     180                        with open (out_file, "r") as myfile:
     181                                error = myfile.read()
    237182
    238183                        ret, info = core_info(exe_file)
     
    269214        except KeyboardInterrupt:
    270215                return False, ""
    271         # except Exception as ex:
    272         #       print("Unexpected error in worker thread running {}: {}".format(t.target(), ex), file=sys.stderr)
    273         #       sys.stderr.flush()
    274         #       return False, ""
     216        except Exception as ex:
     217                print("Unexpected error in worker thread: %s" % ex, file=sys.stderr)
     218                sys.stderr.flush()
     219                return False, ""
    275220
    276221
     
    280225        make('clean', output_file=subprocess.DEVNULL, error=subprocess.DEVNULL)
    281226
    282         # create the executor for our jobs
    283         pool = multiprocessing.Pool(jobs)
     227        # since python prints stacks by default on a interrupt, redo the interrupt handling to be silent
     228        def worker_init():
     229                def sig_int(signal_num, frame):
     230                        pass
     231
     232                signal.signal(signal.SIGINT, sig_int)
     233
     234        # create the executor for our jobs and handle the signal properly
     235        pool = multiprocessing.Pool(jobs, worker_init)
    284236
    285237        failed = False
     238
     239        def stop(x, y):
     240                print("Tests interrupted by user", file=sys.stderr)
     241                sys.exit(1)
     242        signal.signal(signal.SIGINT, stop)
    286243
    287244        # for each test to run
     
    321278        make('clean', output_file=subprocess.DEVNULL, error=subprocess.DEVNULL)
    322279
    323         return failed
     280        return 1 if failed else 0
    324281
    325282
     
    335292        settings.init( options )
    336293
    337         # --------------------------------------------------
    338         # list all the test for auto completion programs
    339         # not pretty, single line, with the command line options
    340         if options.list_comp :
    341                 # fetch the liest of all valid tests
    342                 tests = list_tests( None, None )
    343 
    344                 # print the possible options
    345                 print("-h --help --debug --dry-run --list --ast=new --ast=old --arch --all --regenerate-expected --archive-errors --install --timeout --global-timeout --timeout-with-gdb -j --jobs -I --include -E --exclude --continue ", end='')
    346                 print(" ".join(map(lambda t: "%s" % (t.target()), tests)))
    347 
    348                 # done
    349                 sys.exit(0)
    350 
    351         # --------------------------------------------------
    352         # list all the test for auto completion programs
    353         if options.list_dist :
    354                 # fetch the liest of all valid tests
    355                 tests = list_tests( None, None )
    356 
    357                 for t in tests:
    358                         print(os.path.relpath(t.expect(), settings.SRCDIR), end=' ')
    359                         print(os.path.relpath(t.input() , settings.SRCDIR), end=' ')
    360                         code, out = make_recon(t.target())
    361 
    362                         if code != 0:
    363                                 print('ERROR: recond failed for test {}'.format(t.target()), file=sys.stderr)
    364                                 sys.exit(1)
    365 
    366                         print(' '.join(re.findall('([^\s]+\.cfa)', out)), end=' ')
    367 
    368                 print('')
    369 
    370                 # done
    371                 sys.exit(0)
    372 
    373 
    374         # --------------------------------------------------
    375         # list all the tests for users, in a pretty format
    376         if options.list :
    377                 # fetch the liest of all valid tests
    378                 tests = list_tests( options.include, options.exclude )
    379 
    380                 # print the available tests
    381                 fancy_print("\n".join(map(lambda t: t.toString(), tests)))
    382 
    383                 # done
    384                 sys.exit(0)
    385 
    386294        # fetch the liest of all valid tests
    387295        all_tests = list_tests( options.include, options.exclude )
    388296
     297
    389298        # if user wants all tests than no other treatement of the test list is required
    390         if options.all or options.include :
     299        if options.all or options.list or options.list_comp or options.include :
    391300                tests = all_tests
    392301
     
    400309                sys.exit(1)
    401310
    402         # prep invariants
    403         settings.prep_output(tests)
    404         failed = 0
    405 
    406         # check if the expected files aren't empty
    407         if not options.regenerate_expected:
    408                 for t in tests:
    409                         if is_empty(t.expect()):
    410                                 print('WARNING: test "{}" has empty .expect file'.format(t.target()), file=sys.stderr)
    411 
    412         # for each build configurations, run the test
    413         with Timed() as total_dur:
    414                 for ast, arch, debug, install in itertools.product(settings.all_ast, settings.all_arch, settings.all_debug, settings.all_install):
    415                         settings.ast     = ast
    416                         settings.arch    = arch
    417                         settings.debug   = debug
    418                         settings.install = install
    419 
    420                         # filter out the tests for a different architecture
    421                         # tests are the same across debug/install
    422                         local_tests = settings.ast.filter( tests )
    423                         local_tests = settings.arch.filter( local_tests )
    424                         options.jobs, forceJobs = job_count( options, local_tests )
    425                         settings.update_make_cmd(forceJobs, options.jobs)
    426 
    427                         # check the build configuration works
    428                         settings.validate()
    429 
    430                         # print configuration
    431                         print('%s %i tests on %i cores (%s:%s - %s)' % (
    432                                 'Regenerating' if settings.generating else 'Running',
    433                                 len(local_tests),
    434                                 options.jobs,
    435                                 settings.ast.string,
    436                                 settings.arch.string,
    437                                 settings.debug.string
    438                         ))
    439                         if not local_tests :
    440                                 print('WARNING: No tests for this configuration')
    441                                 continue
    442 
    443                         # otherwise run all tests and make sure to return the correct error code
    444                         failed = run_tests(local_tests, options.jobs)
    445                         if failed:
    446                                 result = 1
    447                                 if not settings.continue_:
    448                                         break
    449 
    450         print('Tests took %s' % fmtDur( total_dur.duration ))
    451         sys.exit( failed )
     311
     312        # sort the test alphabetically for convenience
     313        tests.sort(key=lambda t: (t.arch if t.arch else '') + t.target())
     314
     315        # users may want to simply list the tests
     316        if options.list_comp :
     317                print("-h --help --debug --dry-run --list --arch --all --regenerate-expected --archive-errors --install --timeout --global-timeout -j --jobs ", end='')
     318                print(" ".join(map(lambda t: "%s" % (t.target()), tests)))
     319
     320        elif options.list :
     321                print("Listing for %s:%s"% (settings.arch.string, settings.debug.string))
     322                fancy_print("\n".join(map(lambda t: t.toString(), tests)))
     323
     324        else :
     325                # check the build configuration works
     326                settings.prep_output(tests)
     327                settings.validate()
     328
     329                options.jobs, forceJobs = job_count( options, tests )
     330                settings.update_make_cmd(forceJobs, options.jobs)
     331
     332                print('%s %i tests on %i cores (%s:%s)' % (
     333                        'Regenerating' if settings.generating else 'Running',
     334                        len(tests),
     335                        options.jobs,
     336                        settings.arch.string,
     337                        settings.debug.string
     338                ))
     339
     340                # otherwise run all tests and make sure to return the correct error code
     341                sys.exit( run_tests(tests, options.jobs) )
  • tests/time.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Tue Mar 27 17:24:56 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jun 18 18:14:49 2020
    13 // Update Count     : 37
     12// Last Modified On : Sun Jan  5 18:27:37 2020
     13// Update Count     : 34
    1414//
    1515
     
    2020        Duration d1 = 3`h, d2 = 2`s, d3 = 3.375`s, d4 = 12`s, d5 = 1`s + 10_000`ns;
    2121        sout | d1 | d2 | d3 | d4 | d5;
    22         sout | d1`dd | d2`dm | d3`ds | d4`dms | d5`dus;
    2322        d1 = 0;
    2423        sout | d1 | d2 | d3;
  • tests/tuple/tupleAssign.cfa

    reef8dfb rbdfc032  
    4444                double d = 0.0;
    4545                int i = 0;
    46                 signed char c = '\0';
     46                char c = '\0';
    4747                struct X {
    4848                        int z;
     
    5555                [t, x, d, i, c, x] = (double)94.12;
    5656                printf( "d=%lg i=%d c=%c t=[%d, %lg, %d]\n", d, i, (int)c, t );
    57                 sout | "d=" | d | "i=" | i | "c=" | (char)c | ' ' | "t=[" | t | "]";
     57                sout | "d=" | d | "i=" | i | "c=" | c | ' ' | "t=[" | t | "]";
    5858                [x, c, i, d, x, t] = (double)-94.12;
    5959                printf( "d=%lg i=%d c=%c t=[%d, %lg, %d]\n", d, i, c, t );
    60                 sout | "d=" | d | "i=" | i | "c=" | (char)c | ' ' | "t=[" | t | "]";
     60                sout | "d=" | d | "i=" | i | "c=" | c | ' ' | "t=[" | t | "]";
    6161        }
    6262}
  • tests/typedefRedef.cfa

    reef8dfb rbdfc032  
    2727typedef int ARR[];
    2828typedef int ARR[];
    29 #ifdef ERR1
    30 // if a typedef has an array dimension, it can only be redefined to the same dimension
     29// #ifdef ERR1
     30// if a typedef has an array dimension,
     31// it can only be redefined to the same dimension
    3132typedef int ARR[2];
    32 #endif
     33// #endif
    3334
    3435typedef int X;
     
    5354
    5455int main() {
    55         typedef int ARR[sz];
     56  typedef int ARR[sz];
    5657
    57         // can't redefine typedef which is VLA
     58  // can't redefine typedef which is VLA
    5859#if ERR1
    59         typedef int ARR[sz];
     60  typedef int ARR[sz];
    6061#endif
    6162
    62         Foo * x;
     63  Foo *x;
    6364
    64         typedef struct Bar Foo;
    65         Foo * y;
     65  typedef struct Bar Foo;
     66  Foo *y;
    6667
    67         typedef int *** pt;
    68 
    69         #pragma message( "Compiled" )                   // force non-empty .expect file
     68  typedef int *** pt;
    7069}
  • tests/typeof.cfa

    reef8dfb rbdfc032  
    11int main() {
    2         int *v1;
    3         typeof(v1) v2;
    4         typeof(*v1) v3[4];
    5         char *v4[4];
    6         typeof(typeof(char *)[4]) v5;
    7         typeof (int *) v6;
    8         typeof( int ( int, int p ) ) *v7;
    9         typeof( [int] ( int, int p ) ) *v8;
    10         (typeof(v1)) v2; // cast with typeof
    11         printf( "done\n" );                             // non-empty .expect file
     2    int *v1;
     3    typeof(v1) v2;
     4    typeof(*v1) v3[4];
     5    char *v4[4];
     6    typeof(typeof(char *)[4]) v5;
     7    typeof (int *) v6;
     8    typeof( int ( int, int p ) ) *v7;
     9    typeof( [int] ( int, int p ) ) *v8;
     10    (typeof(v1)) v2; // cast with typeof
    1211}
  • tests/userLiterals.cfa

    reef8dfb rbdfc032  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // userLiterals.cfa --
     7// user_literals.cfa --
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Wed Sep  6 21:40:50 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 19 07:48:45 2020
    13 // Update Count     : 74
     12// Last Modified On : Tue Dec  4 22:03:10 2018
     13// Update Count     : 56
    1414//
    1515
     
    2424int ?`__thingy_( int x ) { sout | "_thingy_" | x; return x; }
    2525
    26 int ?`s( const char * s ) { sout | "s" | s; return 0; }
    27 int ?`m( const char16_t * m ) { sout | "m" | m; return 0;}
    28 int ?`h( const char32_t * h ) { sout | "h" | h; return 0; }
     26int ?`s( const char * s ) { sout | "secs" | s; return 0; }
     27int ?`m( const char16_t * m ) { sout | "mins" | m; return 0;}
     28int ?`h( const char32_t * h ) { sout | "hours" | h; return 0; }
    2929int ?`_A_( const wchar_t * str ) { sout | "_A_" | str; return 0; }
    3030int ?`__thingy_( const char * str ) { sout | "_thingy_" | str; return 0; }
     
    3737        return (Weight){ l.stones + r.stones };
    3838}
    39 ofstream & ?|?( ofstream & os, Weight w ) { return os | wd(1,1, w.stones); }
    40 void ?|?( ofstream & os, Weight w ) { (ofstream)(os | w); ends( os ); }
     39ofstream & ?|?( ofstream & os, Weight w ) { return os | w.stones; }
    4140
    4241Weight ?`st( double w ) { return (Weight){ w }; }               // backquote for user literals
     
    6160        sout | w;
    6261
    63         0`s;
     62//      0`secs;
    6463        1`s;
    6564        23`s;
     
    8382
    8483        "abc"`s;
    85         // FIX ME: requires char16_t, char32_t, and wchar_t be unique types
    86         // u"abc"`m;
    87         // U_"abc"`h;
    88         // L"abc"`_A_;
     84//      u"abc"`m;
     85//      U_"abc"`h;
     86//      L"abc"`_A_;
    8987        u8_"abc"`__thingy_;
    9088} // main
     
    9290// Local Variables: //
    9391// tab-width: 4 //
    94 // compile-command: "cfa userLiterals.cfa" //
     92// compile-command: "cfa user_literals.cfa" //
    9593// End: //
  • tests/variableDeclarator.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Wed Aug 17 08:41:42 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 07:46:17 2020
    13 // Update Count     : 13
     12// Last Modified On : Tue Nov  6 18:02:16 2018
     13// Update Count     : 2
    1414//
    1515
     
    1818int (f2);
    1919
    20 int * f3;
    21 int ** f4;
    22 int * const * f5;
     20int *f3;
     21int **f4;
     22int * const *f5;
    2323int * const * const f6;
    2424
    25 int * (f7);
    26 int ** (f8);
    27 int * const * (f9);
     25int *(f7);
     26int **(f8);
     27int * const *(f9);
    2828int * const * const (f10);
    2929
    30 int (* f11);
    31 int (** f12);
    32 int (* const * f13);
     30int (*f11);
     31int (**f12);
     32int (* const *f13);
    3333int (* const * const f14);
    3434
    35 int f15[0];
     35int f15[];
    3636int f16[10];
    37 int (f17[0]);
     37int (f17[]);
    3838int (f18[10]);
    3939
    40 int * f19[0];
    41 int * f20[10];
    42 int ** f21[0];
    43 int ** f22[10];
    44 int * const * f23[0];
    45 int * const * f24[10];
    46 int * const * const f25[0];
     40int *f19[];
     41int *f20[10];
     42int **f21[];
     43int **f22[10];
     44int * const *f23[];
     45int * const *f24[10];
     46int * const * const f25[];
    4747int * const * const f26[10];
    4848
    49 int *(f27[0]);
     49int *(f27[]);
    5050int *(f28[10]);
    51 int **(f29[0]);
     51int **(f29[]);
    5252int **(f30[10]);
    53 int * const *(f31[0]);
     53int * const *(f31[]);
    5454int * const *(f32[10]);
    55 int * const * const (f33[0]);
     55int * const * const (f33[]);
    5656int * const * const (f34[10]);
    5757
    58 int (* f35)[];
    59 int (* f36)[10];
    60 int (** f37)[];
    61 int (** f38)[10];
    62 int (* const * f39)[];
    63 int (* const * f40)[10];
     58int (*f35)[];
     59int (*f36)[10];
     60int (**f37)[];
     61int (**f38)[10];
     62int (* const *f39)[];
     63int (* const *f40)[10];
    6464int (* const * const f41)[];
    6565int (* const * const f42)[10];
    6666
    67 int f43[0][3];
     67int f43[][3];
    6868int f44[3][3];
    69 int (f45[0])[3];
     69int (f45[])[3];
    7070int (f46[3])[3];
    71 int ((f47[0]))[3];
     71int ((f47[]))[3];
    7272int ((f48[3]))[3];
    7373
    74 int * f49[0][3];
    75 int * f50[3][3];
    76 int ** f51[0][3];
    77 int ** f52[3][3];
    78 int * const * f53[0][3];
    79 int * const * f54[3][3];
    80 int * const * const f55[0][3];
     74int *f49[][3];
     75int *f50[3][3];
     76int **f51[][3];
     77int **f52[3][3];
     78int * const *f53[][3];
     79int * const *f54[3][3];
     80int * const * const f55[][3];
    8181int * const * const f56[3][3];
    8282
    83 int (* f57[0][3]);
    84 int (* f58[3][3]);
    85 int (** f59[0][3]);
    86 int (** f60[3][3]);
    87 int (* const * f61[0][3]);
    88 int (* const * f62[3][3]);
    89 int (* const * const f63[0][3]);
     83int (*f57[][3]);
     84int (*f58[3][3]);
     85int (**f59[][3]);
     86int (**f60[3][3]);
     87int (* const *f61[][3]);
     88int (* const *f62[3][3]);
     89int (* const * const f63[][3]);
    9090int (* const * const f64[3][3]);
    9191
     
    9393int (f66)(int);
    9494
    95 int * f67(int);
    96 int ** f68(int);
    97 int * const * f69(int);
     95int *f67(int);
     96int **f68(int);
     97int * const *f69(int);
    9898int * const * const f70(int);
    9999
     
    104104int * const * const (f74)(int);
    105105
    106 int (* f75)(int);
    107 int (** f76)(int);
    108 int (* const * f77)(int);
     106int (*f75)(int);
     107int (**f76)(int);
     108int (* const *f77)(int);
    109109int (* const * const f78)(int);
    110110
    111 int (*(* f79)(int))();
     111int (*(*f79)(int))();
    112112int (*(* const f80)(int))();
    113113int (* const(* const f81)(int))();
     
    119119//int fe2()[];                          // returning an array
    120120//int fe3()();                          // returning a function
    121 //int (* fe4)()();                              // returning a function
    122 //int ((* fe5())())[];                  // returning an array
     121//int (*fe4)()();                               // returning a function
     122//int ((*fe5())())[];                   // returning an array
    123123
    124 #ifdef __CFA__
    125124// Cforall extensions
    126125
     
    130129const * const * int cf6;
    131130
    132 [0] int cf15;
     131[] int cf15;
    133132[10] int cf16;
    134133
    135 [0] * int cf19;
     134[] * int cf19;
    136135[10] * int cf20;
    137 int ** cf21[0];
     136int **cf21[];
    138137[10] * * int cf22;
    139 [0] * const * int cf23;
     138[] * const * int cf23;
    140139[10] * const * int cf24;
    141 [0] const * const * int cf25;
     140[] const * const * int cf25;
    142141[10] const * const * int cf26;
    143142
     
    151150const * const * [10] int cf42;
    152151
    153 [0][3] int cf43;
     152[][3] int cf43;
    154153[3][3] int cf44;
    155154
    156 [0][3] * int cf49;
     155[][3] * int cf49;
    157156[3][3] * int cf50;
    158 [0][3] * * int cf51;
     157[][3] * * int cf51;
    159158[3][3] * * int cf52;
    160 [0][3] const * int cf53;
     159[][3] const * int cf53;
    161160[3][3] * const * int cf54;
    162 [0][3] const * const * int cf55;
     161[][3] const * const * int cf55;
    163162[3][3] const * const * int cf56;
    164163
     
    174173
    175174*[]*[]* [ *[]*[] int ]( *[]*[] int, *[]*[] int ) v3;
    176 #endif // __CFA__
    177175
    178176//Dummy main
    179 int main( int argc, char const * argv[] ) {
    180         #pragma message( "Compiled" )                                           // force non-empty .expect file
     177int main(int argc, char const *argv[])
     178{
     179        return 0;
    181180}
    182181
  • tests/vector.cfa

    reef8dfb rbdfc032  
    1414//
    1515
     16#include <fstream.hfa>
    1617#include <vector.hfa>
    17 #include <fstream.hfa>
    1818
    1919#undef assert
     
    2828int main() {
    2929        vector( int ) iv;
    30 
    31         assert( ((uintptr_t)&iv.storage.storage ) == (((uintptr_t)&iv)) );
    32         assert( ((uintptr_t)&iv.storage.capacity) == (((uintptr_t)&iv) + sizeof(void *)) );
    33         assert( ((uintptr_t)&iv.size            ) == (((uintptr_t)&iv) + sizeof(void *) + sizeof(size_t)) );
    3430
    3531        assert( empty( &iv ) );
  • tests/voidPtr.cfa

    reef8dfb rbdfc032  
    1313        if ( ! a ) {
    1414                abort();
    15         }
    16         printf( "done\n" );                             // non-empty .expect file
     15        }       
    1716}
    1817
  • tests/warnings/self-assignment.cfa

    reef8dfb rbdfc032  
    1010// Created On       : Thu Mar 1 13:53:57 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 09:24:34 2020
    13 // Update Count     : 6
     12// Last Modified On : Wed Feb 20 07:56:17 2019
     13// Update Count     : 3
    1414//
    1515
     
    3131        s.i = s.i;
    3232        t.s.i = t.s.i;
    33 
    34         #pragma message( "Compiled" )                   // force non-empty .expect file
    3533}
    3634
    3735// Local Variables: //
    3836// tab-width: 4 //
    39 // compile-command: "cfa self-assignment.cfa" //
     37// compile-command: "cfa dtor-early-exit" //
    4038// End: //
  • tools/Makefile.am

    reef8dfb rbdfc032  
    1818ACLOCAL_AMFLAGS  = -I automake
    1919
     20AM_CFLAGS = -Wall -Wextra -O2 -g
     21
    2022noinst_PROGRAMS = busy catchsig repeat watchdog
    21 AM_CFLAGS = -Wall -Wextra -O2 -g
     23
     24busy_SOURCES     = busy.c
    2225busy_LDFLAGS     = -pthread
    23 
    24 nodist_busy_SOURCES     = busy.c
    25 nodist_catchsig_SOURCES = catchsig.c
    26 nodist_repeat_SOURCES   = repeat.c
    27 nodist_watchdog_SOURCES = watchdog.c
     26catchsig_SOURCES = catchsig.c
     27repeat_SOURCES   = repeat.c
     28watchdog_SOURCES = watchdog.c
  • tools/build/push2dist.sh

    reef8dfb rbdfc032  
    22
    33hash="$1"
    4 bwlim="$2"
    54valid=$(distcc -j 2> /dev/null)
    65# if test "${valid}" != 0
     
    2019# echo "Copying to machines : ${hosts} (hash=${hash})"
    2120
    22 files="../../../driver/cfa ../../../driver/cfa-cpp ../../../driver/cc1 ../../../driver/as defines.hfa $(find . -name '*.c*' | tr '\n' ' ')"
     21files="../../../driver/cfa ../../../driver/cfa-cpp ../../../driver/cc1 ../../../driver/as $(find . -name '*.c*' | tr '\n' ' ')"
    2322# echo "Files ${files}"
    2423
    2524function push() {
    2625        ssh ${host} "mkdir -p ~/.cfadistcc/${hash}/"
    27         rsync --bwlimit=${bwlim} -a ${dV} ${files} ${host}:~/.cfadistcc/${hash}/.
     26        rsync -a ${dV} ${files} ${host}:~/.cfadistcc/${hash}/.
    2827}
    2928
  • tools/cfa.nanorc

    reef8dfb rbdfc032  
    1414
    1515# Declarations
    16 color brightgreen "\<(struct|union|typedef|trait|coroutine|generator)\>"
    17 color brightgreen "\<(monitor|thread|with)\>"
     16color brightgreen "\<(struct|union|typedef|trait|coroutine|monitor|thread)\>"
     17color brightgreen "\<(with)\>"
    1818
    1919# Control Flow Structures
    2020color brightyellow "\<(if|else|while|do|for|switch|choose|case|default)\>"
    21 color brightyellow "\<(disable|enable|waitfor|when|timeout|suspend)\>"
     21color brightyellow "\<(disable|enable|waitfor|when|timeout)\>"
    2222color brightyellow "\<(try|catch(Resume)?|finally)\>"
    2323
     
    2626
    2727# Escaped Keywords, now Identifiers.
    28 color white "``\w+"
     28color white "`\w+`"
    2929
    3030# Operator Names
     
    3737## Update/Redistribute
    3838# GCC builtins
    39 color cyan "__attribute__[[:space:]]*\(\(([^)]|[^)]\))*\)\)"
     39color cyan "__attribute__[[:space:]]*\(\([^()]*(\([^()]*\)[^()]*)*\)\)"
    4040##color cyan "__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__"
    4141
  • tools/prettyprinter/Makefile.am

    reef8dfb rbdfc032  
    3030tools_prettyprinter_PROGRAMS = pretty
    3131tools_prettyprinterdir = ../
    32 nodist_pretty_SOURCES = ${SRC}
     32pretty_SOURCES = ${SRC}
    3333pretty_LDADD = ${LEXLIB} -ldl                   # yywrap
    3434pretty_CXXFLAGS = -Wno-deprecated -Wall -DYY_NO_INPUT -O2 -g -std=c++14
  • tools/stat.py

    reef8dfb rbdfc032  
    1 #!/usr/bin/python3
     1#!/usr/bin/python
    22
    33import sys
     
    1717                avg = numpy.mean  (content)
    1818                std = numpy.std   (content)
    19                 print("median {0:.1f} avg {1:.1f} stddev {2:.1f}".format( med, avg, std ))
     19                print "median {0:.1f} avg {1:.1f} stddev {2:.1f}".format( med, avg, std )
    2020
    2121
  • tools/vscode/uwaterloo.cforall-0.1.0/package.json

    reef8dfb rbdfc032  
    22        "name": "cforall",
    33        "version": "0.1.0",
    4         "displayName": "Cāˆ€ (C-for-all) Language Support",
     4        "displayName": "Cforall Language Support",
    55        "description": "Cforall - colorizer, grammar and snippets.",
    66        "publisher": "uwaterloo",
     
    99                "vscode": "^1.5.0"
    1010        },
    11         "icon": "images/icon.png",
     11        "icon": "images/icon.svg",
    1212        "categories": [
    13                 "Programming Languages",
     13                "Languages",
    1414                "Linters",
    1515                "Other"
    1616        ],
    17         "activationEvents": [
    18                 "onLanguage:cforall"
    19         ],
    20         "main": "./client/main.js",
    2117        "contributes": {
    2218                "languages": [
     
    2521                                "aliases": [
    2622                                        "Cāˆ€",
     23                                        "Cforall",
    2724                                        "CForAll",
    28                                         "Cforall",
    2925                                        "cforall"
    3026                                ],
    3127                                "extensions": [
    32                                         ".cfa",
    33                                         ".hfa",
    34                                         ".ifa"
     28                                        ".cf"
    3529                                ],
    3630                                "configuration": "./cforall.configuration.json"
     
    4034                        {
    4135                                "language": "cforall",
    42                                 "scopeName": "source.cfa",
    43                                 "path": "./syntaxes/cfa.tmLanguage.json"
     36                                "scopeName": "source.cf",
     37                                "path": "./syntaxes/cfa.tmLanguage"
    4438                        }
    45                 ],
    46                 "configuration": {
    47                         "type": "object",
    48                         "title": "Example configuration",
    49                         "properties": {
    50                                 "cforall.maxNumberOfProblems": {
    51                                         "scope": "resource",
    52                                         "type": "number",
    53                                         "default": 100,
    54                                         "description": "Controls the maximum number of problems produced by the server."
    55                                 },
    56                                 "cforall.trace.server": {
    57                                         "scope": "window",
    58                                         "type": "string",
    59                                         "enum": [
    60                                                 "off",
    61                                                 "messages",
    62                                                 "verbose"
    63                                         ],
    64                                         "default": "off",
    65                                         "description": "Traces the communication between VS Code and the language server."
    66                                 }
    67                         }
    68                 }
    69         },
    70         "dependencies": {
    71                 "vscode-languageclient": "^4.1.4"
    72         },
    73         "devDependencies": {
    74                 "vscode-languageclient": "^4.1.4"
     39                ]
    7540        }
    7641}
Note: See TracChangeset for help on using the changeset viewer.