Changeset c28ea4e


Ignore:
Timestamp:
Nov 4, 2020, 2:56:30 PM (12 months ago)
Author:
Colby Alexander Parsons <caparsons@…>
Branches:
arm-eh, jacob/cs343-translation, master, new-ast-unique-expr
Children:
eeb5023
Parents:
4b30e8c (diff), a3f5208a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

Files:
21 added
101 edited
4 moved

Legend:

Unmodified
Added
Removed
  • Jenkins/FullBuild

    r4b30e8c rc28ea4e  
    1717
    1818                                parallel (
    19                                         clang_x86: { trigger_build( 'gcc-8',   'x86' ) },
    20                                         gcc_5_x86: { trigger_build( 'gcc-7',   'x86' ) },
     19                                        gcc_8_x86: { trigger_build( 'gcc-8',   'x86' ) },
     20                                        gcc_7_x86: { trigger_build( 'gcc-7',   'x86' ) },
    2121                                        gcc_6_x86: { trigger_build( 'gcc-6',   'x86' ) },
    2222                                        gcc_9_x64: { trigger_build( 'gcc-9',   'x64' ) },
  • Jenkinsfile

    r4b30e8c rc28ea4e  
    127127                        }
    128128
    129                         sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} AR=gcc-ar RANLIB=gcc-ranlib ${targets} --quiet --prefix=${BuildDir}"
     129                        ast = Settings.NewAST ? "--enable-new-ast" : "--disable-new-ast"
     130
     131                        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}"
    130132
    131133                        // Configure libcfa
     
    359361        public final CC_Desc Compiler
    360362        public final Arch_Desc Architecture
     363        public final Boolean NewAST
    361364        public final Boolean RunAllTests
    362365        public final Boolean RunBenchmark
     
    410413
    411414                this.IsSandbox          = (branch == "jenkins-sandbox")
     415                this.NewAST             = param.NewAST
    412416                this.RunAllTests        = param.RunAllTests
    413417                this.RunBenchmark       = param.RunBenchmark
     
    470474                                ],                                                                                              \
    471475                                [$class: 'BooleanParameterDefinition',                                                  \
     476                                        description: 'If true, build compiler using new AST',           \
     477                                        name: 'NewAST',                                                                         \
     478                                        defaultValue: false,                                                            \
     479                                ],                                                                                              \
     480                                [$class: 'BooleanParameterDefinition',                                                  \
    472481                                        description: 'If false, only the quick test suite is ran',              \
    473482                                        name: 'RunAllTests',                                                            \
    474483                                        defaultValue: false,                                                            \
    475                                 ],                                                                                              \
     484                                ],
    476485                                [$class: 'BooleanParameterDefinition',                                                  \
    477486                                        description: 'If true, jenkins also runs benchmarks',           \
  • configure.ac

    r4b30e8c rc28ea4e  
    2828# New AST toggling support
    2929AH_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])
     30DEFAULT_NEW_AST="False"
    3031AC_ARG_ENABLE(new-ast,
    3132        [  --enable-new-ast     whether or not to use new ast as the default AST algorithm],
    3233        [case "${enableval}" in
    33                 yes) newast=true ;;
    34                 no)  newast=false ;;
     34                yes) newast=true ; DEFAULT_NEW_AST="True"  ;;
     35                no)  newast=false; DEFAULT_NEW_AST="False" ;;
    3536                *) AC_MSG_ERROR([bad value ${enableval} for --enable-new-ast]) ;;
    3637        esac],[newast=false])
    3738AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast)
     39AC_SUBST(DEFAULT_NEW_AST)
    3840
    3941#==============================================================================
  • doc/papers/concurrency/mail2

    r4b30e8c rc28ea4e  
     1
    12Date: Wed, 26 Jun 2019 20:12:38 +0000
    23From: Aaron Thomas <onbehalfof@manuscriptcentral.com>
     
    10741075Software: Practice and Experience Editorial Office
    10751076
     1077
     1078
     1079Date: Thu, 15 Oct 2020 13:48:52 +0000
     1080From: Richard Jones <onbehalfof@manuscriptcentral.com>
     1081Reply-To: R.E.Jones@kent.ac.uk
     1082To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
     1083Subject: Software: Practice and Experience - Decision on Manuscript ID
     1084 SPE-19-0219.R3
     1085
     108615-Oct-2020
     1087
     1088Dear Dr Buhr,
     1089
     1090It 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. 
     1091
     1092Please 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.
     1093
     1094Your 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.
     1095
     1096Thank you for your fine contribution.
     1097
     1098Sincerely,
     1099Richard
     1100
     1101Prof. Richard Jones
     1102Editor, Software: Practice and Experience
     1103R.E.Jones@kent.ac.uk
     1104
     1105P.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.
     1106
     1107This 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.
     1108
     1109
     1110
     1111Date: Fri, 16 Oct 2020 12:44:42 +0000
     1112From: Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com>
     1113Reply-To: speoffice@wiley.com
     1114To: pabuhr@uwaterloo.ca
     1115Subject: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c]
     1116
     111716-Oct-2020
     1118
     1119Dear Dr. Buhr,
     1120
     1121Manuscript id: SPE-19-0219.R3
     1122Manuscript title: Advanced Control-flow and Concurrency in Cforall
     1123
     1124Although 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.
     1125
     1126Any special instructions will be listed below:
     11271) Funding Information added in ScholorOne but missing in main document, Kindly add the Funding information in main document.
     11282) Please provide the clean version of the manuscript without any highlights or tracked changes.
     11293) Kindly check and make sure citations for all figures and Tables are present in the main document
     1130
     1131Please 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.
     1132
     1133On 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.
     1134
     1135Instructions for uploading replacement files:
     11361. On the "File Upload" step, click on the "edit" button for the file you wish to replace.
     11372. In the "Upload a later version" section, browse to locate the replacement final version.
     11383. Add any comments concerning the replacement (e.g. "high res image").
     11394. Select whether the new file is a minor or major version (we suggest you select minor version)
     11405. Click upload.
     11416. Click 'Submit' when all the files have been uploaded and you will receive an automated email to say that submission is successful.
     1142
     1143Please submit your updates within the next 7 days to ensure there are no unnecessary delays in production.
     1144
     1145Sincerely,
     1146Software: Practice and Experience Editorial Office
     1147
     1148
     1149
     1150From: SPE Office <speoffice@wiley.com>
     1151To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
     1152Subject: Re: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c]
     1153Date: Mon, 19 Oct 2020 17:04:24 +0000
     1154
     1155Dear Dr. Buhr,
     1156
     1157Thank you very much for contacting the Editorial Office.
     1158
     1159I would like to let you know that the files has been found in order and moved to production.
     1160
     1161Plesae let me know for further assistance in this regard.
     1162
     1163Best Regards
     1164
     1165Mayank Roy Chowdhury
     1166Editorial Assistant
     1167Software practice and Experience
     1168________________________________
     1169From: Peter A. Buhr <pabuhr@uwaterloo.ca>
     1170Sent: Sunday, October 18, 2020 2:00 PM
     1171To: SPE Office <speoffice@wiley.com>
     1172Cc: Thierry Delisle <tdelisle@uwaterloo.ca>
     1173Subject: Re: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c]
     1174
     1175       This is an external email.
     1176
     1177    Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com> writes:
     1178
     1179    Instructions for uploading replacement files:
     1180    1. On the "File Upload" step, click on the "edit" button for the file you wish to replace.
     1181    2. In the "Upload a later version" section, browse to locate the replacement final version.
     1182    3. Add any comments concerning the replacement (e.g. "high res image").
     1183    4. Select whether the new file is a minor or major version (we suggest you select minor version)
     1184    5. Click upload.
     1185    6. Click 'Submit' when all the files have been uploaded and you will receive an automated email to say that submission is successful.
     1186
     1187There was no "edit" button on the "File Upload" page, so I just upload the
     1188final version of the PDF and source files using the mechanism on the "File
     1189Upload" page and submitted that.
     1190
     1191
     1192
     1193Date: Tue, 20 Oct 2020 13:28:37 +0530
     1194To: "Dr. Peter Buhr" <pabuhr@uwaterloo.ca>
     1195From: jpcms@spi-global.com
     1196Subject: Information: Production Editor Contact Software:Practice and Experience  | Advanced Control-flow and Concurrency in C A
     1197
     1198Dear Dr. Peter Buhr,
     1199
     1200We 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.
     1201
     1202Please get in touch with your Production Editor at SPEproofs@wiley.com;EllaMae.Navor@spi-global.com if you have any questions.
     1203               
     1204Sincerely,
     1205Booking-in Team,
     1206On behalf of Wiley
     1207
     1208Article ID: SPE_2925
     1209Article DOI: 10.1002/SPE.2925
     1210
     1211
     1212
     1213Date: Tue, 20 Oct 2020 10:33:04 +0000
     1214From: <cs-author@wiley.com>
     1215To: <pabuhr@uwaterloo.ca>
     1216Subject: In Production: Your article accepted in Software: Practice and Experience
     1217
     1218Dear Peter Buhr,
     1219
     1220Article ID: SPE2925
     1221Article DOI: 10.1002/spe.2925
     1222Internal Article ID: 16922213
     1223Article: Advanced Control-flow and Concurrency in C A
     1224Journal: Software: Practice and Experience
     1225
     1226Congratulations on the acceptance of your article for publication in Software: Practice and Experience.
     1227
     1228Your 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.
     1229
     1230Please 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?):
     1231
     1232https://authorservices.wiley.com/index.html#login?campaign=email_invitation-new
     1233
     1234If applicable, a list of available actions will appear below - check out your Author Services Dashboard for all actions related to your articles.
     1235
     1236Sign 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
     1237If 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.
     1238
     1239Sincerely,
     1240Wiley Author Services
     1241
     1242P.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.
     1243
     1244
     1245
     1246Date: Thu, 22 Oct 2020 20:21:49 +0000
     1247From: <cs-author@wiley.com>
     1248To: <pabuhr@uwaterloo.ca>
     1249Subject: You have actions to complete in Author Services
     1250
     1251Dear Peter Buhr,
     1252
     1253Article ID: SPE2925
     1254Article DOI: 10.1002/spe.2925
     1255Internal Article ID: 16922213
     1256Article: Advanced Control-flow and Concurrency in C A
     1257Journal: Software: Practice and Experience
     1258
     1259For the above article, you have the following open tasks:
     1260
     1261Sign 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.
     1262
     1263Need any help? Please visit our https://authorsupport.wiley.com/s/">Author Support Center.
     1264
     1265Sincerely,
     1266Wiley Author Services
     1267
     1268
     1269
     1270Date: Thu, 22 Oct 2020 23:13:07 +0000
     1271From: <cs-author@wiley.com>
     1272To: <pabuhr@uwaterloo.ca>
     1273Subject: License was successfully submitted! Thank you!
     1274
     1275Dear Peter Buhr,                                                                 
     1276
     1277Article ID: SPE2925
     1278Article DOI: 10.1002/spe.2925
     1279Internal Article ID: 16922213
     1280Article: Advanced Control-flow and Concurrency in C A 
     1281Journal: Software: Practice and Experience                                                                     
     1282                                                                         
     1283You'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.                                                                     
     1284
     1285Sincerely,                                                                                 
     1286
     1287Wiley Author Services
  • doc/proposals/vtable.md

    r4b30e8c rc28ea4e  
    512512possibly like the one used to create the assertion.
    513513
     514### Extension: Associated Types Use
     515If the `associated_types.md` proposal is accepted the following trait could
     516be added:
     517
     518    trait is_virtual(dtype T) {
     519        dtype table;
     520        // An example assertion:
     521        const table & get_virtual_table(T &);
     522    }
     523
     524There may be more assertions but there has to be at least one way to find
     525the (possibly default) virtual table. It is required to construct instances
     526of the type.
     527
     528Without 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
     534Which is just a little bit longer to use but becomes more problematic if the
     535user has to explicately provide the table's name as it doesn't really have its
     536own type name. If it does it is probably mangled.
     537
    514538### Virtual Tables as Types
    515539Here we consider encoding plus the implementation of functions on it to be a
  • doc/theses/andrew_beach_MMath/thesis-frontpgs.tex

    r4b30e8c rc28ea4e  
    55% TITLE PAGE
    66%----------------------------------------------------------------------
     7
     8% Slowly generalizing.
     9\ethesissetup{
     10  author=Pat Neugraad,%
     11  title={University of Waterloo E-Thesis Template for \LaTeX},
     12  degree=phd,%
     13  program=Zoology,%
     14}
    715
    816\pagestyle{empty}
     
    1523        \vspace*{1.0cm}
    1624
    17         \Huge
    18         {\bf University of Waterloo E-Thesis Template for \LaTeX }
    19 
    20         \vspace*{1.0cm}
    21 
    22         \normalsize
     25        {\Huge\bf \eprint{title}}
     26
     27        \vspace*{1.0cm}
     28
    2329        by \\
    2430
    2531        \vspace*{1.0cm}
    2632
    27         \Large
    28         Pat Neugraad \\
     33        {\Large \eprint{author}} \\
    2934
    3035        \vspace*{3.0cm}
    3136
    32         \normalsize
    3337        A thesis \\
    3438        presented to the University of Waterloo \\
    3539        in fulfillment of the \\
    3640        thesis requirement for the degree of \\
    37         Doctor of Philosophy \\
     41        \eprint{degree} \\
    3842        in \\
    39         Zoology \\
     43        \eprint{program} \\
    4044
    4145        \vspace*{2.0cm}
     
    4549        \vspace*{1.0cm}
    4650
    47         \copyright\ Pat Neugraad 2017 \\
     51        \copyright{} \eprint{author} 2017 \\
    4852        \end{center}
    4953\end{titlepage}
  • doc/theses/andrew_beach_MMath/uw-ethesis.cls

    r4b30e8c rc28ea4e  
    1919%
    2020% Exported Names:
     21%   \ethesissetup{<key-value-pairs>}
     22%     Preforms set-up (or a reconfiguration) of the document class. See the
     23%     Set-Up Keys section for the keys that may be passed in. Use commas to
     24%     seperate key-value-pairs.
     25%
    2126%   \ifformat{<format>}{<true>}{<false>}
    2227%     If the document's format is <format> than expands to <true> otherwise
     
    2732%     initial setup depends on the document format but they can be overriden
    2833%     with options in <setup> (set hyperref's \hypersetup for details).
     34%
     35%   \eprint{<key>}
     36%     Expands to a human readable value tracked by the ethesis class. This
     37%     can be used to retreave and format values set during set up.
     38%
     39% Set-Up Keys:
     40%   author=<text>
     41%   title=<text>
     42%   program=<text>
     43%   subject=<text>
     44%   keywords=<text>
     45%   degree=masters|phd
     46%   faculty=ahs|arts|eng|env|math|sci
    2947\NeedsTeXFormat{LaTeX2e}
    30 \ProvidesClass{uw-ethesis}[2020/03/24 v0.1 UW-eThesis Template Document Class]
     48\ProvidesClass{uw-ethesis}[2020/10/25 v0.2 UW-eThesis Template Document Class]
    3149
    3250\RequirePackage{etoolbox}
     51\RequirePackage{xkeyval}
    3352
    3453% Requested Format:
    35 \newrobustcmd*{\ethesis@format}{digital}
    36 \DeclareOption{print}{\renewrobustcmd*{\ethesis@format}{print}}
    37 \DeclareOption{digital}{\renewrobustcmd*{\ethesis@format}{digital}}
     54\newrobustcmd*{\ethesis@@format}{digital}
     55\DeclareOption{print}{\renewrobustcmd*{\ethesis@@format}{print}}
     56\DeclareOption{digital}{\renewrobustcmd*{\ethesis@@format}{digital}}
    3857
    3958\ProcessOptions\relax
     
    81100% a recto page. This will often require an empty verso (left-hand side) page
    82101% that should not have the page number printed on it.
    83 \let\origdoublepage\cleardoublepage
     102\let\ethesis@origdoublepage\cleardoublepage
    84103\newcommand{\clearemptydoublepage}{%
    85   \clearpage{\pagestyle{empty}\origdoublepage}}
     104  \clearpage{\pagestyle{empty}\ethesis@origdoublepage}}
    86105\let\cleardoublepage\clearemptydoublepage
    87106
     
    89108\renewcommand*{\bibname}{References}
    90109
    91 % Configurations
    92 \def\setThesisTitle#1{\newrobustcmd*{\ethesis@title}{#1}}
    93 \def\setThesisAuthor#1{\newrobustcmd*{\ethesis@author}{#1}}
    94 \def\setThesisSubject#1{\newrobustcmd*{\ethesis@subject}{#1}}
    95 \def\setThesisKeywords#1{\newrobustcmd*{\ethesis@keywords}{#1}}
     110\newrobustcmd*\ethesissetup[1]{\setkeys{ethesis}{#1}}
     111
     112\define@cmdkeys{ethesis}[ethesis@@]{%
     113  author,title,program,subject,keywords}
     114
     115\define@choicekey{ethesis}{degree}{masters,phd}{\def\ethesis@@degree{#1}}
     116\define@choicekey{ethesis}{faculty}{ahs,arts,eng,env,math,sci}%
     117  {\def\ethesis@@faculty{#1}}
     118
     119\newrobustcmd*\eprint[1]{
     120  \ifcsdef{ethesis@long#1}{\csuse{ethesis@long#1}}{%
     121    \ifcsdef{ethesis@@#1}{\csuse{ethesis@@#1}}{%
     122      % ERROR: (Check for a way to emit an actual error.)
     123      [UW-eThesis doesn't know how to print: #1 ]
     124    }
     125  }
     126}
     127
     128\newrobustcmd*\ethesis@longdegree{%
     129  \ifdefstring{\ethesis@@degree}{phd}{Doctor of Philosophy}{Masters}}
    96130
    97131% Includes the hyperref package loading a number of defaults.
     
    106140    pdfstartview={FitH},    % Fits the width of the page to the window.
    107141  }
    108   \ifdef{\ethesis@title}{\hypersetup{pdftitle={\ethesis@title}}}{}
    109   \ifdef{\ethesis@author}{\hypersetup{pdfauthor={\ethesis@author}}}{}
    110   \ifdef{\ethesis@subject}{\hypersetup{pdfsubject={\ethesis@subject}}}{}
    111   \ifdef{\ethesis@keywords}{\hypersetup{pdfkeywords={\ethesis@keywords}}}{}
     142  \ifdef{\ethesis@@title}{\hypersetup{pdftitle={\ethesis@@title}}}{}
     143  \ifdef{\ethesis@@author}{\hypersetup{pdfauthor={\ethesis@@author}}}{}
     144  \ifdef{\ethesis@@subject}{\hypersetup{pdfsubject={\ethesis@@subject}}}{}
     145  \ifdef{\ethesis@@keywords}{\hypersetup{pdfkeywords={\ethesis@@keywords}}}{}
    112146  \ifformat{print}{
    113147    \hypersetup{
  • doc/theses/thierry_delisle_PhD/comp_II/presentation.tex

    r4b30e8c rc28ea4e  
    3636        \miniframeson
    3737}
    38 \section{\CFA and Concurrency}
     38\section{Concurrency and \CFA}
     39\begin{frame}{Project}
     40        \begin{center}
     41                {\large Produce a scheduler for \CFA that is simple for programmers to understand and offers good general performance.}
     42        \end{center}
     43\end{frame}
     44%------------------------------
    3945\begin{frame}{\CFA}
     46        \CFA is a modern extension of C.
     47        It adds to C : overloading, constructors/destructors, polymorphism, and much more.
     48
     49        ~\newline
     50        For this project, the relevant aspects are:
     51        \begin{itemize}
     52                \item Fast and safe system language.
     53                \item Threading.
     54                \item Manual memory management.
     55        \end{itemize}
    4056
    4157\end{frame}
     
    104120\begin{frame}{Priority Scheduling}
    105121        \begin{center}
    106         {\large
     122                {\large
    107123                        Runs all ready threads in group \textit{A} before any ready threads in group \textit{B}.
    108124                }
     
    136152
    137153        Processors begin busy for long periods can mean starvation.
     154\end{frame}
     155%------------------------------
     156\begin{frame}{Scheduling in Practice: Summary}
     157        \begin{columns}
     158                \begin{column}{0.5\textwidth}
     159                        \textbf{Feedback Scheduling}
     160                        \newline
     161
     162                        \begin{itemize}
     163                                \item Inappropriate for short lived threads.
     164                                \item Overkill for cooperating threads.\newline
     165                        \end{itemize}
     166                \end{column}
     167                \begin{column}{0.5\textwidth}
     168                        \textbf{Priority Scheduling}
     169                        \newline
     170
     171                        \begin{itemize}
     172                                \item Allows lasting starvation.\newline
     173                                \item Hard to reason about.\newline~\newline
     174                        \end{itemize}
     175                \end{column}
     176        \end{columns}
     177
     178        ~\newline
     179        ~\newline
     180        \CFA would benefit from something different.
    138181\end{frame}
    139182%==============================
     
    190233        \begin{itemize}
    191234                \item Acquire for reading for normal scheduling operations.
    192                 \item Acquire for right when resizing the array and creating/deleting internal queues.
     235                \item Acquire for writing when resizing the array and creating/deleting internal queues.
    193236        \end{itemize}
    194237\end{frame}
     
    314357        Runtime system and scheduling are still open topics.
    315358        \newline
     359        \newline
    316360
    317361        This work offers a novel runtime and scheduling package.
     362        \newline
    318363        \newline
    319364
     
    336381
    337382%------------------------------
    338 \begin{frame}{Timeline}
     383\begin{frame}{}
    339384        \begin{center}
    340385                {\large Questions?}
  • doc/theses/thierry_delisle_PhD/comp_II/presentationstyle.sty

    r4b30e8c rc28ea4e  
    2020\setbeamertemplate{blocks}[rounded][shadow=false]
    2121\newcommand\xrowht[2][0]{\addstackgap[.5\dimexpr#2\relax]{\vphantom{#1}}}
     22\setbeamertemplate{sections/subsections in toc}{\inserttocsectionnumber.~\inserttocsection}
    2223
    2324%==============================
     
    3637\setbeamercolor{palette primary}{bg=colbg}
    3738\setbeamercolor{palette tertiary}{fg=red}
     39\setbeamercolor{section in toc}{fg=white}
     40\setbeamercolor{subsection in toc}{fg=gray}
    3841
    3942%==============================
  • doc/theses/thierry_delisle_PhD/thesis/Makefile

    r4b30e8c rc28ea4e  
    1515        front \
    1616        intro \
     17        existing \
    1718        runtime \
    1819        core \
     
    2728        base \
    2829        empty \
     30        system \
    2931}
    3032
     
    3739## Define the documents that need to be made.
    3840all: thesis.pdf
    39 thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} glossary.tex
     41thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} glossary.tex local.bib
    4042
    4143DOCUMENT = thesis.pdf
  • doc/theses/thierry_delisle_PhD/thesis/fig/system.fig

    r4b30e8c rc28ea4e  
    1 #FIG 3.2  Produced by xfig version 3.2.5c
     1#FIG 3.2  Produced by xfig version 3.2.7b
    22Landscape
    33Center
     
    36361 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 3225 4125 4650 4425
    39 6 4350 4200 4650 4350
    40 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4425 4275 15 15 4425 4275 4440 4290
    41 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4500 4275 15 15 4500 4275 4515 4290
    42 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4575 4275 15 15 4575 4275 4590 4290
    43 -6
    44 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3450 4275 225 150 3450 4275 3675 4425
    45 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 4275 225 150 4050 4275 4275 4425
    46 -6
    47 6 6675 4125 7500 4425
    48 6 7200 4200 7500 4350
    49 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7275 4275 15 15 7275 4275 7290 4290
    50 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7350 4275 15 15 7350 4275 7365 4290
    51 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7425 4275 15 15 7425 4275 7440 4290
    52 -6
    53 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6900 4275 225 150 6900 4275 7125 4425
    54 -6
    55386 6675 3525 8025 3975
    56392 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
     
    79621 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3975 2850 150 150 3975 2850 4125 2850
    80631 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 7200 2775 150 150 7200 2775 7350 2775
    81 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 4860
     641 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 4830
    82651 3 0 1 0 0 0 0 0 0.000 1 0.0000 7200 2775 30 30 7200 2775 7230 2805
    83661 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3525 3600 150 150 3525 3600 3675 3600
    84 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3875 4800 100 100 3875 4800 3975 4800
    85 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 4800 150 75 4650 4800 4800 4875
     671 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4625 4838 100 100 4625 4838 4725 4838
    86682 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    8769         2400 4200 2400 3750 1950 3750 1950 4200 2400 4200
     
    153135        1 1 1.00 45.00 90.00
    154136         7875 3750 7875 2325 7200 2325 7200 2550
     1372 2 1 1 -1 -1 0 0 -1 3.000 0 0 0 0 0 5
     138         6975 4950 6750 4950 6750 4725 6975 4725 6975 4950
    1551392 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    156140         5850 4950 5850 4725 5625 4725 5625 4950 5850 4950
    157 2 2 1 1 -1 -1 0 0 -1 3.000 0 0 0 0 0 5
    158          6975 4950 6750 4950 6750 4725 6975 4725 6975 4950
    159 4 1 -1 0 0 0 10 0.0000 2 105 720 5550 4425 Processors\001
    160 4 1 -1 0 0 0 10 0.0000 2 120 1005 4200 3225 Blocked Tasks\001
    161 4 1 -1 0 0 0 10 0.0000 2 150 870 4200 3975 Ready Tasks\001
    162 4 1 -1 0 0 0 10 0.0000 2 135 1095 7350 1725 Other Cluster(s)\001
    163 4 1 -1 0 0 0 10 0.0000 2 105 840 4650 1725 User Cluster\001
    164 4 1 -1 0 0 0 10 0.0000 2 150 615 2175 3675 Manager\001
    165 4 1 -1 0 0 0 10 0.0000 2 105 990 2175 3525 Discrete-event\001
    166 4 1 -1 0 0 0 10 0.0000 2 135 795 2175 4350 preemption\001
    167 4 0 -1 0 0 0 10 0.0000 2 150 1290 2325 4875 generator/coroutine\001
    168 4 0 -1 0 0 0 10 0.0000 2 120 270 4050 4875 task\001
    169 4 0 -1 0 0 0 10 0.0000 2 105 450 7050 4875 cluster\001
    170 4 0 -1 0 0 0 10 0.0000 2 105 660 5925 4875 processor\001
    171 4 0 -1 0 0 0 10 0.0000 2 105 555 4875 4875 monitor\001
     1414 1 -1 0 0 0 10 0.0000 2 135 900 5550 4425 Processors\001
     1424 1 -1 0 0 0 10 0.0000 2 165 1170 4200 3975 Ready Threads\001
     1434 1 -1 0 0 0 10 0.0000 2 165 1440 7350 1725 Other Cluster(s)\001
     1444 1 -1 0 0 0 10 0.0000 2 135 1080 4650 1725 User Cluster\001
     1454 1 -1 0 0 0 10 0.0000 2 165 630 2175 3675 Manager\001
     1464 1 -1 0 0 0 10 0.0000 2 135 1260 2175 3525 Discrete-event\001
     1474 1 -1 0 0 0 10 0.0000 2 150 900 2175 4350 preemption\001
     1484 0 -1 0 0 0 10 0.0000 2 135 630 7050 4875 cluster\001
     1494 1 -1 0 0 0 10 0.0000 2 135 1350 4200 3225 Blocked Threads\001
     1504 0 -1 0 0 0 10 0.0000 2 135 540 4800 4875 thread\001
     1514 0 -1 0 0 0 10 0.0000 2 120 810 5925 4875 processor\001
     1524 0 -1 0 0 0 10 0.0000 2 165 1710 2325 4875 generator/coroutine\001
  • doc/theses/thierry_delisle_PhD/thesis/glossary.tex

    r4b30e8c rc28ea4e  
    11\makeglossaries
     2
     3% ----------------------------------
     4% Acronyms
     5\newacronym{api}{API}{Application Programming Interface}
     6\newacronym{fifo}{FIFO}{First-In, First-Out}
     7\newacronym{io}{I/O}{Input and Output}
     8\newacronym{numa}{NUMA}{Non-Uniform Memory Access}
     9\newacronym{raii}{RAII}{Resource Acquisition Is Initialization}
     10\newacronym{tls}{TLS}{Thread Local Storage}
     11
     12% ----------------------------------
     13% Definitions
     14
     15\longnewglossaryentry{thrd}
     16{name={thread}}
     17{
     18Threads created and managed inside user-space. Each thread has its own stack and its own thread of execution. User-level threads are invisible to the underlying operating system.
     19
     20\textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.}
     21}
     22
     23\longnewglossaryentry{proc}
     24{name={processor}}
     25{
     26
     27}
     28
     29\longnewglossaryentry{rQ}
     30{name={ready-queue}}
     31{
     32
     33}
     34
     35\longnewglossaryentry{uthrding}
     36{name={user-level threading}}
     37{
     38
     39
     40\textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.}
     41}
     42
     43% ----------------------------------
    244
    345\longnewglossaryentry{hthrd}
    446{name={hardware thread}}
    547{
    6 Threads representing the underlying hardware directly.
     48Threads representing the underlying hardware directly, \eg the CPU core, or hyper-thread if the hardware supports multiple threads of execution per core. The number of hardware threads is considered to be always fixed to a specific number determined by the hardware.
    749
    8 \textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.}
    9 }
    10 
    11 \longnewglossaryentry{thrd}
    12 {name={threads}}
    13 {
    14 Threads created and managed inside user-space. Each thread has its own stack and its own thread of execution. User-level threads are invisible to the underlying operating system.
    15 
    16 \textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.}
     50\textit{Synonyms : }
    1751}
    1852
     
    5791}
    5892
    59 \longnewglossaryentry{proc}
    60 {name={virtual processor}}
    61 {
    6293
    63 }
    64 
    65 \longnewglossaryentry{Q}
    66 {name={work-queue}}
    67 {
    68 
    69 }
    7094
    7195\longnewglossaryentry{at}
     
    131155}
    132156
    133 
    134 \newacronym{tls}{TLS}{Thread Local Storage}
    135 \newacronym{api}{API}{Application Program Interface}
    136 \newacronym{raii}{RAII}{Resource Acquisition Is Initialization}
    137 \newacronym{numa}{NUMA}{Non-Uniform Memory Access}
  • doc/theses/thierry_delisle_PhD/thesis/text/core.tex

    r4b30e8c rc28ea4e  
    11\chapter{Scheduling Core}\label{core}
    22
    3 This chapter addresses the need of scheduling on a somewhat ideal scenario
     3Before discussing scheduling in general, where it is important to address systems that are changing states, this document discusses scheduling in a somewhat ideal scenerio, where the system has reached a steady state. For this purpose, a steady state is loosely defined as a state where there are always \glspl{thrd} ready to run and but the system has the ressources necessary to accomplish the work. In short, the system is neither overloaded or underloaded.
    44
    5 \section{Existing Schedulers}
    6 \subsection{Feedback Scheduling}
     5I believe it is important to discuss the steady state first because it is the easiest case to handle and, relatedly, the case in which the best performance is to be expected. As such, when the system is either overloaded or underloaded, a common approach is to try to adapt the system to the new load and return to the steady state. Flaws in the scheduling in the steady state tend therefore to be pervasive in all states.
    76
    8 \subsection{Priority Scheduling}\label{priority}
     7\section{Design Goals}
     8As with most of the design decisions behind \CFA, the main goal is to match the expectation of the programmer, according to their probable mental model. To match these expectations, the design must offer the programmers sufficient guarantees so that, as long as the programmer respects the mental model, the system will also respect this model.
    99
    10 \subsection{Work Stealing}
     10For threading, a simple and common mental model is the ``Ideal multi-tasking CPU'' :
     11
     12\begin{displayquote}[Linux CFS\cit{https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt}]
     13        {[The]} ``Ideal multi-tasking CPU'' is a (non-existent  :-)) CPU that has 100\% physical power and which can run each task at precise equal speed, in parallel, each at [an equal fraction of the] speed.  For example: if there are 2 tasks running, then it runs each at 50\% physical power --- i.e., actually in parallel.
     14\end{displayquote}
     15
     16Applied to threads, this model states that every ready \gls{thrd} immediately runs in parallel with all other ready \glspl{thrd}. While a strict implementation of this model is not feasible, programmers still have expectations about scheduling that come from this model.
     17
     18In general, the expectation at the center of this model is that ready \glspl{thrd} do not interfere with eachother but simply share the hardware. This makes it easier to reason about threading because ready \glspl{thrd} can be taken in isolation and the effect of the scheduler can be virtually ignored. This expectation of \gls{thrd} independence means the scheduler is expected to offer 2 guarantees:
     19\begin{enumerate}
     20        \item A fairness guarantee: a \gls{thrd} that is ready to run will not be prevented to do so by another thread.
     21        \item A performance guarantee: a \gls{thrd} that wants to start or stop running will not be slowed down by other threads wanting to do the same.
     22\end{enumerate}
     23
     24It is important to note that these guarantees are expected only up to a point. \Glspl{thrd} that are ready to run should not be prevented to do so, but they still need to share a limited amount of hardware. Therefore, the guarantee is considered respected if a \gls{thrd} gets access to a \emph{fair share} of the hardware, even if that share is very small.
     25
     26Similarly the performance guarantee, the lack of interferance between threads is only relevant op to a point. Ideally the cost of running and blocking would be constant regardless of contention, but the guarantee is considered satisfied if the cost is not \emph{too high} with or without contention. How much is an acceptable cost is obviously highly variable. For this document the performance experimentation will attempt to show that the cost of scheduling is not a major factor in application performance. This demonstration can be made by comparing application built in \CFA to applications built with other languages or other models. If the performance of an application built in \CFA is not meaningfully different than one built with a different runtime, then the scheduler has a negigeable impact on performance, \ie its impact can be ignored. Recall from a few paragraphs ago that the expectation of programmers is that the impact of the scheduler can be ignored. Therefore, if the cost of scheduling is not a significant portion of the runtime of several different application, I will consider the guarantee achieved.
     27
     28\todo{This paragraph should be moved later}
     29% The next step is then to decide what is considered a \emph{fair share}, \ie what metric is used to measure fairness. Since \CFA is intended to allow numerous short lived threads, I decided to avoid total CPU time as the measure of fairness. Total CPU time inherently favors new \glspl{thrd} over older ones which isn't necessarily a good thing. Instead, fairness is measured in terms of opportunities to run. This metric is more appropriate for a mix of short and long lived \glspl{thrd}.
    1130
    1231\section{Design}
    13 While avoiding the pitfalls of Feedback Scheduling is fairly easy, scheduling does not innately require feedback, avoiding prioritization of \glspl{thrd} is more difficult because of implicitly priorities, see Subsection~\ref{priority}.
     32While avoiding the pitfalls of Feedback Scheduling is fairly easy, scheduling does not innately require feedback, avoiding prioritization of \glspl{thrd} is more difficult because of implicitly priorities, see Subsection~\ref{priority}. A strictly \glsxtrshort{fifo} rea
    1433
    1534\subsection{Sharding}
     
    1938                \input{base.pstex_t}
    2039        \end{center}
    21         \caption{Relaxed FIFO list at the base of the scheduler: an array of strictly FIFO lists.
    22         The timestamp is in all nodes and cell arrays.}
     40        \caption{Relaxed FIFO list}
    2341        \label{fig:base}
     42        List at the base of the scheduler: an array of strictly FIFO lists.
     43        The timestamp is in all nodes and cell arrays.
    2444\end{figure}
    2545
     
    2848Indeed, if the number of \glspl{thrd} does not far exceed the number of queues, it is probable that several of these queues are empty.
    2949Figure~\ref{fig:empty} shows an example with 2 \glspl{thrd} running on 8 queues, where the chances of getting an empty queue is 75\% per pick, meaning two random picks yield a \gls{thrd} only half the time.
    30 This can lead to performance problems since picks that do not yield a \gls{thrd} are not useful and do not necessarily help make more informed guesses.
    31 
    32 Solutions to this problem can take many forms, but they ultimately all have to encode where the threads are in some form. My results show that the density and locality of this encoding is generally the dominating factor in these scheme.
    33 
    34 \paragraph{Dense Information}
    35 
    36 
    37 
    3850
    3951
     
    4254                \input{empty.pstex_t}
    4355        \end{center}
    44         \caption{``More empty'' state of the queue: the array contains many empty cells.}
     56        \caption{``More empty'' Relaxed FIFO list}
    4557        \label{fig:empty}
     58        Emptier state of the queue: the array contains many empty cells, that is strictly FIFO lists containing no elements.
    4659\end{figure}
     60
     61This can lead to performance problems since picks that do not yield a \gls{thrd} are not useful and do not necessarily help make more informed guesses.
     62
     63Solutions to this problem can take many forms, but they ultimately all have to encode where the threads are in some form. My results show that the density and locality of this encoding is generally the dominating factor in these scheme.
     64
     65\paragraph{Dense Information}
  • doc/theses/thierry_delisle_PhD/thesis/text/front.tex

    r4b30e8c rc28ea4e  
    184184\phantomsection         % allows hyperref to link to the correct page
    185185
     186% TODOs and missing citations
     187% -----------------------------
    186188\listofcits
    187189\listoftodos
     190\cleardoublepage
     191\phantomsection         % allows hyperref to link to the correct page
    188192
    189193
  • doc/theses/thierry_delisle_PhD/thesis/text/intro.tex

    r4b30e8c rc28ea4e  
    1 \chapter{Introduction}
     1\chapter*{Introduction}\label{intro}
     2\todo{A proper intro}
     3
     4The C programming language\cit{C}
     5
     6The \CFA programming language\cite{cfa:frontpage,cfa:typesystem} which extends the C programming language to add modern safety and productiviy features while maintaining backwards compatibility. Among it's productiviy features, \CFA introduces support for threading\cit{CFA Concurrency}, to allow programmers to write modern concurrent and parallel programming.
     7While previous work on the concurrent package of \CFA focused on features and interfaces, this thesis focuses on performance, introducing \glsxtrshort{api} changes only when required by performance considerations. More specifically, this thesis concentrates on scheduling and \glsxtrshort{io}. Prior to this work, the \CFA runtime used a strictly \glsxtrshort{fifo} \gls{rQ}.
     8
     9This work exclusively concentrates on Linux as it's operating system since the existing \CFA runtime and compiler does not already support other operating systems. Furthermore, as \CFA is yet to be released, supporting version of Linux older that the latest version is not a goal of this work.
  • doc/theses/thierry_delisle_PhD/thesis/text/io.tex

    r4b30e8c rc28ea4e  
    1 \chapter{I/O}
     1\chapter{User Level \glsxtrshort{io}}
     2As mentionned in Section~\ref{prev:io}, User-Level \glsxtrshort{io} requires multiplexing the \glsxtrshort{io} operations of many \glspl{thrd} onto fewer \glspl{proc} using asynchronous \glsxtrshort{io} operations. Various operating systems offer various forms of asynchronous operations and as mentioned in Chapter~\ref{intro}, this work is exclusively focuesd on Linux.
    23
    34\section{Existing options}
     5Since \glsxtrshort{io} operations are generally handled by the
    46
    57\subsection{\texttt{epoll}, \texttt{poll} and \texttt{select}}
     
    79\subsection{Linux's AIO}
    810
     11
     12
     13\begin{displayquote}
     14        AIO is a horrible ad-hoc design, with the main excuse being "other,
     15        less gifted people, made that design, and we are implementing it for
     16        compatibility because database people - who seldom have any shred of
     17        taste - actually use it".
     18
     19        But AIO was always really really ugly.
     20
     21        \begin{flushright}
     22                -- Linus Torvalds\cit{https://lwn.net/Articles/671657/}
     23        \end{flushright}
     24\end{displayquote}
     25
     26Interestingly, in this e-mail answer, Linus goes on to describe
     27``a true \textit{asynchronous system call} interface''
     28that does
     29``[an] arbitrary system call X with arguments A, B, C, D asynchronously using a kernel thread''
     30in
     31``some kind of arbitrary \textit{queue up asynchronous system call} model''.
     32This description is actually quite close to the interface of the interface described in the next section.
     33
    934\subsection{\texttt{io\_uring}}
     35A very recent addition to Linux, \texttt{io\_uring}\cit{io\_uring} is a framework that aims to solve many of the problems listed with the above mentioned solutions.
    1036
    11 \subsection{Extra Kernel Threads}
     37\subsection{Extra Kernel Threads}\label{io:morethreads}
     38Finally, if the operating system does not offer any satisfying forms of asynchronous \glsxtrshort{io} operations, a solution is to fake it by creating a pool of \glspl{kthrd} and delegating operations to them in order to avoid blocking \glspl{proc}.
    1239
    1340\subsection{Discussion}
  • doc/theses/thierry_delisle_PhD/thesis/text/practice.tex

    r4b30e8c rc28ea4e  
    22The scheduling algorithm discribed in Chapter~\ref{core} addresses scheduling in a stable state.
    33However, it does not address problems that occur when the system changes state.
    4 Indeed the \CFA runtime, supports expanding and shrinking
    5 
    6 the number of KTHREAD\_place
    7 
    8 , both manually and, to some extent automatically.
     4Indeed the \CFA runtime, supports expanding and shrinking the number of KTHREAD\_place \todo{add kthrd to glossary}, both manually and, to some extent automatically.
    95This entails that the scheduling algorithm must support these transitions.
    106
  • doc/theses/thierry_delisle_PhD/thesis/text/runtime.tex

    r4b30e8c rc28ea4e  
    11\chapter{\CFA Runtime}
     2This chapter offers an overview of the capabilities of the \CFA runtime prior to this work.
    23
    3 \section{M:N Threading}
     4Threading in \CFA offers is based on \Gls{uthrding}, where \glspl{thrd} are the representation of a unit of work. As such, \CFA programmers should expect these units to be fairly inexpensive, that is: programmers should be able to create a large number of \glspl{thrd} and switch between \glspl{thrd} liberally without many concerns for performance.
     5
     6\section{M:N Threading}\label{prev:model}
     7
     8C traditionnally uses a 1:1 threading model. This model uses \glspl{kthrd} to achive parallelism and concurrency. In this model, every thread of computation maps to an object in the kernel. The kernel then has the responsibility of managing these threads, \eg creating, scheduling, blocking. This also entails that the kernel has a perfect view of every thread executing in the system\footnote{This is not completly true due to primitives like \texttt{futex}es, which have a significant portion of their logic in user space.}.
     9
     10By contrast \CFA uses an M:N threading models, where concurrency is achieved using many user-level threads mapped onto fewer \glspl{kthrd}. The user-level threads have the same semantic meaning as a \glspl{kthrd} in the 1:1 model, they represent an independant thread of execution with it's on stack. The difference is that user-level threads do not have a corresponding object in the kernel, they are handled by the runtime in user space and scheduled onto \glspl{kthrd}, referred to as \glspl{proc} in this document. \Glspl{proc} run a \gls{thrd} until it context switches out, it then choses a different \gls{thrd} to run.
    411
    512\section{Clusters}
     13\begin{figure}
     14        \begin{center}
     15                \input{system.pstex_t}
     16        \end{center}
     17        \caption{Overview of the \CFA runtime}
     18        \label{fig:system}
     19        \Glspl{thrd} are scheduled inside a particular cluster, where it only runs on the \glspl{proc} which belong to the cluster. The discrete-event manager, which handles preemption and timeout, is a \gls{kthrd} which lives outside any cluster and does not run \glspl{thrd}.
     20\end{figure}
     21\CFA allows the option to group user-level threading, in the form of clusters. Both \glspl{thrd} and \glspl{proc} belong to a specific cluster. \Glspl{thrd} will only be scheduled onto \glspl{proc} in the same cluster and scheduling is done independantly of other clusters. Figure~\ref{fig:system} shows an overview if this system. This allows programmers to control more tightly parallelism. It also opens the door to handling effects like NUMA, by pining clusters to specific NUMA node\footnote{This is not currently implemented in \CFA, but the only hurdle left is creating a generic interface for cpu masks.}.
     22
     23\section{Scheduling}
     24The \CFA runtime was previously using a strictly \glsxtrshort{fifo} ready queue with a single lock. This setup offers perfect fairness in terms of opportunities to run/ However, it offers poor scalability, since the performance of the ready queue can never be improved by adding more \glspl{hthrd}, but the contention can cause significant performance degradation.
     25
     26\section{\glsxtrshort{io}}\label{prev:io}
     27Prior to this work, the \CFA runtime did not add any particular support for \glsxtrshort{io} operations. \CFA being built on C, this means that, while all the operations available in C are available in \CFA, \glsxtrshort{io} operations are designed for the POSIX threading model\cit{pthreads}. Using these operations in a M:N threading model, when they are built for 1:1 threading, means that operations block \glspl{proc} instead of \glspl{thrd}. While this can work in certain cases, it limits the number of concurrent operations to the number of \glspl{proc} rather than \glspl{thrd}. This also means that deadlocks can occur because all \glspl{proc} are blocked even if at least one \gls{thrd} is ready to run. A simple example of this type of deadlock would be as follows:
     28
     29Given a simple network program with 2 \glspl{thrd} and a single \gls{proc}, one \gls{thrd} sends network requests to a server and the other \gls{thrd} waits for response from the server. If the second \gls{thrd} races ahead, it may wait for responses to requests that have not been sent yet. In theory, this should not be a problem, even if the second \gls{thrd} waits, the first \gls{thrd} is still ready to run and should just be able to get CPU time and send the request. In practice with M:N threading, while the first \gls{thrd} is ready, the lone \gls{proc} in this example will \emph{not} try to run the first \gls{thrd} if it is blocked in the \glsxtrshort{io} operation of the second \gls{thrd}. If this happen, the system is effectively deadlocked\footnote{In this example, the deadlocked could be resolved if the server sends unprompted messages to the client. However, this solution is not general and may not be appropriate even in this simple case.}.
     30
     31One of the objective of this work, is to introduce \emph{User-Level \glsxtrshort{io}} which, as a parallel to \glslink{uthrding}{User-Level \emph{Threading}}, blocks \glspl{thrd} rather than \glspl{proc} when doing \glsxtrshort{io} operations. This entails multiplexing the \glsxtrshort{io} operations of many \glspl{thrd} onto fewer \glspl{proc}. This multiplexing requires that a single \gls{proc} be able to execute multiple operations in parallel. This cannot be done with operations that block \glspl{proc}, \ie \glspl{kthrd}, since the first operation would prevent starting new operations for its duration. Executing operations in parallel requires \emph{asynchronous} \glsxtrshort{io}, sometimes referred to as \emph{non-blocking}, since the \gls{kthrd} is not blocked.
    632
    733\section{Interoperating with \texttt{C}}
     34While \glsxtrshort{io} operations are the classical example of operations that block \glspl{kthrd}, the challenges mentioned in the previous section do not require \glsxtrshort{io} to be involved. These challenges are a product of blocking system calls rather than \glsxtrshort{io}. C offers no tools to identify whether or not a librairy function will lead to a blocking system call. This fact means interoperatability with C becomes a challenge in a M:N threading model.
     35
     36Languages like Go and Java, which have strict interoperatability with C\cit{JNI, GoLang with C}, can control operations in C by ``sandboxing'' them. They can, for example, delegate C operations to \glspl{kthrd} that are not \glspl{proc}. Sandboxing may help towards guaranteeing that the deadlocks mentioned in the previous section do not occur.
     37
     38As mentioned in Section~\cit{\CFA intro}, \CFA is binary compatible with C and, as such, trivially supports calls to and from C librairies. Furthermore, interoperatability can happen within a single library, through inline code or simply C and \CFA translation units archived together. The fine-grained interoperatability between C and \CFA has two consequences:
     39\begin{enumerate}
     40        \item Precisely identifying C calls that could block is difficult.
     41        \item Introducing code where interoperatability occurs could have a significant impact on general performance.
     42\end{enumerate}
     43
     44Because of these consequences, this work does not attempt to ``sandbox'' calls to C. It is possible that conflicting calls to C could lead to deadlocks on \CFA's M:N threading model where they would not in the traditionnal 1:1 threading model. However, I judge that solving this problem in general, in a way that is composable and flexible, is too complex in itself and would add too much work to this thesis. Therefore it is outside the scope of this thesis.
  • doc/theses/thierry_delisle_PhD/thesis/thesis.tex

    r4b30e8c rc28ea4e  
    121121% installation instructions there.
    122122
     123\usepackage{csquotes}
     124\usepackage{indentfirst} % as any self-respecting frenchman would
     125
    123126% Setting up the page margins...
    124127% uWaterloo thesis requirements specify a minimum of 1 inch (72pt) margin at the
     
    218221% separate documents, they would each start with the \chapter command, i.e,
    219222% do not contain \documentclass or \begin{document} and \end{document} commands.
     223\part{Introduction}
    220224\input{text/intro.tex}
     225\input{text/existing.tex}
    221226\input{text/runtime.tex}
     227\part{Design}
    222228\input{text/core.tex}
    223229\input{text/practice.tex}
    224230\input{text/io.tex}
     231\part{Evaluation}
     232\chapter{Theoretical and Existance Proofs}
     233\chapter{Micro-Benchmarks}
     234\chapter{Larger-Scale applications}
     235\part{Conclusion \& Annexes}
    225236
    226237%----------------------------------------------------------------------
     
    245256\addcontentsline{toc}{chapter}{\textbf{References}}
    246257
    247 \bibliography{uw-ethesis}
     258\bibliography{local}
    248259% Tip 5: You can create multiple .bib files to organize your references.
    249260% Just list them all in the \bibliogaphy command, separated by commas (no spaces).
    250261
    251 % The following statement causes the specified references to be added to the bibliography% even if they were not
    252 % cited in the text. The asterisk is a wildcard that causes all entries in the bibliographic database to be included (optional).
    253 \nocite{*}
     262% % The following statement causes the specified references to be added to the bibliography% even if they were not
     263% % cited in the text. The asterisk is a wildcard that causes all entries in the bibliographic database to be included (optional).
     264% \nocite{*}
    254265
    255266% The \appendix statement indicates the beginning of the appendices.
  • libcfa/prelude/builtins.c

    r4b30e8c rc28ea4e  
    99// Author           : Peter A. Buhr
    1010// Created On       : Fri Jul 21 16:21:03 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Oct  9 18:26:19 2020
    13 // Update Count     : 110
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct 27 14:42:00 2020
     13// Update Count     : 111
    1414//
     15
     16#define __cforall_builtins__
    1517
    1618// type that wraps a pointer and a destructor-like function - used in generating implicit destructor calls for struct members in user-defined functions
  • libcfa/src/concurrency/clib/cfathread.cfa

    r4b30e8c rc28ea4e  
    5959        void cfathread_setproccnt( int ncnt ) {
    6060                assert( ncnt >= 1 );
    61                 adelete(proc_cnt, procs);
     61                adelete( procs );
    6262
    6363                proc_cnt = ncnt - 1;
  • libcfa/src/concurrency/coroutine.cfa

    r4b30e8c rc28ea4e  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue May 26 22:06:09 2020
    13 // Update Count     : 21
     12// Last Modified On : Fri Oct 23 23:05:24 2020
     13// Update Count     : 22
    1414//
    1515
     
    2424#include <unistd.h>
    2525#include <sys/mman.h>                                                                   // mprotect
    26 extern "C" {
    27 // use this define to make unwind.h play nice, definitely a hack
    28 #define HIDE_EXPORTS
    2926#include <unwind.h>
    30 #undef HIDE_EXPORTS
    31 }
    3227
    3328#include "kernel_private.hfa"
     29#include "exception.hfa"
    3430
    3531#define __CFA_INVOKE_PRIVATE__
     
    4945FORALL_DATA_INSTANCE(CoroutineCancelled, (dtype coroutine_t), (coroutine_t))
    5046
    51 struct __cfaehm_node {
    52         struct _Unwind_Exception unwind_exception;
    53         struct __cfaehm_node * next;
    54         int handler_index;
    55 };
    56 
    5747forall(dtype T)
    5848void mark_exception(CoroutineCancelled(T) *) {}
     
    6050forall(dtype T)
    6151void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {
     52        dst->virtual_table = src->virtual_table;
    6253        dst->the_coroutine = src->the_coroutine;
    6354        dst->the_exception = src->the_exception;
     
    7465        verify( desc->cancellation );
    7566        desc->state = Cancelled;
    76         exception_t * except = (exception_t *)(1 + (__cfaehm_node *)desc->cancellation);
     67        exception_t * except = __cfaehm_cancellation_exception( desc->cancellation );
    7768
    7869        // TODO: Remove explitate vtable set once trac#186 is fixed.
     
    9283
    9384// minimum feasible stack size in bytes
    94 #define MinStackSize 1000
     85static const size_t MinStackSize = 1000;
    9586extern size_t __page_size;                              // architecture pagesize HACK, should go in proper runtime singleton
    9687
     
    217208                size = libFloor(create_size - stack_data_size - diff, libAlign());
    218209        } // if
    219         assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", size, MinStackSize );
     210        assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %zd bytes for a stack.", size, MinStackSize );
    220211
    221212        this->storage = (__stack_t *)((intptr_t)storage + size);
  • libcfa/src/concurrency/exception.cfa

    r4b30e8c rc28ea4e  
    1010// Created On       : Mon Aug 17 10:41:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Aug 25 14:41:00 2020
    13 // Update Count     : 0
     12// Last Modified On : Wed Oct 28 14:34:00 2020
     13// Update Count     : 1
    1414//
    1515
    16 extern "C" {
    17 // use this define to make unwind.h play nice, definitely a hack
    18 #define HIDE_EXPORTS
    19 #include <unwind.h>
    20 #undef HIDE_EXPORTS
    21 }
     16#define __cforall_thread__
    2217
    23 #include "invoke.h"
    2418#include "exception.hfa"
     19
    2520#include "coroutine.hfa"
    2621
    2722extern struct $thread * mainThread;
     23extern "C" {
     24extern void __cfactx_thrd_leave();
     25}
    2826
    2927// Common pattern for all the stop functions, wait until the end then act.
     
    5250
    5351STOP_AT_END_FUNCTION(thread_cancelstop,
    54         // TODO: Instead pass information to the joiner.
    55         abort();
     52        __cfactx_thrd_leave();
     53        __cabi_abort( "Resumed cancelled thread" );
    5654)
    5755
     
    8583                stop_param = (void *)0x22;
    8684        } else {
     85                this_thread->self_cor.cancellation = unwind_exception;
     86
    8787                stop_func = thread_cancelstop;
    8888                stop_param = this_thread;
  • libcfa/src/concurrency/exception.hfa

    r4b30e8c rc28ea4e  
    1616#pragma once
    1717
     18// This is an internal bridge between the two modes and must be C compatable.
     19
     20#include <unwind.h>
    1821#include "bits/defs.hfa"
    1922#include "invoke.h"
     23#include "exception.h"
    2024
    2125#ifdef __cforall
    2226extern "C" {
    23 
    24 #define HIDE_EXPORTS
    2527#endif
    26 #include "unwind.h"
    2728
    2829struct exception_context_t * this_exception_context(void) OPTIONAL_THREAD;
     
    3233
    3334#ifdef __cforall
    34 #undef HIDE_EXPORTS
    3535}
    3636#endif
  • libcfa/src/concurrency/invoke.h

    r4b30e8c rc28ea4e  
    157157
    158158                // 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
    159163                volatile int ticket;
    160164                enum __Coroutine_State state:8;
  • libcfa/src/concurrency/io/call.cfa.in

    r4b30e8c rc28ea4e  
    4747        #include "kernel/fwd.hfa"
    4848
    49         #if defined(CFA_HAVE_IOSQE_FIXED_FILE) && defined(CFA_HAVE_IOSQE_IO_DRAIN) && defined(CFA_HAVE_IOSQE_ASYNC)
    50                 #define REGULAR_FLAGS (IOSQE_FIXED_FILE | IOSQE_IO_DRAIN | IOSQE_ASYNC)
    51         #elif defined(CFA_HAVE_IOSQE_FIXED_FILE) && defined(CFA_HAVE_IOSQE_ASYNC)
    52                 #define REGULAR_FLAGS (IOSQE_FIXED_FILE | IOSQE_ASYNC)
    53         #elif defined(CFA_HAVE_IOSQE_FIXED_FILE) && defined(CFA_HAVE_IOSQE_IO_DRAIN)
    54                 #define REGULAR_FLAGS (IOSQE_FIXED_FILE | IOSQE_IO_DRAIN)
    55         #elif defined(CFA_HAVE_IOSQE_IO_DRAIN) && defined(CFA_HAVE_IOSQE_ASYNC)
    56                 #define REGULAR_FLAGS (IOSQE_IO_DRAIN | IOSQE_ASYNC)
    57         #elif defined(CFA_HAVE_IOSQE_FIXED_FILE)
    58                 #define REGULAR_FLAGS (IOSQE_FIXED_FILE)
    59         #elif defined(CFA_HAVE_IOSQE_IO_DRAIN)
    60                 #define REGULAR_FLAGS (IOSQE_IO_DRAIN)
    61         #elif defined(CFA_HAVE_IOSQE_ASYNC)
    62                 #define REGULAR_FLAGS (IOSQE_ASYNC)
    63         #else
    64                 #define REGULAR_FLAGS (0)
    65         #endif
    66 
    67         #if defined(CFA_HAVE_IOSQE_IO_LINK) && defined(CFA_HAVE_IOSQE_IO_HARDLINK)
    68                 #define LINK_FLAGS (IOSQE_IO_LINK | IOSQE_IO_HARDLINK)
    69         #elif defined(CFA_HAVE_IOSQE_IO_LINK)
    70                 #define LINK_FLAGS (IOSQE_IO_LINK)
    71         #elif defined(CFA_HAVE_IOSQE_IO_HARDLINK)
    72                 #define LINK_FLAGS (IOSQE_IO_HARDLINK)
    73         #else
    74                 #define LINK_FLAGS (0)
    75         #endif
    76 
    77         #if defined(CFA_HAVE_SPLICE_F_FD_IN_FIXED)
    78                 #define SPLICE_FLAGS (SPLICE_F_FD_IN_FIXED)
    79         #else
    80                 #define SPLICE_FLAGS (0)
    81         #endif
     49        static const __u8 REGULAR_FLAGS = 0
     50                #if defined(CFA_HAVE_IOSQE_FIXED_FILE)
     51                        | IOSQE_FIXED_FILE
     52                #endif
     53                #if defined(CFA_HAVE_IOSQE_IO_DRAIN)
     54                        | IOSQE_IO_DRAIN
     55                #endif
     56                #if defined(CFA_HAVE_IOSQE_ASYNC)
     57                        | IOSQE_ASYNC
     58                #endif
     59        ;
     60
     61        static const __u32 LINK_FLAGS = 0
     62                #if defined(CFA_HAVE_IOSQE_IO_LINK)
     63                        | IOSQE_IO_LINK
     64                #endif
     65                #if defined(CFA_HAVE_IOSQE_IO_HARDLINK)
     66                        | IOSQE_IO_HARDLINK
     67                #endif
     68        ;
     69
     70        static const __u32 SPLICE_FLAGS = 0
     71                #if defined(CFA_HAVE_SPLICE_F_FD_IN_FIXED)
     72                        | SPLICE_F_FD_IN_FIXED
     73                #endif
     74        ;
    8275
    8376        extern [* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data );
  • libcfa/src/concurrency/io/setup.cfa

    r4b30e8c rc28ea4e  
    149149                id.full_proc = false;
    150150                id.id = doregister(&id);
     151                kernelTLS.this_proc_id = &id;
    151152                __cfaabi_dbg_print_safe( "Kernel : IO poller thread starting\n" );
    152153
     
    180181                                        kernelTLS.this_stats = io_ctx->self.curr_cluster->stats;
    181182                                #endif
    182                                 __post( io_ctx->sem, &id );
     183                                post( io_ctx->sem );
    183184                        }
    184185                }
     
    235236                        if( thrd.state == Ready || thrd.preempted != __NO_PREEMPTION ) {
    236237
    237                                 ready_schedule_lock( (struct __processor_id_t *)active_processor() );
     238                                ready_schedule_lock();
    238239
    239240                                        // This is the tricky case
     
    250251                                        // Fixup the thread state
    251252                                        thrd.state = Blocked;
    252                                         thrd.ticket = 0;
     253                                        thrd.ticket = TICKET_BLOCKED;
    253254                                        thrd.preempted = __NO_PREEMPTION;
    254255
    255                                 ready_schedule_unlock( (struct __processor_id_t *)active_processor() );
     256                                ready_schedule_unlock();
    256257
    257258                                // Pretend like the thread was blocked all along
     
    275276                        }
    276277                } else {
    277                         unpark( &thrd );
     278                        post( this.thrd.sem );
    278279                }
    279280
  • libcfa/src/concurrency/kernel.cfa

    r4b30e8c rc28ea4e  
    108108static $thread * __next_thread_slow(cluster * this);
    109109static void __run_thread(processor * this, $thread * dst);
    110 static void __wake_one(struct __processor_id_t * id, cluster * cltr);
     110static void __wake_one(cluster * cltr);
    111111
    112112static void push  (__cluster_idles & idles, processor & proc);
     
    252252                /* paranoid */ verify( kernelTLS.this_thread == thrd_dst );
    253253                /* paranoid */ verify( thrd_dst->context.SP );
     254                /* paranoid */ verify( thrd_dst->state != Halted );
    254255                /* 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
    255256                /* 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
     
    281282                if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) {
    282283                        // The thread was preempted, reschedule it and reset the flag
    283                         __schedule_thread( (__processor_id_t*)this, thrd_dst );
     284                        __schedule_thread( thrd_dst );
    284285                        break RUNNING;
    285286                }
     
    287288                if(unlikely(thrd_dst->state == Halted)) {
    288289                        // The thread has halted, it should never be scheduled/run again
    289                         // We may need to wake someone up here since
    290                         unpark( this->destroyer );
    291                         this->destroyer = 0p;
     290                        // finish the thread
     291                        __thread_finish( thrd_dst );
    292292                        break RUNNING;
    293293                }
     
    299299                int old_ticket = __atomic_fetch_sub(&thrd_dst->ticket, 1, __ATOMIC_SEQ_CST);
    300300                switch(old_ticket) {
    301                         case 1:
     301                        case TICKET_RUNNING:
    302302                                // This is case 1, the regular case, nothing more is needed
    303303                                break RUNNING;
    304                         case 2:
     304                        case TICKET_UNBLOCK:
    305305                                // This is case 2, the racy case, someone tried to run this thread before it finished blocking
    306306                                // In this case, just run it again.
     
    358358// Scheduler routines
    359359// KERNEL ONLY
    360 void __schedule_thread( struct __processor_id_t * id, $thread * thrd ) {
     360void __schedule_thread( $thread * thrd ) {
    361361        /* paranoid */ verify( thrd );
    362362        /* paranoid */ verify( thrd->state != Halted );
    363363        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     364        /* paranoid */ verify( kernelTLS.this_proc_id );
    364365        /* paranoid */ #if defined( __CFA_WITH_VERIFY__ )
    365366        /* paranoid */  if( thrd->state == Blocked || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION,
     
    374375        if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready;
    375376
    376         ready_schedule_lock  ( id );
     377        ready_schedule_lock();
    377378                push( thrd->curr_cluster, thrd );
    378                 __wake_one(id, thrd->curr_cluster);
    379         ready_schedule_unlock( id );
     379                __wake_one(thrd->curr_cluster);
     380        ready_schedule_unlock();
    380381
    381382        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     
    384385// KERNEL ONLY
    385386static inline $thread * __next_thread(cluster * this) with( *this ) {
    386         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    387 
    388         ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
     387        /* paranoid */ verify( kernelTLS.this_proc_id );
     388        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     389
     390        ready_schedule_lock();
    389391                $thread * thrd = pop( this );
    390         ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
    391 
    392         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     392        ready_schedule_unlock();
     393
     394        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     395        /* paranoid */ verify( kernelTLS.this_proc_id );
    393396        return thrd;
    394397}
     
    396399// KERNEL ONLY
    397400static inline $thread * __next_thread_slow(cluster * this) with( *this ) {
    398         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    399 
    400         ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
     401        /* paranoid */ verify( kernelTLS.this_proc_id );
     402        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     403
     404        ready_schedule_lock();
    401405                $thread * thrd = pop_slow( this );
    402         ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
    403 
    404         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     406        ready_schedule_unlock();
     407
     408        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     409        /* paranoid */ verify( kernelTLS.this_proc_id );
    405410        return thrd;
    406411}
    407412
    408 // KERNEL ONLY unpark with out disabling interrupts
    409 void __unpark(  struct __processor_id_t * id, $thread * thrd ) {
     413void unpark( $thread * thrd ) {
     414        if( !thrd ) return;
     415
     416        /* paranoid */ verify( kernelTLS.this_proc_id );
     417        bool full = kernelTLS.this_proc_id->full_proc;
     418        if(full) disable_interrupts();
     419
     420        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    410421        int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST);
    411422        switch(old_ticket) {
    412                 case 1:
     423                case TICKET_RUNNING:
    413424                        // Wake won the race, the thread will reschedule/rerun itself
    414425                        break;
    415                 case 0:
     426                case TICKET_BLOCKED:
    416427                        /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION );
    417428                        /* paranoid */ verify( thrd->state == Blocked );
    418429
    419430                        // Wake lost the race,
    420                         __schedule_thread( id, thrd );
     431                        __schedule_thread( thrd );
    421432                        break;
    422433                default:
    423434                        // This makes no sense, something is wrong abort
    424                         abort();
    425         }
    426 }
    427 
    428 void unpark( $thread * thrd ) {
    429         if( !thrd ) return;
    430 
    431         disable_interrupts();
    432         __unpark( (__processor_id_t*)kernelTLS.this_processor, thrd );
    433         enable_interrupts( __cfaabi_dbg_ctx );
     435                        abort("Thread %p (%s) has mismatch park/unpark\n", thrd, thrd->self_cor.name);
     436        }
     437        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     438
     439        if(full) enable_interrupts( __cfaabi_dbg_ctx );
     440        /* paranoid */ verify( kernelTLS.this_proc_id );
    434441}
    435442
     
    448455}
    449456
    450 // KERNEL ONLY
    451 void __leave_thread() {
    452         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    453         returnToKernel();
    454         abort();
     457extern "C" {
     458        // Leave the thread monitor
     459        // last routine called by a thread.
     460        // Should never return
     461        void __cfactx_thrd_leave() {
     462                $thread * thrd = TL_GET( this_thread );
     463                $monitor * this = &thrd->self_mon;
     464
     465                // Lock the monitor now
     466                lock( this->lock __cfaabi_dbg_ctx2 );
     467
     468                disable_interrupts();
     469
     470                thrd->state = Halted;
     471                if( TICKET_RUNNING != thrd->ticket ) { abort( "Thread terminated with pending unpark" ); }
     472                if( thrd != this->owner || this->recursion != 1) { abort( "Thread internal monitor has unbalanced recursion" ); }
     473
     474                // Leave the thread
     475                /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     476                returnToKernel();
     477                abort();
     478
     479                // Control flow should never reach here!
     480        }
    455481}
    456482
     
    486512//=============================================================================================
    487513// Wake a thread from the front if there are any
    488 static void __wake_one(struct __processor_id_t * id, cluster * this) {
    489         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    490         /* paranoid */ verify( ready_schedule_islocked( id ) );
     514static void __wake_one(cluster * this) {
     515        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     516        /* paranoid */ verify( ready_schedule_islocked() );
    491517
    492518        // Check if there is a sleeping processor
     
    506532        #endif
    507533
    508         /* paranoid */ verify( ready_schedule_islocked( id ) );
     534        /* paranoid */ verify( ready_schedule_islocked() );
    509535        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    510536
     
    709735                this.print_halts = true;
    710736        }
     737
     738        void print_stats_now( cluster & this, int flags ) {
     739                __print_stats( this.stats, this.print_stats, true, this.name, (void*)&this );
     740        }
    711741#endif
    712742// Local Variables: //
  • libcfa/src/concurrency/kernel.hfa

    r4b30e8c rc28ea4e  
    7979        // Handle to pthreads
    8080        pthread_t kernel_thread;
    81 
    82         // RunThread data
    83         // Action to do after a thread is ran
    84         $thread * destroyer;
    8581
    8682        // Preemption data
  • libcfa/src/concurrency/kernel/fwd.hfa

    r4b30e8c rc28ea4e  
    3535        extern "Cforall" {
    3636                extern __attribute__((aligned(128))) thread_local struct KernelThreadData {
    37                         struct $thread    * volatile this_thread;
    38                         struct processor  * volatile this_processor;
    39                         struct __stats_t  * volatile this_stats;
     37                        struct $thread          * volatile this_thread;
     38                        struct processor        * volatile this_processor;
     39                        struct __processor_id_t * volatile this_proc_id;
     40                        struct __stats_t        * volatile this_stats;
    4041
    4142                        struct {
  • libcfa/src/concurrency/kernel/startup.cfa

    r4b30e8c rc28ea4e  
    122122        NULL,
    123123        NULL,
     124        NULL,
    124125        { 1, false, false },
    125126};
     
    212213        //initialize the global state variables
    213214        kernelTLS.this_processor = mainProcessor;
     215        kernelTLS.this_proc_id   = (__processor_id_t*)mainProcessor;
    214216        kernelTLS.this_thread    = mainThread;
    215217
     
    227229        // Add the main thread to the ready queue
    228230        // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
    229         __schedule_thread((__processor_id_t *)mainProcessor, mainThread);
     231        __schedule_thread(mainThread);
    230232
    231233        // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
     
    324326        processor * proc = (processor *) arg;
    325327        kernelTLS.this_processor = proc;
     328        kernelTLS.this_proc_id   = (__processor_id_t*)proc;
    326329        kernelTLS.this_thread    = 0p;
    327330        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
     
    441444
    442445static void ?{}( $thread & this, current_stack_info_t * info) with( this ) {
    443         ticket = 1;
     446        ticket = TICKET_RUNNING;
    444447        state = Start;
    445448        self_cor{ info };
     
    474477        this.cltr = &_cltr;
    475478        full_proc = true;
    476         destroyer = 0p;
    477479        do_terminate = false;
    478480        preemption_alarm = 0p;
  • libcfa/src/concurrency/kernel_private.hfa

    r4b30e8c rc28ea4e  
    3333}
    3434
    35 void __schedule_thread( struct __processor_id_t *, $thread * )
     35void __schedule_thread( $thread * )
    3636#if defined(NDEBUG) || (!defined(__CFA_DEBUG__) && !defined(__CFA_VERIFY__))
    37         __attribute__((nonnull (2)))
     37        __attribute__((nonnull (1)))
    3838#endif
    3939;
    4040
    41 //Block current thread and release/wake-up the following resources
    42 void __leave_thread() __attribute__((noreturn));
     41//release/wake-up the following resources
     42void __thread_finish( $thread * thrd );
    4343
    4444//-----------------------------------------------------------------------------
     
    6363)
    6464
    65 // KERNEL ONLY unpark with out disabling interrupts
    66 void __unpark( struct __processor_id_t *, $thread * thrd );
    67 
    68 static inline bool __post(single_sem & this, struct __processor_id_t * id) {
    69         for() {
    70                 struct $thread * expected = this.ptr;
    71                 if(expected == 1p) return false;
    72                 if(expected == 0p) {
    73                         if(__atomic_compare_exchange_n(&this.ptr, &expected, 1p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    74                                 return false;
    75                         }
    76                 }
    77                 else {
    78                         if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    79                                 __unpark( id, expected );
    80                                 return true;
    81                         }
    82                 }
    83         }
    84 }
     65#define TICKET_BLOCKED (-1) // thread is blocked
     66#define TICKET_RUNNING ( 0) // thread is running
     67#define TICKET_UNBLOCK ( 1) // thread should ignore next block
    8568
    8669//-----------------------------------------------------------------------------
     
    197180// Reader side : acquire when using the ready queue to schedule but not
    198181//  creating/destroying queues
    199 static inline void ready_schedule_lock( struct __processor_id_t * proc) with(*__scheduler_lock) {
    200         unsigned iproc = proc->id;
    201         /*paranoid*/ verify(data[iproc].handle == proc);
     182static inline void ready_schedule_lock(void) with(*__scheduler_lock) {
     183        /*paranoid*/ verify( kernelTLS.this_proc_id );
     184
     185        unsigned iproc = kernelTLS.this_proc_id->id;
     186        /*paranoid*/ verify(data[iproc].handle == kernelTLS.this_proc_id);
    202187        /*paranoid*/ verify(iproc < ready);
    203188
     
    221206}
    222207
    223 static inline void ready_schedule_unlock( struct __processor_id_t * proc) with(*__scheduler_lock) {
    224         unsigned iproc = proc->id;
    225         /*paranoid*/ verify(data[iproc].handle == proc);
     208static inline void ready_schedule_unlock(void) with(*__scheduler_lock) {
     209        /*paranoid*/ verify( kernelTLS.this_proc_id );
     210
     211        unsigned iproc = kernelTLS.this_proc_id->id;
     212        /*paranoid*/ verify(data[iproc].handle == kernelTLS.this_proc_id);
    226213        /*paranoid*/ verify(iproc < ready);
    227214        /*paranoid*/ verify(data[iproc].lock);
     
    235222
    236223#ifdef __CFA_WITH_VERIFY__
    237         static inline bool ready_schedule_islocked( struct __processor_id_t * proc) {
     224        static inline bool ready_schedule_islocked(void) {
     225                /*paranoid*/ verify( kernelTLS.this_proc_id );
     226                __processor_id_t * proc = kernelTLS.this_proc_id;
    238227                return __scheduler_lock->data[proc->id].owned;
    239228        }
  • libcfa/src/concurrency/monitor.cfa

    r4b30e8c rc28ea4e  
    281281}
    282282
    283 extern "C" {
    284         // Leave the thread monitor
    285         // last routine called by a thread.
    286         // Should never return
    287         void __cfactx_thrd_leave() {
    288                 $thread * thrd = TL_GET( this_thread );
    289                 $monitor * this = &thrd->self_mon;
    290 
    291                 // Lock the monitor now
    292                 lock( this->lock __cfaabi_dbg_ctx2 );
    293 
    294                 disable_interrupts();
    295 
    296                 thrd->state = Halted;
    297 
    298                 /* paranoid */ verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this );
    299 
    300                 // Leaving a recursion level, decrement the counter
    301                 this->recursion -= 1;
    302 
    303                 // If we haven't left the last level of recursion
    304                 // it must mean there is an error
    305                 if( this->recursion != 0) { abort( "Thread internal monitor has unbalanced recursion" ); }
    306 
    307                 // Fetch the next thread, can be null
    308                 $thread * new_owner = next_thread( this );
    309 
    310                 // Release the monitor lock
    311                 unlock( this->lock );
    312 
    313                 // Unpark the next owner if needed
    314                 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this );
    315                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    316                 /* paranoid */ verify( ! kernelTLS.this_processor->destroyer );
    317                 /* paranoid */ verify( thrd->state == Halted );
    318 
    319                 kernelTLS.this_processor->destroyer = new_owner;
    320 
    321                 // Leave the thread
    322                 __leave_thread();
    323 
    324                 // Control flow should never reach here!
    325         }
    326 }
    327 
    328 // Join a thread
    329 forall( dtype T | is_thread(T) )
    330 T & join( T & this ) {
    331         $monitor *    m = get_monitor(this);
    332         void (*dtor)(T& mutex this) = ^?{};
    333         monitor_dtor_guard_t __guard = { &m, (fptr_t)dtor, true };
    334         {
    335                 return this;
    336         }
     283void __thread_finish( $thread * thrd ) {
     284        $monitor * this = &thrd->self_mon;
     285
     286        // Lock the monitor now
     287        /* paranoid */ verify( this->lock.lock );
     288        /* paranoid */ verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this );
     289        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     290        /* paranoid */ verify( thrd->state == Halted );
     291        /* paranoid */ verify( this->recursion == 1 );
     292
     293        // Leaving a recursion level, decrement the counter
     294        this->recursion -= 1;
     295        this->owner = 0p;
     296
     297        // Fetch the next thread, can be null
     298        $thread * new_owner = next_thread( this );
     299
     300        // Release the monitor lock
     301        unlock( this->lock );
     302
     303        // Unpark the next owner if needed
     304        /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this );
     305        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     306        /* paranoid */ verify( thrd->state == Halted );
     307        unpark( new_owner );
    337308}
    338309
  • libcfa/src/concurrency/preemption.cfa

    r4b30e8c rc28ea4e  
    3838// FwdDeclarations : timeout handlers
    3939static void preempt( processor   * this );
    40 static void timeout( struct __processor_id_t * id, $thread * this );
     40static void timeout( $thread * this );
    4141
    4242// FwdDeclarations : Signal handlers
     
    9191
    9292// Tick one frame of the Discrete Event Simulation for alarms
    93 static void tick_preemption( struct __processor_id_t * id ) {
     93static void tick_preemption(void) {
    9494        alarm_node_t * node = 0p;                                                       // Used in the while loop but cannot be declared in the while condition
    9595        alarm_list_t * alarms = &event_kernel->alarms;          // Local copy for ease of reading
     
    109109                }
    110110                else if( node->type == User ) {
    111                         timeout( id, node->thrd );
     111                        timeout( node->thrd );
    112112                }
    113113                else {
    114114                        bool unpark_thd = node->callback(*node);
    115                         if (unpark_thd) timeout( id, node->thrd );
     115                        if (unpark_thd) timeout( node->thrd );
    116116                }
    117117
     
    274274
    275275// reserved for future use
    276 static void timeout( struct __processor_id_t * id, $thread * this ) {
     276static void timeout( $thread * this ) {
    277277        #if !defined( __CFA_NO_STATISTICS__ )
    278278                kernelTLS.this_stats = this->curr_cluster->stats;
    279279        #endif
    280         __unpark( id, this );
     280        unpark( this );
    281281}
    282282
     
    417417        id.full_proc = false;
    418418        id.id = doregister(&id);
     419        kernelTLS.this_proc_id = &id;
    419420
    420421        // Block sigalrms to control when they arrive
     
    462463                        // __cfaabi_dbg_print_safe( "Kernel : Preemption thread tick\n" );
    463464                        lock( event_kernel->lock __cfaabi_dbg_ctx2 );
    464                         tick_preemption( &id );
     465                        tick_preemption();
    465466                        unlock( event_kernel->lock );
    466467                        break;
  • libcfa/src/concurrency/snzi.hfa

    r4b30e8c rc28ea4e  
    3636static inline void depart( __snzi_node_t & );
    3737
    38 #define __snzi_half -1
     38static const int __snzi_half = -1;
    3939
    4040//--------------------------------------------------
  • libcfa/src/concurrency/thread.cfa

    r4b30e8c rc28ea4e  
    1919
    2020#include "kernel_private.hfa"
     21#include "exception.hfa"
    2122
    2223#define __CFA_INVOKE_PRIVATE__
     
    2829        context{ 0p, 0p };
    2930        self_cor{ name, storage, storageSize };
    30         ticket = 1;
     31        ticket = TICKET_RUNNING;
    3132        state = Start;
    3233        preempted = __NO_PREEMPTION;
     
    5859}
    5960
     61FORALL_DATA_INSTANCE(ThreadCancelled, (dtype thread_t), (thread_t))
     62
     63forall(dtype T)
     64void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src) {
     65        dst->virtual_table = src->virtual_table;
     66        dst->the_thread = src->the_thread;
     67        dst->the_exception = src->the_exception;
     68}
     69
     70forall(dtype T)
     71const char * msg(ThreadCancelled(T) *) {
     72        return "ThreadCancelled";
     73}
     74
     75forall(dtype T)
     76static void default_thread_cancel_handler(ThreadCancelled(T) & ) {
     77        abort( "Unhandled thread cancellation.\n" );
     78}
     79
     80forall(dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)))
     81void ?{}( thread_dtor_guard_t & this,
     82                T & thrd, void(*defaultResumptionHandler)(ThreadCancelled(T) &)) {
     83        $monitor * m = get_monitor(thrd);
     84        void (*dtor)(T& mutex this) = ^?{};
     85        bool join = defaultResumptionHandler != (void(*)(ThreadCancelled(T)&))0;
     86        (this.mg){&m, (void(*)())dtor, join};
     87
     88        // After the guard set-up and any wait, check for cancellation.
     89        $thread * desc = get_thread(thrd);
     90        struct _Unwind_Exception * cancellation = desc->self_cor.cancellation;
     91        if ( likely( 0p == cancellation ) ) {
     92                return;
     93        } else if ( Cancelled == desc->state ) {
     94                return;
     95        }
     96        desc->state = Cancelled;
     97        if (!join) {
     98                defaultResumptionHandler = default_thread_cancel_handler;
     99        }
     100
     101        ThreadCancelled(T) except;
     102        // TODO: Remove explitate vtable set once trac#186 is fixed.
     103        except.virtual_table = &get_exception_vtable(&except);
     104        except.the_thread = &thrd;
     105        except.the_exception = __cfaehm_cancellation_exception( cancellation );
     106        throwResume except;
     107
     108        except.the_exception->virtual_table->free( except.the_exception );
     109        free( cancellation );
     110        desc->self_cor.cancellation = 0p;
     111}
     112
     113void ^?{}( thread_dtor_guard_t & this ) {
     114        ^(this.mg){};
     115}
     116
    60117//-----------------------------------------------------------------------------
    61118// Starting and stopping threads
     
    70127        verify( this_thrd->context.SP );
    71128
    72         __schedule_thread( (__processor_id_t *)kernelTLS.this_processor, this_thrd);
     129        __schedule_thread( this_thrd );
    73130        enable_interrupts( __cfaabi_dbg_ctx );
    74131}
     
    93150}
    94151
     152//-----------------------------------------------------------------------------
     153forall(dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))
     154T & join( T & this ) {
     155        thread_dtor_guard_t guard = { this, defaultResumptionHandler };
     156        return this;
     157}
     158
    95159// Local Variables: //
    96160// mode: c //
  • libcfa/src/concurrency/thread.hfa

    r4b30e8c rc28ea4e  
    2222#include "kernel.hfa"
    2323#include "monitor.hfa"
     24#include "exception.hfa"
    2425
    2526//-----------------------------------------------------------------------------
    2627// thread trait
    2728trait is_thread(dtype T) {
    28       void ^?{}(T& mutex this);
    29       void main(T& this);
    30       $thread* get_thread(T& this);
     29        void ^?{}(T& mutex this);
     30        void main(T& this);
     31        $thread* get_thread(T& this);
    3132};
     33
     34FORALL_DATA_EXCEPTION(ThreadCancelled, (dtype thread_t), (thread_t)) (
     35        thread_t * the_thread;
     36        exception_t * the_exception;
     37);
     38
     39forall(dtype T)
     40void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src);
     41
     42forall(dtype T)
     43const char * msg(ThreadCancelled(T) *);
    3244
    3345// define that satisfies the trait without using the thread keyword
     
    6577static inline void ?{}($thread & this, const char * const name, struct cluster & cl )                   { this{ name, cl, 0p, 65000 }; }
    6678static inline void ?{}($thread & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; }
     79
     80struct thread_dtor_guard_t {
     81        monitor_dtor_guard_t mg;
     82};
     83
     84forall( dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )
     85void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
     86void ^?{}( thread_dtor_guard_t & this );
    6787
    6888//-----------------------------------------------------------------------------
     
    108128//----------
    109129// join
    110 forall( dtype T | is_thread(T) )
     130forall( dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) )
    111131T & join( T & this );
    112132
  • libcfa/src/exception.c

    r4b30e8c rc28ea4e  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:13:00 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 29 15:52:22 2020
    13 // Update Count     : 34
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct 27 16:27:00 2020
     13// Update Count     : 35
    1414//
    1515
     
    1717#include <stddef.h> // for size_t
    1818
     19#include <unwind.h> // for struct _Unwind_Exception {...};
     20
    1921#include "exception.h"
    2022
    2123#include <stdlib.h>
    2224#include <stdio.h>
    23 #include <unwind.h>
    2425#include <bits/debug.hfa>
    2526#include "concurrency/invoke.h"
     
    113114
    114115// MEMORY MANAGEMENT =========================================================
    115 
    116 struct __cfaehm_node {
    117         struct _Unwind_Exception unwind_exception;
    118         struct __cfaehm_node * next;
    119         int handler_index;
    120 };
    121116
    122117#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
  • libcfa/src/exception.h

    r4b30e8c rc28ea4e  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // exception.h -- Builtins for exception handling.
     7// exception.h -- Internal exception handling definitions.
    88//
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:11:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue May 19 14:17:00 2020
    13 // Update Count     : 10
     12// Last Modified On : Tue Oct 27 14:45:00 2020
     13// Update Count     : 11
    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.
    1821
    1922#ifdef __cforall
    2023extern "C" {
    2124#endif
     25
     26// Included in C code or the built-ins.
     27#if !defined(__cforall) || defined(__cforall_builtins__)
    2228
    2329struct __cfaehm_base_exception_t;
     
    4753// Function catches termination exceptions.
    4854void __cfaehm_try_terminate(
    49     void (*try_block)(),
    50     void (*catch_block)(int index, exception_t * except),
    51     int (*match_block)(exception_t * except));
     55        void (*try_block)(),
     56        void (*catch_block)(int index, exception_t * except),
     57        int (*match_block)(exception_t * except));
    5258
    5359// Clean-up the exception in catch blocks.
     
    5662// Data structure creates a list of resume handlers.
    5763struct __cfaehm_try_resume_node {
    58     struct __cfaehm_try_resume_node * next;
    59     _Bool (*handler)(exception_t * except);
     64        struct __cfaehm_try_resume_node * next;
     65        _Bool (*handler)(exception_t * except);
    6066};
    6167
    6268// These act as constructor and destructor for the resume node.
    6369void __cfaehm_try_resume_setup(
    64     struct __cfaehm_try_resume_node * node,
    65     _Bool (*handler)(exception_t * except));
     70        struct __cfaehm_try_resume_node * node,
     71        _Bool (*handler)(exception_t * except));
    6672void __cfaehm_try_resume_cleanup(
    67     struct __cfaehm_try_resume_node * node);
     73        struct __cfaehm_try_resume_node * node);
    6874
    6975// Check for a standard way to call fake deconstructors.
    7076struct __cfaehm_cleanup_hook {};
    7177
     78#endif
     79
     80// Included in C code and the library.
     81#if !defined(__cforall) || !defined(__cforall_builtins__)
     82struct __cfaehm_node {
     83        struct _Unwind_Exception unwind_exception;
     84        struct __cfaehm_node * next;
     85        int handler_index;
     86};
     87
     88static 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
     93
    7294#ifdef __cforall
    7395}
     96
     97// Built-ins not visible in C.
     98#if defined(__cforall_builtins__)
    7499
    75100// Not all the built-ins can be expressed in C. These can't be
     
    124149
    125150#endif
     151
     152#endif
  • libcfa/src/stdlib.cfa

    r4b30e8c rc28ea4e  
    5858
    5959forall( dtype T | sized(T) | { void ^?{}( T & ); } )
    60 void adelete( size_t dim, T arr[] ) {
     60void adelete( T arr[] ) {
    6161        if ( arr ) {                                                                            // ignore null
     62                size_t dim = malloc_size( arr ) / sizeof( T );
    6263                for ( int i = dim - 1; i >= 0; i -= 1 ) {               // reverse allocation order, must be unsigned
    6364                        ^(arr[i]){};                                                            // run destructor
     
    6869
    6970forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } )
    70 void adelete( size_t dim, T arr[], Params rest ) {
     71void adelete( T arr[], Params rest ) {
    7172        if ( arr ) {                                                                            // ignore null
     73                size_t dim = malloc_size( arr ) / sizeof( T );
    7274                for ( int i = dim - 1; i >= 0; i -= 1 ) {               // reverse allocation order, must be unsigned
    7375                        ^(arr[i]){};                                                            // run destructor
  • libcfa/src/stdlib.hfa

    r4b30e8c rc28ea4e  
    263263// Cforall allocation/deallocation and constructor/destructor, array types
    264264forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p );
    265 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );
    266 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } ) void adelete( size_t dim, T arr[], Params rest );
     265forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] );
     266forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } ) void adelete( T arr[], Params rest );
    267267
    268268//---------------------------------------
  • src/AST/Convert.cpp

    r4b30e8c rc28ea4e  
    2525#include "AST/Init.hpp"
    2626#include "AST/Stmt.hpp"
     27#include "AST/TranslationUnit.hpp"
    2728#include "AST/TypeSubstitution.hpp"
    2829
     
    4748
    4849//================================================================================================
    49 namespace {
     50namespace ast {
    5051
    5152// This is to preserve the FindSpecialDecls hack. It does not (and perhaps should not)
    5253// 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
    5357ast::Type * sizeType = nullptr;
    5458ast::FunctionDecl * dereferenceOperator = nullptr;
     
    6367        using Cache = std::unordered_map< const ast::Node *, BaseSyntaxNode * >;
    6468        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;
    6574
    6675        template<typename T>
     
    154163        }
    155164
    156         const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final {
    157                 auto&& bfwd = get<Expression>().accept1( node->bitfieldWidth );
    158                 auto&& type = get<Type>().accept1( node->type );
    159                 auto&& init = get<Initializer>().accept1( node->init );
    160                 auto&& attr = get<Attribute>().acceptL( node->attributes );
     165        const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final {       
    161166                if ( inCache( node ) ) {
    162167                        return nullptr;
    163168                }
     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
    164173                auto decl = new ObjectDecl(
    165174                        node->name,
     
    168177                        bfwd,
    169178                        type->clone(),
    170                         init,
     179                        nullptr, // prevent infinite loop
    171180                        attr,
    172181                        Type::FuncSpecifiers( node->funcSpec.val )
    173182                );
    174                 return declWithTypePostamble( decl, node );
     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;
    175192        }
    176193
     
    205222                decl->statements = get<CompoundStmt>().accept1( node->stmts );
    206223                decl->withExprs = get<Expression>().acceptL( node->withExprs );
    207                 if ( dereferenceOperator == node ) {
     224                if ( ast::dereferenceOperator == node ) {
    208225                        Validate::dereferenceOperator = decl;
    209226                }
    210                 if ( dtorStructDestroy == node ) {
     227                if ( ast::dtorStructDestroy == node ) {
    211228                        Validate::dtorStructDestroy = decl;
    212229                }
     
    267284                );
    268285
    269                 if ( dtorStruct == node ) {
     286                if ( ast::dtorStruct == node ) {
    270287                        Validate::dtorStruct = decl;
    271288                }
     
    320337
    321338        const ast::Stmt * stmtPostamble( Statement * stmt, const ast::Stmt * node ) {
    322                 cache.emplace( node, stmt );
     339                // force statements in old tree to be unique.
     340                // cache.emplace( node, stmt );
     341                readonlyCache.emplace( node, stmt );
    323342                stmt->location = node->location;
    324343                stmt->labels = makeLabelL( stmt, node->labels );
     
    337356                if ( inCache( node ) ) return nullptr;
    338357                auto stmt = new ExprStmt( nullptr );
    339                 cache.emplace( node, stmt );
    340358                stmt->expr = get<Expression>().accept1( node->expr );
    341359                return stmtPostamble( stmt, node );
     
    10111029                auto stmts = node->stmts;
    10121030                // disable sharing between multiple StmtExprs explicitly.
    1013                 if (inCache(stmts)) {
    1014                         stmts = ast::deepCopy(stmts.get());
    1015                 }
     1031                // this should no longer be true.
     1032
    10161033                auto rslt = new StmtExpr(
    10171034                        get<CompoundStmt>().accept1(stmts)
     
    10201037                rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls);
    10211038                rslt->dtors       = get<Expression>().acceptL(node->dtors);
     1039                if (node->resultExpr) {
     1040                        // this MUST be found by children visit
     1041                        rslt->resultExpr  = strict_dynamic_cast<ExprStmt *>(readonlyCache.at(node->resultExpr));
     1042                }
    10221043
    10231044                auto expr = visitBaseExpr( node, rslt );
     
    10361057
    10371058                auto expr = visitBaseExpr( node, rslt );
    1038                 this->node = expr;
     1059                this->node = expr->clone();
    10391060                return nullptr;
    10401061        }
     
    11261147                auto type = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind };
    11271148                // I believe this should always be a BasicType.
    1128                 if ( sizeType == node ) {
     1149                if ( ast::sizeType == node ) {
    11291150                        Validate::SizeType = type;
    11301151                }
     
    13841405};
    13851406
    1386 std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > > && translationUnit ) {
     1407std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit ) {
    13871408        ConverterNewToOld c;
    13881409        std::list< Declaration * > decls;
    1389         for(auto d : translationUnit) {
     1410        for(auto d : translationUnit.decls) {
    13901411                decls.emplace_back( c.decl( d ) );
    13911412        }
     
    15291550
    15301551                // function type is now derived from parameter decls instead of storing them
     1552
     1553                /*
    15311554                auto ftype = new ast::FunctionType((ast::ArgumentFlag)old->type->isVarArgs, cv(old->type));
    15321555                ftype->params.reserve(paramVars.size());
     
    15401563                }
    15411564                ftype->forall = std::move(forall);
    1542                 visitType(old->type, ftype);
     1565                */
     1566
     1567                // can function type have attributes? seems not to be the case.
     1568                // visitType(old->type, ftype);
    15431569
    15441570                auto decl = new ast::FunctionDecl{
     
    15461572                        old->name,
    15471573                        // GET_ACCEPT_1(type, FunctionType),
     1574                        std::move(forall),
    15481575                        std::move(paramVars),
    15491576                        std::move(returnVars),
     
    15521579                        { old->linkage.val },
    15531580                        GET_ACCEPT_V(attributes, Attribute),
    1554                         { old->get_funcSpec().val }
     1581                        { old->get_funcSpec().val },
     1582                        old->type->isVarArgs
    15551583                };
    15561584
    1557                 decl->type = ftype;
     1585                // decl->type = ftype;
    15581586                cache.emplace( old, decl );
    15591587
     
    15701598
    15711599                if ( Validate::dereferenceOperator == old ) {
    1572                         dereferenceOperator = decl;
     1600                        ast::dereferenceOperator = decl;
    15731601                }
    15741602
    15751603                if ( Validate::dtorStructDestroy == old ) {
    1576                         dtorStructDestroy = decl;
     1604                        ast::dtorStructDestroy = decl;
    15771605                }
    15781606        }
     
    15991627
    16001628                if ( Validate::dtorStruct == old ) {
    1601                         dtorStruct = decl;
     1629                        ast::dtorStruct = decl;
    16021630                }
    16031631        }
     
    25312559                // I believe this should always be a BasicType.
    25322560                if ( Validate::SizeType == old ) {
    2533                         sizeType = type;
     2561                        ast::sizeType = type;
    25342562                }
    25352563                visitType( old, type );
     
    27762804#undef GET_ACCEPT_1
    27772805
    2778 std::list< ast::ptr< ast::Decl > > convert( const std::list< Declaration * > && translationUnit ) {
     2806ast::TranslationUnit convert( const std::list< Declaration * > && translationUnit ) {
    27792807        ConverterOldToNew c;
    2780         std::list< ast::ptr< ast::Decl > > decls;
     2808        ast::TranslationUnit unit;
    27812809        for(auto d : translationUnit) {
    27822810                d->accept( c );
    2783                 decls.emplace_back( c.decl() );
     2811                unit.decls.emplace_back( c.decl() );
    27842812        }
    27852813        deleteAll(translationUnit);
    2786         return decls;
     2814        return unit;
    27872815}
  • src/AST/Convert.hpp

    r4b30e8c rc28ea4e  
    1818#include <list>
    1919
    20 #include "AST/Node.hpp"
    21 
    2220class Declaration;
    2321namespace ast {
    24         class Decl;
     22        class TranslationUnit;
    2523};
    2624
    27 std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > > && translationUnit );
    28 std::list< ast::ptr< ast::Decl > > convert( const std::list< Declaration * > && translationUnit );
     25std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit );
     26ast::TranslationUnit convert( const std::list< Declaration * > && translationUnit );
  • src/AST/Decl.cpp

    r4b30e8c rc28ea4e  
    4848
    4949// --- FunctionDecl
     50
     51FunctionDecl::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          stmts( stmts ) {
     58                  FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs));
     59                  for (auto & param : this->params) {
     60                          ftype->params.emplace_back(param->get_type());
     61                  }
     62                  for (auto & ret : this->returns) {
     63                          ftype->returns.emplace_back(ret->get_type());
     64                  }
     65                  ftype->forall = std::move(forall);
     66                  this->type = ftype;
     67          }
     68
    5069
    5170const Type * FunctionDecl::get_type() const { return type.get(); }
  • src/AST/Decl.hpp

    r4b30e8c rc28ea4e  
    131131        std::vector< ptr<Expr> > withExprs;
    132132
    133         FunctionDecl( const CodeLocation & loc, const std::string & name,
     133        FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
    134134                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    135135                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
    136                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {})
    137         : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
    138           stmts( stmts ) {}
     136                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
     137        // : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
     138        //  stmts( stmts ) {}
    139139
    140140        const Type * get_type() const override;
  • src/AST/DeclReplacer.cpp

    r4b30e8c rc28ea4e  
    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                };
    4050        }
    4151
     
    5464                DeclMap declMap;
    5565                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 );
    5671        }
    5772
     
    88103                        return ninst;
    89104                }
     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
    90112        }
    91113}
  • src/AST/DeclReplacer.hpp

    r4b30e8c rc28ea4e  
    2323        class DeclWithType;
    2424        class TypeDecl;
     25        class Expr;
    2526
    2627        namespace DeclReplacer {
    2728                using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >;
    2829                using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >;
     30                using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >;
    2931
    3032                const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false );
    3133                const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false );
    3234                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);
    3336        }
    3437}
  • src/AST/Expr.cpp

    r4b30e8c rc28ea4e  
    6767// --- UntypedExpr
    6868
    69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, Expr * arg ) {
     69UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) {
    7070        assert( arg );
    7171
     
    9292}
    9393
    94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs ) {
     94UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) {
    9595        assert( lhs && rhs );
    9696
     
    102102        }
    103103        return ret;
     104}
     105
     106// --- VariableExpr
     107
     108VariableExpr::VariableExpr( const CodeLocation & loc )
     109: Expr( loc ), var( nullptr ) {}
     110
     111VariableExpr::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
     118bool VariableExpr::get_lvalue() const {
     119        // It isn't always an lvalue, but it is never an rvalue.
     120        return true;
     121}
     122
     123VariableExpr * 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;
    104129}
    105130
     
    238263}
    239264
    240 // --- VariableExpr
    241 
    242 VariableExpr::VariableExpr( const CodeLocation & loc )
    243 : Expr( loc ), var( nullptr ) {}
    244 
    245 VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v )
    246 : Expr( loc ), var( v ) {
    247         assert( var );
    248         assert( var->get_type() );
    249         result = shallowCopy( var->get_type() );
    250 }
    251 
    252 bool VariableExpr::get_lvalue() const {
    253         // It isn't always an lvalue, but it is never an rvalue.
    254         return true;
    255 }
    256 
    257 VariableExpr * VariableExpr::functionPointer(
    258                 const CodeLocation & loc, const FunctionDecl * decl ) {
    259         // wrap usually-determined result type in a pointer
    260         VariableExpr * funcExpr = new VariableExpr{ loc, decl };
    261         funcExpr->result = new PointerType{ funcExpr->result };
    262         return funcExpr;
    263 }
    264 
    265265// --- ConstantExpr
    266266
  • src/AST/Expr.hpp

    r4b30e8c rc28ea4e  
    226226
    227227        /// Creates a new dereference expression
    228         static UntypedExpr * createDeref( const CodeLocation & loc, Expr * arg );
     228        static UntypedExpr * createDeref( const CodeLocation & loc, const Expr * arg );
    229229        /// Creates a new assignment expression
    230         static UntypedExpr * createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs );
     230        static UntypedExpr * createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs );
    231231
    232232        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    247247private:
    248248        NameExpr * clone() const override { return new NameExpr{ *this }; }
     249        MUTATE_FRIEND
     250};
     251
     252/// A reference to a named variable.
     253class VariableExpr final : public Expr {
     254public:
     255        readonly<DeclWithType> var;
     256
     257        VariableExpr( const CodeLocation & loc );
     258        VariableExpr( const CodeLocation & loc, const DeclWithType * v );
     259
     260        bool get_lvalue() const final;
     261
     262        /// generates a function pointer for a given function
     263        static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl );
     264
     265        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     266private:
     267        VariableExpr * clone() const override { return new VariableExpr{ *this }; }
    249268        MUTATE_FRIEND
    250269};
     
    392411};
    393412
    394 /// A reference to a named variable.
    395 class VariableExpr final : public Expr {
    396 public:
    397         readonly<DeclWithType> var;
    398 
    399         VariableExpr( const CodeLocation & loc );
    400         VariableExpr( const CodeLocation & loc, const DeclWithType * v );
    401 
    402         bool get_lvalue() const final;
    403 
    404         /// generates a function pointer for a given function
    405         static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl );
    406 
    407         const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    408 private:
    409         VariableExpr * clone() const override { return new VariableExpr{ *this }; }
    410         MUTATE_FRIEND
    411 };
    412 
    413413/// A compile-time constant.
    414414/// Mostly carries C-source text from parse to code-gen, without interpretation.  E.g. strings keep their outer quotes and never have backslashes interpreted.
     
    422422                const CodeLocation & loc, const Type * ty, const std::string & r,
    423423                        std::optional<unsigned long long> i )
    424         : Expr( loc, ty ), rep( r ), ival( i ) {}
     424        : Expr( loc, ty ), rep( r ), ival( i ), underlyer(ty) {}
    425425
    426426        /// Gets the integer value of this constant, if one is appropriate to its type.
     
    617617
    618618        ImplicitCopyCtorExpr( const CodeLocation& loc, const ApplicationExpr * call )
    619         : Expr( loc, call->result ) { assert( call ); }
     619        : Expr( loc, call->result ), callExpr(call) { assert( call ); assert(call->result); }
    620620
    621621        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    742742        std::vector<ptr<Expr>> dtors;              ///< destructor(s) for return variable(s)
    743743
     744        readonly<ExprStmt> resultExpr;
     745
    744746        StmtExpr( const CodeLocation & loc, const CompoundStmt * ss );
    745747
  • src/AST/Fwd.hpp

    r4b30e8c rc28ea4e  
    137137typedef unsigned int UniqueId;
    138138
     139class TranslationUnit;
     140// TODO: Get from the TranslationUnit:
     141extern Type * sizeType;
     142extern FunctionDecl * dereferenceOperator;
     143extern StructDecl   * dtorStruct;
     144extern FunctionDecl * dtorStructDestroy;
     145
    139146}
  • src/AST/Node.hpp

    r4b30e8c rc28ea4e  
    4949
    5050        bool unique() const { return strong_count == 1; }
     51        bool isManaged() const {return strong_count > 0; }
    5152
    5253private:
  • src/AST/Pass.hpp

    r4b30e8c rc28ea4e  
    103103        /// Construct and run a pass on a translation unit.
    104104        template< typename... Args >
    105         static void run( std::list< ptr<Decl> > & decls, Args &&... args ) {
     105        static void run( TranslationUnit & decls, Args &&... args ) {
    106106                Pass<core_t> visitor( std::forward<Args>( args )... );
    107107                accept_all( decls, visitor );
     
    119119        // Versions of the above for older compilers.
    120120        template< typename... Args >
    121         static void run( std::list< ptr<Decl> > & decls ) {
     121        static void run( TranslationUnit & decls ) {
    122122                Pass<core_t> visitor;
    123123                accept_all( decls, visitor );
     
    228228        template<typename core_type>
    229229        friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor );
     230
     231        bool isInFunction() const {
     232                return inFunction;
     233        }
     234
    230235private:
    231236
     
    235240        const ast::Stmt * call_accept( const ast::Stmt * );
    236241        const ast::Expr * call_accept( const ast::Expr * );
     242
     243        // requests WithStmtsToAdd directly add to this statement, as if it is a compound.
     244
     245        const ast::Stmt * call_accept_as_compound(const ast::Stmt *);
    237246
    238247        template< typename node_t >
     
    257266        template<typename node_t, typename parent_t, typename child_t>
    258267        void maybe_accept(const node_t * &, child_t parent_t::* child);
     268
     269        template<typename node_t, typename parent_t, typename child_t>
     270        void maybe_accept_as_compound(const node_t * &, child_t parent_t::* child);
    259271
    260272private:
     
    284296private:
    285297        bool inFunction = false;
     298        bool atFunctionTop = false;
    286299};
    287300
     
    289302template<typename core_t>
    290303void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor );
     304
     305template<typename core_t>
     306void accept_all( ast::TranslationUnit &, ast::Pass<core_t> & visitor );
    291307
    292308//-------------------------------------------------------------------------------------------------
     
    371387struct WithVisitorRef {
    372388        Pass<core_t> * const visitor = nullptr;
     389
     390        bool isInFunction() const {
     391                return visitor->isInFunction();
     392        }
    373393};
    374394
  • src/AST/Pass.impl.hpp

    r4b30e8c rc28ea4e  
    2020#include <unordered_map>
    2121
     22#include "AST/TranslationUnit.hpp"
    2223#include "AST/TypeSubstitution.hpp"
    2324
     
    167168                __pedantic_pass_assert( stmt );
    168169
     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
    169178                // add a few useful symbols to the scope
    170179                using __pass::empty;
     
    334343        }
    335344
     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);
     364                        new_parent->*child = new_val;
     365                        parent = new_parent;
     366                }
     367        }
     368
    336369
    337370        template< typename core_t >
     
    398431        pass_visitor_stats.depth--;
    399432        if ( !errors.isEmpty() ) { throw errors; }
     433}
     434
     435template< typename core_t >
     436inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) {
     437        return ast::accept_all( unit.decls, visitor );
    400438}
    401439
     
    470508                                // foralls are still in function type
    471509                                maybe_accept( node, &FunctionDecl::type );
    472                                 // function body needs to have the same scope as parameters - CompoundStmt will not enter
    473                                 // a new scope if inFunction is true
     510                                // First remember that we are now within a function.
    474511                                ValueGuard< bool > oldInFunction( inFunction );
    475512                                inFunction = true;
     513                                // The function body needs to have the same scope as parameters.
     514                                // A CompoundStmt will not enter a new scope if atFunctionTop is true.
     515                                ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
     516                                atFunctionTop = true;
    476517                                maybe_accept( node, &FunctionDecl::stmts );
    477518                                maybe_accept( node, &FunctionDecl::attributes );
     
    639680const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) {
    640681        VISIT_START( node );
    641         VISIT({
    642                 // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    643                 auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() {
    644                         if ( ! inFunctionCpy ) __pass::symtab::enter(core, 0);
    645                 }, [this, inFunctionCpy = this->inFunction]() {
    646                         if ( ! inFunctionCpy ) __pass::symtab::leave(core, 0);
     682        VISIT(
     683                // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result.
     684                auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() {
     685                        if ( enterScope ) __pass::symtab::enter(core, 0);
     686                }, [this, leaveScope = !this->atFunctionTop]() {
     687                        if ( leaveScope ) __pass::symtab::leave(core, 0);
    647688                });
    648                 ValueGuard< bool > guard2( inFunction );
     689                ValueGuard< bool > guard2( atFunctionTop );
     690                atFunctionTop = false;
    649691                guard_scope guard3 { *this };
    650                 inFunction = false;
    651692                maybe_accept( node, &CompoundStmt::kids );
    652         })
     693        )
    653694        VISIT_END( CompoundStmt, node );
    654695}
     
    703744                maybe_accept( node, &IfStmt::inits    );
    704745                maybe_accept( node, &IfStmt::cond     );
    705                 maybe_accept( node, &IfStmt::thenPart );
    706                 maybe_accept( node, &IfStmt::elsePart );
     746                maybe_accept_as_compound( node, &IfStmt::thenPart );
     747                maybe_accept_as_compound( node, &IfStmt::elsePart );
    707748        })
    708749
     
    721762                maybe_accept( node, &WhileStmt::inits );
    722763                maybe_accept( node, &WhileStmt::cond  );
    723                 maybe_accept( node, &WhileStmt::body  );
     764                maybe_accept_as_compound( node, &WhileStmt::body  );
    724765        })
    725766
     
    736777                // for statements introduce a level of scope (for the initialization)
    737778                guard_symtab guard { *this };
     779                // xxx - old ast does not create WithStmtsToAdd scope for loop inits. should revisit this later.
    738780                maybe_accept( node, &ForStmt::inits );
    739781                maybe_accept( node, &ForStmt::cond  );
    740782                maybe_accept( node, &ForStmt::inc   );
    741                 maybe_accept( node, &ForStmt::body  );
     783                maybe_accept_as_compound( node, &ForStmt::body  );
    742784        })
    743785
     
    834876                maybe_accept( node, &CatchStmt::decl );
    835877                maybe_accept( node, &CatchStmt::cond );
    836                 maybe_accept( node, &CatchStmt::body );
     878                maybe_accept_as_compound( node, &CatchStmt::body );
    837879        })
    838880
  • src/AST/Pass.proto.hpp

    r4b30e8c rc28ea4e  
    2222template<typename core_t>
    2323class Pass;
     24
     25class TranslationUnit;
    2426
    2527struct PureVisitor;
  • src/AST/SymbolTable.cpp

    r4b30e8c rc28ea4e  
    335335}
    336336
    337 /*
    338 void SymbolTable::addFunctionType( const FunctionType * ftype ) {
    339         addTypes( ftype->forall );
    340         addIds( ftype->returns );
    341         addIds( ftype->params );
    342 }
    343 */
     337
     338void SymbolTable::addFunction( const FunctionDecl * func ) {
     339        addTypes( func->type->forall );
     340        addIds( func->returns );
     341        addIds( func->params );
     342}
     343
    344344
    345345void SymbolTable::lazyInitScope() {
  • src/AST/SymbolTable.hpp

    r4b30e8c rc28ea4e  
    145145
    146146        /// convenience function for adding all of the declarations in a function type to the indexer
    147         // void addFunctionType( const FunctionType * ftype );
     147        void addFunction( const FunctionDecl * );
    148148
    149149private:
  • src/AST/Type.cpp

    r4b30e8c rc28ea4e  
    157157
    158158template<typename decl_t>
     159SueInstType<decl_t>::SueInstType(
     160        const base_type * b, std::vector<ptr<Expr>> && params,
     161        CV::Qualifiers q, std::vector<ptr<Attribute>> && as )
     162: BaseInstType( b->name, std::move(params), q, std::move(as) ), base( b ) {}
     163
     164template<typename decl_t>
    159165bool SueInstType<decl_t>::isComplete() const {
    160166        return base ? base->body : false;
  • src/AST/Type.hpp

    r4b30e8c rc28ea4e  
    302302class FunctionType final : public ParameterizedType {
    303303public:
    304 //      std::vector<ptr<DeclWithType>> returns;
    305 //      std::vector<ptr<DeclWithType>> params;
    306 
    307304        std::vector<ptr<Type>> returns;
    308305        std::vector<ptr<Type>> params;
     
    345342        : ParameterizedType(q, std::move(as)), params(), name(n) {}
    346343
     344        BaseInstType(
     345                const std::string& n, std::vector<ptr<Expr>> && params,
     346                CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
     347        : ParameterizedType(q, std::move(as)), params(std::move(params)), name(n) {}
     348
    347349        BaseInstType( const BaseInstType & o );
    348350
     
    369371
    370372        SueInstType(
    371                 const decl_t * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
     373                const base_type * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
     374
     375        SueInstType(
     376                const base_type * b, std::vector<ptr<Expr>> && params,
     377                CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
    372378
    373379        bool isComplete() const override;
  • src/AST/porting.md

    r4b30e8c rc28ea4e  
    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`
    3236
    3337## Structural Changes ##
     
    146150  * allows `newObject` as just default settings
    147151
     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
    148157`NamedTypeDecl`
    149158* `parameters` => `params`
     
    154163`AggregateDecl`
    155164* `parameters` => `params`
     165
     166`StructDecl`
     167* `makeInst` replaced by better constructor on `StructInstType`.
    156168
    157169`Expr`
     
    245257* **TODO** move `kind`, `typeNames` into code generator
    246258
    247 `ReferenceToType`
     259`ReferenceToType` => `BaseInstType`
    248260* deleted `get_baseParameters()` from children
    249261  * replace with `aggr() ? aggr()->params : nullptr`
     
    261273* `returnVals` => `returns`
    262274* `parameters` => `params`
     275  * Both now just point at types.
    263276* `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`
    264281
    265282`TypeInstType`
  • src/Common/PassVisitor.h

    r4b30e8c rc28ea4e  
    354354        virtual TypeSubstitution * mutate( TypeSubstitution * sub ) final;
    355355
     356        bool isInFunction() const {
     357                return inFunction;
     358        }
     359
    356360private:
    357361        bool inFunction = false;
     362        bool atFunctionTop = false;
    358363
    359364        template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor );
     
    526531public:
    527532        PassVisitor<pass_type> * const visitor = nullptr;
     533
     534        bool isInFunction() const {
     535                return visitor->isInFunction();
     536        }
    528537};
    529538
  • src/Common/PassVisitor.impl.h

    r4b30e8c rc28ea4e  
    532532                        indexerAddId( &func );
    533533                        maybeAccept_impl( node->type, *this );
    534                         // function body needs to have the same scope as parameters - CompoundStmt will not enter
    535                         // a new scope if inFunction is true
     534                        // First remember that we are now within a function.
    536535                        ValueGuard< bool > oldInFunction( inFunction );
    537536                        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;
    538541                        maybeAccept_impl( node->statements, *this );
    539542                        maybeAccept_impl( node->attributes, *this );
     
    567570                        indexerAddId( &func );
    568571                        maybeAccept_impl( node->type, *this );
    569                         // function body needs to have the same scope as parameters - CompoundStmt will not enter
    570                         // a new scope if inFunction is true
     572                        // First remember that we are now within a function.
    571573                        ValueGuard< bool > oldInFunction( inFunction );
    572574                        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;
    573579                        maybeAccept_impl( node->statements, *this );
    574580                        maybeAccept_impl( node->attributes, *this );
     
    601607                        indexerAddId( &func );
    602608                        maybeMutate_impl( node->type, *this );
    603                         // function body needs to have the same scope as parameters - CompoundStmt will not enter
    604                         // a new scope if inFunction is true
     609                        // First remember that we are now within a function.
    605610                        ValueGuard< bool > oldInFunction( inFunction );
    606611                        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;
    607616                        maybeMutate_impl( node->statements, *this );
    608617                        maybeMutate_impl( node->attributes, *this );
     
    10071016        VISIT_START( node );
    10081017        {
    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(); } );
     1018                // Do not enter a new scope if atFunctionTop is true, don't leave one either.
     1019                ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
     1020                auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } );
    10121021                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1013                 inFunction = false;
     1022                atFunctionTop = false;
    10141023                visitStatementList( node->kids );
    10151024        }
     
    10211030        VISIT_START( node );
    10221031        {
    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(); } );
     1032                // Do not enter a new scope if atFunctionTop is true, don't leave one either.
     1033                ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
     1034                auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } );
    10261035                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1027                 inFunction = false;
     1036                atFunctionTop = false;
    10281037                visitStatementList( node->kids );
    10291038        }
     
    10351044        MUTATE_START( node );
    10361045        {
    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(); } );
     1046                // Do not enter a new scope if atFunctionTop is true, don't leave one either.
     1047                ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
     1048                auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } );
    10401049                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1041                 inFunction = false;
     1050                atFunctionTop = false;
    10421051                mutateStatementList( node->kids );
    10431052        }
  • src/Common/utility.h

    r4b30e8c rc28ea4e  
    360360        reverse_iterate_t( T & ref ) : ref(ref) {}
    361361
    362         typedef typename T::reverse_iterator iterator;
    363         iterator begin() { return ref.rbegin(); }
    364         iterator end() { return ref.rend(); }
     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(); }
    365366};
    366367
  • src/Concurrency/Keywords.cc

    r4b30e8c rc28ea4e  
    4646        }
    4747
     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
    4856        //=============================================================================================
    4957        // Pass declarations
     
    119127                        "get_thread",
    120128                        "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
    121                         "",
     129                        "ThreadCancelled",
    122130                        true,
    123131                        AggregateDecl::Thread
     
    290298                std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first );
    291299                void validate( DeclarationWithType * );
    292                 void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
    293                 void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<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 );
    294303
    295304                static void implement( std::list< Declaration * > & translationUnit ) {
     
    302311                StructDecl* guard_decl = nullptr;
    303312                StructDecl* dtor_guard_decl = nullptr;
     313                StructDecl* thread_guard_decl = nullptr;
    304314
    305315                static std::unique_ptr< Type > generic_func;
     
    801811                bool first = false;
    802812                std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first );
    803                 bool isDtor = CodeGen::isDestructor( decl->name );
     813                bool const isDtor = CodeGen::isDestructor( decl->name );
    804814
    805815                // Is this function relevant to monitors
     
    849859
    850860                // Instrument the body
    851                 if( isDtor ) {
    852                         addDtorStatments( decl, body, mutexArgs );
     861                if ( isDtor && isThread( mutexArgs.front() ) ) {
     862                        if( !thread_guard_decl ) {
     863                                SemanticError( decl, "thread destructor requires threads to be in scope, add #include <thread.hfa>\n" );
     864                        }
     865                        addThreadDtorStatements( decl, body, mutexArgs );
     866                }
     867                else if ( isDtor ) {
     868                        addDtorStatements( decl, body, mutexArgs );
    853869                }
    854870                else {
    855                         addStatments( decl, body, mutexArgs );
     871                        addStatements( decl, body, mutexArgs );
    856872                }
    857873        }
     
    870886                        assert( !dtor_guard_decl );
    871887                        dtor_guard_decl = decl;
     888                }
     889                else if( decl->name == "thread_dtor_guard_t" && decl->body ) {
     890                        assert( !thread_guard_decl );
     891                        thread_guard_decl = decl;
    872892                }
    873893        }
     
    908928        }
    909929
    910         void MutexKeyword::addDtorStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
     930        void MutexKeyword::addDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
    911931                Type * arg_type = args.front()->get_type()->clone();
    912932                arg_type->set_mutex( false );
     
    957977
    958978                //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
    959                 body->push_front( new DeclStmt( monitors) );
    960         }
    961 
    962         void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
     979                body->push_front( new DeclStmt( monitors ) );
     980        }
     981
     982        void MutexKeyword::addThreadDtorStatements(
     983                        FunctionDecl*, CompoundStmt * body,
     984                        const std::list<DeclarationWithType * > & args ) {
     985                assert( args.size() == 1 );
     986                DeclarationWithType * arg = args.front();
     987                Type * arg_type = arg->get_type()->clone();
     988                assert( arg_type->get_mutex() );
     989                arg_type->set_mutex( false );
     990
     991                // thread_dtor_guard_t __guard = { this, intptr( 0 ) };
     992                body->push_front(
     993                        new DeclStmt( new ObjectDecl(
     994                                "__guard",
     995                                noStorageClasses,
     996                                LinkageSpec::Cforall,
     997                                nullptr,
     998                                new StructInstType(
     999                                        noQualifiers,
     1000                                        thread_guard_decl
     1001                                ),
     1002                                new ListInit(
     1003                                        {
     1004                                                new SingleInit( new CastExpr( new VariableExpr( arg ), arg_type ) ),
     1005                                                new SingleInit( new UntypedExpr(
     1006                                                        new NameExpr( "intptr" ), {
     1007                                                                new ConstantExpr( Constant::from_int( 0 ) ),
     1008                                                        }
     1009                                                ) ),
     1010                                        },
     1011                                        noDesignators,
     1012                                        true
     1013                                )
     1014                        ))
     1015                );
     1016        }
     1017
     1018        void MutexKeyword::addStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
    9631019                ObjectDecl * monitors = new ObjectDecl(
    9641020                        "__monitors",
  • src/GenPoly/GenPoly.cc

    r4b30e8c rc28ea4e  
    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
    4856                /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present
    4957                bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
     
    5664                }
    5765
     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
    5874                /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present
    5975                bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
     
    92108                        Type *newType = env->lookup( typeInst->get_name() );
    93109                        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->name);
     118                        if (newType) return newType;
    94119                }
    95120                return type;
     
    111136        }
    112137
     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
    113153        Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    114154                type = replaceTypeInst( type, env );
     
    126166                }
    127167                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->name) != 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;
    128183        }
    129184
     
    449504        }
    450505
     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
    451514        bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {
    452515                // is parameter is not polymorphic, don't need to box
     
    459522        }
    460523
     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
    461533        bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {
    462534                FunctionType * function = getFunctionType( appExpr->function->result );
     
    467539        }
    468540
     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
    469550        void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {
    470551                tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } );
     552        }
     553
     554        void addToTyVarMap( const ast::TypeDecl * tyVar, TyVarMap & tyVarMap) {
     555                tyVarMap.insert(tyVar->name, convData(ast::TypeDecl::Data{tyVar}));
    471556        }
    472557
     
    478563                if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) {
    479564                        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::ParameterizedType *>(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);
    480577                }
    481578        }
  • src/GenPoly/GenPoly.h

    r4b30e8c rc28ea4e  
    2626
    2727namespace GenPoly {
     28
    2829        typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
    29 
    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);
    3536
    3637        /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
    3738        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);
    3840
    3941        /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided
     
    8486        /// true if arg requires boxing given exprTyVars
    8587        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);
    8689
    8790        /// true if arg requires boxing in the call to appExpr
    8891        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);
    8993
    9094        /// Adds the type variable `tyVar` to `tyVarMap`
     
    9397        /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
    9498        void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
     99        void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap);
    95100
    96101        /// Prints type variable map
  • src/GenPoly/Specialize.cc

    r4b30e8c rc28ea4e  
    218218                thunkFunc->get_attributes().push_back( new Attribute( "unused" ) );
    219219
     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
    220224                // thread thunk parameters into call to actual function, naming thunk parameters as we go
    221225                UniqueName paramNamer( paramPrefix );
  • src/InitTweak/FixGlobalInit.cc

    r4b30e8c rc28ea4e  
    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
    3640namespace InitTweak {
    3741        class GlobalFixer : public WithShortCircuiting {
     
    5054                FunctionDecl * initFunction;
    5155                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;
    5270        };
    5371
     
    91109        }
    92110
     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
    93134        void GlobalFixer::previsit( ObjectDecl *objDecl ) {
    94135                std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids();
     
    112153                        } // if
    113154                        if ( Statement * ctor = ctorInit->ctor ) {
    114                                 // Translation 1: Add this attribute on the global declaration:
    115                                 //    __attribute__((section (".data#")))
    116                                 // which makes gcc put the global in the data section,
    117                                 // so that the global is writeable (via a const cast) in the init function.
    118                                 // The trailing # is an injected assembly comment, to suppress the "a" in
    119                                 //    .section .data,"a"
    120                                 //    .section .data#,"a"
    121                                 // to avoid assembler warning "ignoring changed section attributes for .data"
    122                                 Type *strLitT = new PointerType( Type::Qualifiers( ),
    123                                         new BasicType( Type::Qualifiers( ), BasicType::Char ) );
    124                                 std::list< Expression * > attr_params;
    125                                 attr_params.push_back(
    126                                         new ConstantExpr( Constant( strLitT, "\".data#\"", std::nullopt ) ) );
    127                                 objDecl->attributes.push_back(new Attribute("section", attr_params));
    128                                 // Translation 2: Move the initizliation off the global declaration,
    129                                 // into the startup function.
     155                                addDataSectonAttribute( objDecl );
    130156                                initStatements.push_back( ctor );
    131157                                objDecl->init = nullptr;
     
    142168        }
    143169
     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                                initStmts.push_back( ctor );
     186                                mutDecl->init = nullptr;
     187                                // ctorInit->ctor = nullptr;
     188                        } else if ( const ast::Init * init = ctorInit->init ) {
     189                                mutDecl->init = init;
     190                                // ctorInit->init = nullptr;
     191                        } else {
     192                                // no constructor and no initializer, which is okay
     193                                mutDecl->init = nullptr;
     194                        } // if
     195                        // delete ctorInit;
     196                } // if
     197        }
     198
    144199        // only modify global variables
    145200        void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; }
  • src/InitTweak/FixGlobalInit.h

    r4b30e8c rc28ea4e  
    1919#include <string>  // for string
    2020
     21#include <AST/Fwd.hpp>
     22
     23
    2124class Declaration;
    2225
     
    2629        /// function is for library code.
    2730        void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary );
     31        void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary );
    2832} // namespace
    2933
  • src/InitTweak/FixInit.cc

    r4b30e8c rc28ea4e  
    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 );
     
    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
    804810                                                // originally wanted to take advantage of gcc nested functions, but
    805811                                                // we get memory errors with this approach. To remedy this, the static
  • src/InitTweak/FixInit.h

    r4b30e8c rc28ea4e  
    2020
    2121class Declaration;
     22namespace ast {
     23        class TranslationUnit;
     24}
    2225
    2326namespace InitTweak {
    2427        /// replace constructor initializers with expression statements and unwrap basic C-style initializers
    2528        void fix( std::list< Declaration * > & translationUnit, bool inLibrary );
     29
     30        void fix( ast::TranslationUnit & translationUnit, bool inLibrary);
    2631} // namespace
    2732
  • src/InitTweak/GenInit.cc

    r4b30e8c rc28ea4e  
    283283                assert( stmts.size() <= 1 );
    284284                return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr;
     285
     286        }
     287
     288        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
     289                assertf(objDecl, "genCtorDtor passed null objDecl");
     290                InitExpander_new srcParam(arg);
     291                return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
    285292        }
    286293
  • src/InitTweak/GenInit.h

    r4b30e8c rc28ea4e  
    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);
    3536
    3637        /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
  • src/InitTweak/InitTweak.cc

    r4b30e8c rc28ea4e  
    498498        }
    499499
     500        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
     501                assertf( func, "getParamThis: nullptr ftype" );
     502                auto & params = func->params;
     503                assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str());
     504                return params.front().strict_as<ast::ObjectDecl>();
     505        }
     506
    500507        bool tryConstruct( DeclarationWithType * dwt ) {
    501508                ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );
     
    511518        }
    512519
     520        bool tryConstruct( const ast::DeclWithType * dwt ) {
     521                auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt );
     522                if ( ! objDecl ) return false;
     523                return (objDecl->init == nullptr ||
     524                                ( objDecl->init != nullptr && objDecl->init->maybeConstructed ))
     525                        && ! objDecl->storage.is_extern
     526                        && isConstructable( objDecl->type );
     527        }
     528
     529        bool isConstructable( const ast::Type * type ) {
     530                return ! dynamic_cast< const ast::VarArgsType * >( type ) && ! dynamic_cast< const ast::ReferenceType * >( type )
     531                && ! dynamic_cast< const ast::FunctionType * >( type ) && ! Tuples::isTtype( type );
     532        }
     533
    513534        struct CallFinder_old {
    514535                CallFinder_old( const std::list< std::string > & names ) : names( names ) {}
     
    536557
    537558        struct CallFinder_new final {
    538                 std::vector< ast::ptr< ast::Expr > > matches;
     559                std::vector< const ast::Expr * > matches;
    539560                const std::vector< std::string > names;
    540561
     
    558579        }
    559580
    560         std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt ) {
     581        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
    561582                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
    562583                maybe_accept( stmt, finder );
     
    696717                template <typename Predicate>
    697718                bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
    698                         std::vector< ast::ptr< ast::Expr > > callExprs = collectCtorDtorCalls( stmt );
     719                        std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt );
    699720                        return std::all_of( callExprs.begin(), callExprs.end(), pred );
    700721                }
     
    939960        }
    940961
     962        // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards
     963        // following passes may accidentally resolve this expression if returned as untyped...
     964        ast::Expr * createBitwiseAssignment (const ast::Expr * dst, const ast::Expr * src) {
     965                static ast::ptr<ast::FunctionDecl> assign = nullptr;
     966                if (!assign) {
     967                        auto td = new ast::TypeDecl({}, "T", {}, nullptr, ast::TypeDecl::Dtype, true);
     968                        assign = new ast::FunctionDecl({}, "?=?", {},
     969                        { new ast::ObjectDecl({}, "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))),
     970                          new ast::ObjectDecl({}, "_src", new ast::TypeInstType("T", td))},
     971                        { new ast::ObjectDecl({}, "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic);
     972                }
     973                if (dst->result.as<ast::ReferenceType>()) {
     974                        for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {
     975                                dst = new ast::AddressExpr(dst);
     976                        }
     977                }
     978                else {
     979                        dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {}));
     980                }
     981                if (src->result.as<ast::ReferenceType>()) {
     982                        for (int depth = src->result->referenceDepth(); depth > 0; depth--) {
     983                                src = new ast::AddressExpr(src);
     984                        }
     985                }
     986                return new ast::ApplicationExpr(dst->location, ast::VariableExpr::functionPointer(dst->location, assign), {dst, src});
     987        }
     988
    941989        struct ConstExprChecker : public WithShortCircuiting {
    942990                // most expressions are not const expr
     
    10551103                return isCopyFunction( decl, "?{}" );
    10561104        }
     1105
     1106        void addDataSectonAttribute( ObjectDecl * objDecl ) {
     1107                Type *strLitT = new PointerType( Type::Qualifiers( ),
     1108                        new BasicType( Type::Qualifiers( ), BasicType::Char ) );
     1109                std::list< Expression * > attr_params;
     1110                attr_params.push_back(
     1111                        new ConstantExpr( Constant( strLitT, "\".data#\"", std::nullopt ) ) );
     1112                objDecl->attributes.push_back(new Attribute("section", attr_params));
     1113        }
     1114
    10571115}
  • src/InitTweak/InitTweak.h

    r4b30e8c rc28ea4e  
    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);
    4041
    4142        /// generate a bitwise assignment operation.
    4243        ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );
     44
     45        ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
    4346
    4447        /// transform Initializer into an argument list that can be passed to a call expression
     
    4851        /// True if the resolver should try to construct dwt
    4952        bool tryConstruct( DeclarationWithType * dwt );
     53        bool tryConstruct( const ast::DeclWithType * dwt );
    5054
    5155        /// True if the type can have a user-defined constructor
    5256        bool isConstructable( Type * t );
     57        bool isConstructable( const ast::Type * t );
    5358
    5459        /// True if the Initializer contains designations
     
    7984        /// get all Ctor/Dtor call expressions from a Statement
    8085        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
    81         std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt );
     86        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
    8287
    8388        /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
     
    102107        bool isConstExpr( Expression * expr );
    103108        bool isConstExpr( Initializer * init );
     109
     110        /// Modifies objDecl to have:
     111        ///    __attribute__((section (".data#")))
     112        /// which makes gcc put the declared variable in the data section,
     113        /// which is helpful for global constants on newer gcc versions,
     114        /// so that CFA's generated initialization won't segfault when writing it via a const cast.
     115        /// The trailing # is an injected assembly comment, to suppress the "a" in
     116        ///    .section .data,"a"
     117        ///    .section .data#,"a"
     118        /// to avoid assembler warning "ignoring changed section attributes for .data"
     119        void addDataSectonAttribute( ObjectDecl * objDecl );
    104120
    105121        class InitExpander_old {
  • src/InitTweak/module.mk

    r4b30e8c rc28ea4e  
    2323        InitTweak/GenInit.h \
    2424        InitTweak/InitTweak.cc \
    25         InitTweak/InitTweak.h
     25        InitTweak/InitTweak.h \
     26        InitTweak/FixInitNew.cpp
    2627
    2728SRCDEMANGLE += \
  • src/Parser/ParseNode.h

    r4b30e8c rc28ea4e  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jul  6 09:33:32 2020
    13 // Update Count     : 892
     12// Last Modified On : Sat Oct 24 03:53:54 2020
     13// Update Count     : 895
    1414//
    1515
     
    205205struct TypeData;
    206206
    207 class DeclarationNode : public ParseNode {
    208   public:
     207struct DeclarationNode : public ParseNode {
    209208        // These enumerations must harmonize with their names in DeclarationNode.cc.
    210209        enum BasicType { Void, Bool, Char, Int, Int128,
     
    304303        bool get_inLine() const { return inLine; }
    305304        DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
    306   public:
     305
    307306        DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }
    308307
     
    360359//##############################################################################
    361360
    362 class StatementNode final : public ParseNode {
    363   public:
     361struct StatementNode final : public ParseNode {
    364362        StatementNode() { stmt = nullptr; }
    365363        StatementNode( Statement * stmt ) : stmt( stmt ) {}
     
    382380                os << stmt.get() << std::endl;
    383381        }
    384   private:
     382
    385383        std::unique_ptr<Statement> stmt;
    386384}; // StatementNode
     
    426424Statement * build_finally( StatementNode * stmt );
    427425Statement * build_compound( StatementNode * first );
     426StatementNode * maybe_build_compound( StatementNode * first );
    428427Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
    429428Statement * build_directive( std::string * directive );
  • src/Parser/StatementNode.cc

    r4b30e8c rc28ea4e  
    1010// Created On       : Sat May 16 14:59:41 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug  4 09:39:25 2018
    13 // Update Count     : 363
     12// Last Modified On : Sat Oct 24 04:20:55 2020
     13// Update Count     : 383
    1414//
    1515
     
    345345} // build_compound
    346346
     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.
     351StatementNode * 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
    347362Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    348363        std::list< Expression * > out, in;
  • src/Parser/parser.yy

    r4b30e8c rc28ea4e  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Oct  9 18:09:09 2020
    13 // Update Count     : 4614
     12// Last Modified On : Sat Oct 24 08:21:14 2020
     13// Update Count     : 4624
    1414//
    1515
     
    10801080        IF '(' if_control_expression ')' statement                      %prec THEN
    10811081                // explicitly deal with the shift/reduce conflict on if/else
    1082                 { $$ = new StatementNode( build_if( $3, $5, nullptr ) ); }
     1082                { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), nullptr ) ); }
    10831083        | IF '(' if_control_expression ')' statement ELSE statement
    1084                 { $$ = new StatementNode( build_if( $3, $5, $7 ) ); }
     1084                { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); }
    10851085        ;
    10861086
     
    11301130
    11311131case_clause:                                                                                    // CFA
    1132         case_label_list statement                                       { $$ = $1->append_last_case( new StatementNode( build_compound( $2 ) ) ); }
     1132        case_label_list statement                                       { $$ = $1->append_last_case( maybe_build_compound( $2 ) ); }
    11331133        ;
    11341134
     
    11481148iteration_statement:
    11491149        WHILE '(' push if_control_expression ')' statement pop
    1150                 { $$ = new StatementNode( build_while( $4, $6 ) ); }
     1150                { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); }
    11511151        | WHILE '(' ')' statement                                                       // CFA => while ( 1 )
    1152                 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), $4 ) ); }
     1152                { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
    11531153        | DO statement WHILE '(' comma_expression ')' ';'
    1154                 { $$ = new StatementNode( build_do_while( $5, $2 ) ); }
     1154                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
    11551155        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    1156                 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), $2 ) ); }
     1156                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
    11571157        | FOR '(' push for_control_expression_list ')' statement pop
    1158                 { $$ = new StatementNode( build_for( $4, $6 ) ); }
     1158                { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); }
    11591159        | FOR '(' ')' statement                                                         // CFA => for ( ;; )
    1160                 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), $4 ) ); }
     1160                { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
    11611161        ;
    11621162
     
    13411341waitfor_clause:
    13421342        when_clause_opt waitfor statement                                       %prec THEN
    1343                 { $$ = build_waitfor( $2, $3, $1 ); }
     1343                { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1 ); }
    13441344        | when_clause_opt waitfor statement WOR waitfor_clause
    1345                 { $$ = build_waitfor( $2, $3, $1, $5 ); }
     1345                { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1, $5 ); }
    13461346        | when_clause_opt timeout statement                                     %prec THEN
    1347                 { $$ = build_waitfor_timeout( $2, $3, $1 ); }
     1347                { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1 ); }
    13481348        | when_clause_opt ELSE statement
    1349                 { $$ = build_waitfor_timeout( nullptr, $3, $1 ); }
     1349                { $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); }
    13501350                // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    13511351        | when_clause_opt timeout statement WOR ELSE statement
    13521352                { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    13531353        | when_clause_opt timeout statement WOR when_clause ELSE statement
    1354                 { $$ = build_waitfor_timeout( $2, $3, $1, $7, $5 ); }
     1354                { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1, maybe_build_compound( $7 ), $5 ); }
    13551355        ;
    13561356
  • src/ResolvExpr/Resolver.cc

    r4b30e8c rc28ea4e  
    11051105                }
    11061106
    1107                 /// Establish post-resolver invariants for expressions
     1107               
     1108        } // anonymous namespace
     1109/// Establish post-resolver invariants for expressions
    11081110                void finishExpr(
    11091111                        ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
     
    11181120                        StripCasts_new::strip( expr );
    11191121                }
    1120         } // anonymous namespace
    1121 
    11221122
    11231123        ast::ptr< ast::Expr > resolveInVoidContext(
     
    11391139        }
    11401140
    1141         namespace {
    1142                 /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
     1141        /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
    11431142                /// context.
    11441143                ast::ptr< ast::Expr > findVoidExpression(
     
    11511150                        return newExpr;
    11521151                }
     1152
     1153        namespace {
     1154               
    11531155
    11541156                /// resolve `untyped` to the expression whose candidate satisfies `pred` with the
     
    11621164                        CandidateRef choice =
    11631165                                findUnfinishedKindExpression( untyped, symtab, kind, pred, mode );
    1164                         finishExpr( choice->expr, choice->env, untyped->env );
     1166                        ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
    11651167                        return std::move( choice->expr );
    11661168                }
     
    12721274        // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver");
    12731275
    1274         void resolve( std::list< ast::ptr< ast::Decl > >& translationUnit ) {
     1276        void resolve( ast::TranslationUnit& translationUnit ) {
    12751277                ast::Pass< Resolver_new >::run( translationUnit );
    12761278        }
  • src/ResolvExpr/Resolver.h

    r4b30e8c rc28ea4e  
    3535        class StmtExpr;
    3636        class SymbolTable;
     37        class TranslationUnit;
    3738        class Type;
    3839        class TypeEnvironment;
     
    5556
    5657        /// Checks types and binds syntactic constructs to typed representations
    57         void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit );
     58        void resolve( ast::TranslationUnit& translationUnit );
    5859        /// Searches expr and returns the first DeletedExpr found, otherwise nullptr
    5960        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr );
     
    6667        ast::ptr< ast::Expr > findSingleExpression(
    6768                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);
    6871        /// Resolves a constructor init expression
    69         ast::ptr< ast::Init > resolveCtorInit( 
     72        ast::ptr< ast::Init > resolveCtorInit(
    7073                const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab );
    7174        /// Resolves a statement expression
    72         ast::ptr< ast::Expr > resolveStmtExpr( 
     75        ast::ptr< ast::Expr > resolveStmtExpr(
    7376                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab );
    7477} // namespace ResolvExpr
  • src/SymTab/Autogen.cc

    r4b30e8c rc28ea4e  
    233233        }
    234234
     235        // shallow copy the pointer list for return
     236        std::vector<ast::ptr<ast::TypeDecl>> getGenericParams (const ast::Type * t) {
     237                if (auto structInst = dynamic_cast<const ast::StructInstType*>(t)) {
     238                        return structInst->base->params;
     239                }
     240                if (auto unionInst = dynamic_cast<const ast::UnionInstType*>(t)) {
     241                        return unionInst->base->params;
     242                }
     243                return {};
     244        }
     245
    235246        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
    236247        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
     
    244255                ftype->parameters.push_back( dstParam );
    245256                return ftype;
     257        }
     258
     259        ///
     260        ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic) {
     261                std::vector<ast::ptr<ast::TypeDecl>> typeParams;
     262                if (maybePolymorphic) typeParams = getGenericParams(paramType);
     263                auto dstParam = new ast::ObjectDecl(loc, "_dst", new ast::ReferenceType(paramType), nullptr, {}, ast::Linkage::Cforall);
     264                return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc));
    246265        }
    247266
  • src/SymTab/Autogen.h

    r4b30e8c rc28ea4e  
    5555        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
    5656        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);
    5759
    5860        /// generate the type of a copy constructor for paramType.
  • src/SynTree/Expression.h

    r4b30e8c rc28ea4e  
    163163};
    164164
     165/// VariableExpr represents an expression that simply refers to the value of a named variable.
     166/// Does not take ownership of var.
     167class 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
    165190// The following classes are used to represent expression types that cannot be converted into
    166191// function-call format.
     
    329354};
    330355
    331 /// VariableExpr represents an expression that simply refers to the value of a named variable.
    332 /// Does not take ownership of var.
    333 class VariableExpr : public Expression {
    334   public:
    335         DeclarationWithType * var;
    336 
    337         VariableExpr();
    338         VariableExpr( DeclarationWithType * var );
    339         VariableExpr( const VariableExpr & other );
    340         virtual ~VariableExpr();
    341 
    342         bool get_lvalue() const final;
    343 
    344         DeclarationWithType * get_var() const { return var; }
    345         void set_var( DeclarationWithType * newValue ) { var = newValue; }
    346 
    347         static VariableExpr * functionPointer( FunctionDecl * decl );
    348 
    349         virtual VariableExpr * clone() const override { return new VariableExpr( * this ); }
    350         virtual void accept( Visitor & v ) override { v.visit( this ); }
    351         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    352         virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    353         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    354 };
    355 
    356356/// ConstantExpr represents an expression that simply refers to the value of a constant
    357357class ConstantExpr : public Expression {
  • src/main.cc

    r4b30e8c rc28ea4e  
    343343                        auto transUnit = convert( move( translationUnit ) );
    344344                        PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
     345                        if ( exprp ) {
     346                                translationUnit = convert( move( transUnit ) );
     347                                dump( translationUnit );
     348                                return EXIT_SUCCESS;
     349                        } // if
     350
     351                        PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
    345352                        translationUnit = convert( move( transUnit ) );
    346353                } else {
    347354                        PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
     355                        if ( exprp ) {
     356                                dump( translationUnit );
     357                                return EXIT_SUCCESS;
     358                        }
     359
     360                        PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
    348361                }
    349362
    350                 if ( exprp ) {
    351                         dump( translationUnit );
    352                         return EXIT_SUCCESS;
    353                 } // if
    354 
    355363                // fix ObjectDecl - replaces ConstructorInit nodes
    356                 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
    357364                if ( ctorinitp ) {
    358365                        dump ( translationUnit );
  • tests/.expect/const-init.txt

    r4b30e8c rc28ea4e  
    1 done
     1almost done
     2dtor
  • tests/Makefile.am

    r4b30e8c rc28ea4e  
    5353
    5454# adjust CC to current flags
    55 CC = LC_ALL=C $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
     55CC = LC_ALL=C $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS} ${AST_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS} ${AST_FLAGS})
    5656CFACC = $(CC)
    5757
     
    6060
    6161# adjusted CC but without the actual distcc call
    62 CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
     62CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS} ${AST_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS} ${AST_FLAGS})
    6363CFACCLINK = $(CFACCLOCAL) -quiet $(if $(test), 2> $(test), ) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g'))
    6464
  • tests/alloc.cfa

    r4b30e8c rc28ea4e  
    342342        for ( i; dim ) { printf( "%d %g, ", stp1[i].x, stp1[i].y ); }
    343343        printf( "\n" );
    344         adelete( dim, stp, dim, stp1 );
     344        adelete( stp, stp1 );
    345345
    346346        // extras
  • tests/complex.cfa

    r4b30e8c rc28ea4e  
    1414//
    1515
    16 #include <stdio.h>
    1716#include <complex.h>
    1817#ifdef __CFA__
  • tests/config.py.in

    r4b30e8c rc28ea4e  
    99HOSTARCH = "@host_cpu@"
    1010DISTRIBUTE = @HAS_DISTCC@
     11NEWAST = @DEFAULT_NEW_AST@
  • tests/const-init.cfa

    r4b30e8c rc28ea4e  
    1616/*
    1717
    18 This test shows non-crashing of generated code for constants with interesting initizers.
     18These tests show non-crashing of generated code for constants with interesting initializers.
    1919The potential for these to crash is compiler dependent.
    2020
    2121There are two cases:
    22 1. static constants in one compilation unit (tested here)
     221. static constants in one compilation unit (tested here, in a few sub-cases)
    23232. extern constants across compilation units (tested by libcfa being loadable, specifically
    24    the constant declarations in libcfa/src/limits.cfa, which almost every test exercises,
     24   the constant definitions in libcfa/src/limits.cfa, which almost every test exercises,
    2525   including "hello;" but notably, the "limits" test does not exercise it because that test
    2626   is compile-only)
     
    3737GCC-10 on Ubuntu 20.04    Has crashed      Has crashed
    3838
    39 For this test case to fail, with most other tests passing, would be a situation only ever
     39For this test to fail, with most other tests passing, would be a situation only ever
    4040observed with GCC-8.
    4141
    4242*/
    4343
     44// initailized by generated function, called before main
    4445static const char foo = -1;
    4546
     47struct thing{};
     48void ^?{}( thing & ) { printf("dtor\n"); }
     49
    4650int main() {
    47     printf("done\n");
     51    // foo is already initialized
     52
     53    // no dtor => stays a (static) local, initialized here
     54    static const char bar = -1;
     55
     56    // has dtor => becomes a global, ctor called here, dtor called at exit
     57    static const thing it;
     58
     59    printf("almost done\n");
    4860}
  • tests/exceptions/cancel/coroutine.cfa

    r4b30e8c rc28ea4e  
    11// Try cancelling a coroutine.
    22
    3 #include <stdio.h>
    43#include <coroutine.hfa>
    54#include <exception.hfa>
  • tests/exceptions/conditional.cfa

    r4b30e8c rc28ea4e  
    55
    66#include <exception.hfa>
    7 #include <stdio.h>
    87
    98VTABLE_DECLARATION(num_error)(
  • tests/exceptions/except-io.hfa

    r4b30e8c rc28ea4e  
    11// Common tools for the exception tests.
    2 
    3 #include <stdio.h>
    42
    53// Echo when a destructor is run and an area/block is left.
  • tests/exceptions/trash.cfa

    r4b30e8c rc28ea4e  
    22
    33#include <exception.hfa>
    4 #include <stdio.h>
    54
    65TRIVIAL_EXCEPTION(yin);
  • tests/global-monomorph.cfa

    r4b30e8c rc28ea4e  
    1 // Crea
    2 
    3 #include <stdlib.hfa>
    4 #include <stdio.h>
     1// Create monomorphic instances of polymorphic types at global scope.
    52
    63forall(dtype T)
  • tests/poly-d-cycle.cfa

    r4b30e8c rc28ea4e  
    11// Check that a cycle of polymorphic dtype structures can be instancated.
    2 
    3 #include <stdio.h>
    42
    53forall(dtype T)
  • tests/poly-o-cycle.cfa

    r4b30e8c rc28ea4e  
    11// Check that a cycle of polymorphic otype structures can be instancated.
    2 
    3 #include <stdio.h>
    42
    53forall(otype T)
  • tests/pybin/settings.py

    r4b30e8c rc28ea4e  
    8585        def filter(self, tests):
    8686                return [test for test in tests if not test.arch or self.target == test.arch]
    87                 return True if not arch else self.target == arch
    8887
    8988        @staticmethod
     
    9897                self.path   = "debug" if value else "nodebug"
    9998
     99class 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]
     120
    100121class Install:
    101122        def __init__(self, value):
     
    120141
    121142def init( options ):
     143        global all_ast
    122144        global all_arch
    123145        global all_debug
    124146        global all_install
     147        global ast
    125148        global arch
     149        global debug
    126150        global archive
     151        global install
     152
    127153        global continue_
    128         global debug
    129154        global dry_run
    130155        global generating
    131         global install
    132156        global make
    133157        global output_width
     
    135159        global timeout2gdb
    136160
     161        all_ast      = [AST(o)          for o in list(dict.fromkeys(options.ast    ))] if options.ast  else [AST(None)]
    137162        all_arch     = [Architecture(o) for o in list(dict.fromkeys(options.arch   ))] if options.arch else [Architecture(None)]
    138163        all_debug    = [Debug(o)        for o in list(dict.fromkeys(options.debug  ))]
  • tests/pybin/test_run.py

    r4b30e8c rc28ea4e  
    1111                self.path = ''
    1212                self.arch = ''
     13                self.astv = ''
    1314
    1415        def toString(self):
    15                 return "{:25s} ({:5s} {:s})".format( self.name, self.arch if self.arch else "Any", self.target() )
     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() )
    1617
    1718        def prepare(self):
     
    2021
    2122        def expect(self):
    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)) )
     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)) )
    2326
    2427        def error_log(self):
     
    4548
    4649        @staticmethod
    47         def new_target(target, arch):
     50        def new_target(target, arch, astv):
    4851                test = Test()
    4952                test.name = os.path.basename(target)
    5053                test.path = os.path.relpath (os.path.dirname(target), settings.SRCDIR)
    5154                test.arch = arch.target if arch else ''
     55                test.astv = astv.target if astv else ''
    5256                return test
    5357
  • tests/pybin/tools.py

    r4b30e8c rc28ea4e  
    181181                '-s' if silent else None,
    182182                test_param,
     183                settings.ast.flags,
    183184                settings.arch.flags,
    184185                settings.debug.flags,
  • tests/test.py

    r4b30e8c rc28ea4e  
    2424
    2525        def match_test(path):
    26                 match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path)
     26                match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.nast|\.oast)?(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path)
    2727                if match :
    2828                        test = Test()
    2929                        test.name = match.group(2)
    3030                        test.path = match.group(1)
    31                         test.arch = match.group(3)[1:] if match.group(3) else None
     31                        test.arch = match.group(4)[1:] if match.group(4) else None
     32
     33