Changes in / [c28ea4e:4b30e8cc]


Ignore:
Files:
4 added
25 deleted
101 edited

Legend:

Unmodified
Added
Removed
  • Jenkins/FullBuild

    rc28ea4e r4b30e8cc  
    1717
    1818                                parallel (
    19                                         gcc_8_x86: { trigger_build( 'gcc-8',   'x86' ) },
    20                                         gcc_7_x86: { trigger_build( 'gcc-7',   'x86' ) },
     19                                        clang_x86: { trigger_build( 'gcc-8',   'x86' ) },
     20                                        gcc_5_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

    rc28ea4e r4b30e8cc  
    127127                        }
    128128
    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}"
     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}"
    132130
    133131                        // Configure libcfa
     
    361359        public final CC_Desc Compiler
    362360        public final Arch_Desc Architecture
    363         public final Boolean NewAST
    364361        public final Boolean RunAllTests
    365362        public final Boolean RunBenchmark
     
    413410
    414411                this.IsSandbox          = (branch == "jenkins-sandbox")
    415                 this.NewAST             = param.NewAST
    416412                this.RunAllTests        = param.RunAllTests
    417413                this.RunBenchmark       = param.RunBenchmark
     
    474470                                ],                                                                                              \
    475471                                [$class: 'BooleanParameterDefinition',                                                  \
    476                                         description: 'If true, build compiler using new AST',           \
    477                                         name: 'NewAST',                                                                         \
    478                                         defaultValue: false,                                                            \
    479                                 ],                                                                                              \
    480                                 [$class: 'BooleanParameterDefinition',                                                  \
    481472                                        description: 'If false, only the quick test suite is ran',              \
    482473                                        name: 'RunAllTests',                                                            \
    483474                                        defaultValue: false,                                                            \
    484                                 ],
     475                                ],                                                                                              \
    485476                                [$class: 'BooleanParameterDefinition',                                                  \
    486477                                        description: 'If true, jenkins also runs benchmarks',           \
  • configure.ac

    rc28ea4e r4b30e8cc  
    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])
    30 DEFAULT_NEW_AST="False"
    3130AC_ARG_ENABLE(new-ast,
    3231        [  --enable-new-ast     whether or not to use new ast as the default AST algorithm],
    3332        [case "${enableval}" in
    34                 yes) newast=true ; DEFAULT_NEW_AST="True"  ;;
    35                 no)  newast=false; DEFAULT_NEW_AST="False" ;;
     33                yes) newast=true ;;
     34                no)  newast=false ;;
    3635                *) AC_MSG_ERROR([bad value ${enableval} for --enable-new-ast]) ;;
    3736        esac],[newast=false])
    3837AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast)
    39 AC_SUBST(DEFAULT_NEW_AST)
    4038
    4139#==============================================================================
  • doc/papers/concurrency/mail2

    rc28ea4e r4b30e8cc  
    1 
    21Date: Wed, 26 Jun 2019 20:12:38 +0000
    32From: Aaron Thomas <onbehalfof@manuscriptcentral.com>
     
    10751074Software: Practice and Experience Editorial Office
    10761075
    1077 
    1078 
    1079 Date: Thu, 15 Oct 2020 13:48:52 +0000
    1080 From: Richard Jones <onbehalfof@manuscriptcentral.com>
    1081 Reply-To: R.E.Jones@kent.ac.uk
    1082 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
    1083 Subject: Software: Practice and Experience - Decision on Manuscript ID
    1084  SPE-19-0219.R3
    1085 
    1086 15-Oct-2020
    1087 
    1088 Dear Dr Buhr,
    1089 
    1090 It is a pleasure to accept your manuscript entitled "Advanced Control-flow and Concurrency in Cforall" in its current form for publication in Software: Practice and Experience. 
    1091 
    1092 Please note although the manuscript is accepted the files will now be checked to ensure that everything is ready for publication, and you may be contacted if final versions of files for publication are required.
    1093 
    1094 Your article cannot be published until the publisher has received the appropriate signed license agreement. Within the next few days the corresponding author will receive an email from Wiley's Author Services system which will ask them to log in and will present them with the appropriate license for completion.
    1095 
    1096 Thank you for your fine contribution.
    1097 
    1098 Sincerely,
    1099 Richard
    1100 
    1101 Prof. Richard Jones
    1102 Editor, Software: Practice and Experience
    1103 R.E.Jones@kent.ac.uk
    1104 
    1105 P.S. - You can help your research get the attention it deserves! Check out Wiley's free Promotion Guide for best-practice recommendations for promoting your work at www.wileyauthors.com/eeo/guide. And learn more about Wiley Editing Services which offers professional video, design, and writing services to create shareable video abstracts, infographics, conference posters, lay summaries, and research news stories for your research at www.wileyauthors.com/eeo/promotion.
    1106 
    1107 This journal accepts artwork submissions for Cover Images. This is an optional service you can use to help increase article exposure and showcase your research. For more information, including artwork guidelines, pricing, and submission details, please visit the Journal Cover Image page at www.wileyauthors.com/eeo/covers. If you want help creating an image, Wiley Editing Services offers a professional cover image design service that creates eye-catching images, ready to be showcased on the journal cover at www.wileyauthors.com/eeo/design.
    1108 
    1109 
    1110 
    1111 Date: Fri, 16 Oct 2020 12:44:42 +0000
    1112 From: Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com>
    1113 Reply-To: speoffice@wiley.com
    1114 To: pabuhr@uwaterloo.ca
    1115 Subject: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c]
    1116 
    1117 16-Oct-2020
    1118 
    1119 Dear Dr. Buhr,
    1120 
    1121 Manuscript id: SPE-19-0219.R3
    1122 Manuscript title: Advanced Control-flow and Concurrency in Cforall
    1123 
    1124 Although your manuscript has been accepted for publication it is now being returned to your author center for you to review and make any final adjustments or corrections prior to production and publication.
    1125 
    1126 Any special instructions will be listed below:
    1127 1) Funding Information added in ScholorOne but missing in main document, Kindly add the Funding information in main document.
    1128 2) Please provide the clean version of the manuscript without any highlights or tracked changes.
    1129 3) Kindly check and make sure citations for all figures and Tables are present in the main document
    1130 
    1131 Please now log back into your Scholar One Author Center and click on the "Manuscripts Accepted for First Look" queue. In order to update the submission, click on the "submit updated manuscript" link in the "Actions" column and follow the steps as you would during a manuscript submission process.
    1132 
    1133 On the File Upload screen please upload the FINAL versions of all the files, including print quality image files. For information about image quality requirements, please refer to the guidelines at https://authorservices.wiley.com/asset/photos/electronic_artwork_guidelines.pdf.
    1134 
    1135 Instructions for uploading replacement files:
    1136 1. On the "File Upload" step, click on the "edit" button for the file you wish to replace.
    1137 2. In the "Upload a later version" section, browse to locate the replacement final version.
    1138 3. Add any comments concerning the replacement (e.g. "high res image").
    1139 4. Select whether the new file is a minor or major version (we suggest you select minor version)
    1140 5. Click upload.
    1141 6. Click 'Submit' when all the files have been uploaded and you will receive an automated email to say that submission is successful.
    1142 
    1143 Please submit your updates within the next 7 days to ensure there are no unnecessary delays in production.
    1144 
    1145 Sincerely,
    1146 Software: Practice and Experience Editorial Office
    1147 
    1148 
    1149 
    1150 From: SPE Office <speoffice@wiley.com>
    1151 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
    1152 Subject: Re: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c]
    1153 Date: Mon, 19 Oct 2020 17:04:24 +0000
    1154 
    1155 Dear Dr. Buhr,
    1156 
    1157 Thank you very much for contacting the Editorial Office.
    1158 
    1159 I would like to let you know that the files has been found in order and moved to production.
    1160 
    1161 Plesae let me know for further assistance in this regard.
    1162 
    1163 Best Regards
    1164 
    1165 Mayank Roy Chowdhury
    1166 Editorial Assistant
    1167 Software practice and Experience
    1168 ________________________________
    1169 From: Peter A. Buhr <pabuhr@uwaterloo.ca>
    1170 Sent: Sunday, October 18, 2020 2:00 PM
    1171 To: SPE Office <speoffice@wiley.com>
    1172 Cc: Thierry Delisle <tdelisle@uwaterloo.ca>
    1173 Subject: 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 
    1187 There was no "edit" button on the "File Upload" page, so I just upload the
    1188 final version of the PDF and source files using the mechanism on the "File
    1189 Upload" page and submitted that.
    1190 
    1191 
    1192 
    1193 Date: Tue, 20 Oct 2020 13:28:37 +0530
    1194 To: "Dr. Peter Buhr" <pabuhr@uwaterloo.ca>
    1195 From: jpcms@spi-global.com
    1196 Subject: Information: Production Editor Contact Software:Practice and Experience  | Advanced Control-flow and Concurrency in C A
    1197 
    1198 Dear Dr. Peter Buhr,
    1199 
    1200 We are in the process of preparing "Advanced Control-flow and Concurrency in C A" for publication. Your production editor, Joel Pacaanas, will support you and your article throughout the process.
    1201 
    1202 Please get in touch with your Production Editor at SPEproofs@wiley.com;EllaMae.Navor@spi-global.com if you have any questions.
    1203                
    1204 Sincerely,
    1205 Booking-in Team,
    1206 On behalf of Wiley
    1207 
    1208 Article ID: SPE_2925
    1209 Article DOI: 10.1002/SPE.2925
    1210 
    1211 
    1212 
    1213 Date: Tue, 20 Oct 2020 10:33:04 +0000
    1214 From: <cs-author@wiley.com>
    1215 To: <pabuhr@uwaterloo.ca>
    1216 Subject: In Production: Your article accepted in Software: Practice and Experience
    1217 
    1218 Dear Peter Buhr,
    1219 
    1220 Article ID: SPE2925
    1221 Article DOI: 10.1002/spe.2925
    1222 Internal Article ID: 16922213
    1223 Article: Advanced Control-flow and Concurrency in C A
    1224 Journal: Software: Practice and Experience
    1225 
    1226 Congratulations on the acceptance of your article for publication in Software: Practice and Experience.
    1227 
    1228 Your article has been received and the production process is now underway. We look forward to working with you and publishing your article. Using Wiley Author Services, you can track your article's progress.
    1229 
    1230 Please click below to login - if you are using a different email address than this one, you will need to manually assign this article to your Dashboard (see https://hub.wiley.com/docs/support/assigning-a-missing-article-to-my-dashboard-DOC-11871?utm_source=new%20user%20invitation&utm_medium=email How do I assign a missing article to My Dashboard?):
    1231 
    1232 https://authorservices.wiley.com/index.html#login?campaign=email_invitation-new
    1233 
    1234 If applicable, a list of available actions will appear below - check out your Author Services Dashboard for all actions related to your articles.
    1235 
    1236 Sign your license agreement (REQUIRED)  -- you will receive an email when this task is ready on your dashboard. Track your article's progress to publicationAccess your published articleInvite colleagues to view your published article
    1237 If you need any assistance, please click http://www.wileyauthors.com/help?utm_source=new%20user%20invitation&utm_medium=email here to view our Help section.
    1238 
    1239 Sincerely,
    1240 Wiley Author Services
    1241 
    1242 P.S. - Some journals accept artwork submissions for Cover Images. This is an optional service you can use to help increase article exposure and showcase your research. Pricing and placement options vary by journal. For more information, including artwork guidelines, pricing, and submission details, please visit the https://authorservices.wiley.com/author-resources/Journal-Authors/Promotion/journal-cover-image.html?utm_source=as&utm_medium=email&utm_term=invitation_msg&utm_content=covers&utm_campaign=2019feb?campaign=email_invitation-new" target=_blank">Journal Cover Image page. If you want help creating an image, Wiley Editing Services offers a professional https://wileyeditingservices.com/en/article-promotion/cover-image-design.html?utm_source=as&utm_medium=email&utm_term=ie&utm_content=cid&utm_campaign=prodops" target=_blank">Cover Image Design service that creates eye-catching images, ready to be showcased on the journal cover.
    1243 
    1244 
    1245 
    1246 Date: Thu, 22 Oct 2020 20:21:49 +0000
    1247 From: <cs-author@wiley.com>
    1248 To: <pabuhr@uwaterloo.ca>
    1249 Subject: You have actions to complete in Author Services
    1250 
    1251 Dear Peter Buhr,
    1252 
    1253 Article ID: SPE2925
    1254 Article DOI: 10.1002/spe.2925
    1255 Internal Article ID: 16922213
    1256 Article: Advanced Control-flow and Concurrency in C A
    1257 Journal: Software: Practice and Experience
    1258 
    1259 For the above article, you have the following open tasks:
    1260 
    1261 Sign your license agreement in order to publish your article. Simply click the Sign License button on your https://authorservices.wiley.com?campaign=email_license-notice1">Wiley Author Services Dashboard.
    1262 
    1263 Need any help? Please visit our https://authorsupport.wiley.com/s/">Author Support Center.
    1264 
    1265 Sincerely,
    1266 Wiley Author Services
    1267 
    1268 
    1269 
    1270 Date: Thu, 22 Oct 2020 23:13:07 +0000
    1271 From: <cs-author@wiley.com>
    1272 To: <pabuhr@uwaterloo.ca>
    1273 Subject: License was successfully submitted! Thank you!
    1274 
    1275 Dear Peter Buhr,                                                                 
    1276 
    1277 Article ID: SPE2925
    1278 Article DOI: 10.1002/spe.2925
    1279 Internal Article ID: 16922213
    1280 Article: Advanced Control-flow and Concurrency in C A 
    1281 Journal: Software: Practice and Experience                                                                     
    1282                                                                          
    1283 You've successfully completed license signing for your article - thank you! You can view your signed agreement at any time by visiting your https://authorservices.wiley.com?campaign=email_license-confirm">Wiley Author Services Dashboard.                                                                     
    1284 
    1285 Sincerely,                                                                                 
    1286 
    1287 Wiley Author Services
  • doc/proposals/vtable.md

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

    rc28ea4e r4b30e8cc  
    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 }
    157
    168\pagestyle{empty}
     
    2315        \vspace*{1.0cm}
    2416
    25         {\Huge\bf \eprint{title}}
    26 
    27         \vspace*{1.0cm}
    28 
     17        \Huge
     18        {\bf University of Waterloo E-Thesis Template for \LaTeX }
     19
     20        \vspace*{1.0cm}
     21
     22        \normalsize
    2923        by \\
    3024
    3125        \vspace*{1.0cm}
    3226
    33         {\Large \eprint{author}} \\
     27        \Large
     28        Pat Neugraad \\
    3429
    3530        \vspace*{3.0cm}
    3631
     32        \normalsize
    3733        A thesis \\
    3834        presented to the University of Waterloo \\
    3935        in fulfillment of the \\
    4036        thesis requirement for the degree of \\
    41         \eprint{degree} \\
     37        Doctor of Philosophy \\
    4238        in \\
    43         \eprint{program} \\
     39        Zoology \\
    4440
    4541        \vspace*{2.0cm}
     
    4945        \vspace*{1.0cm}
    5046
    51         \copyright{} \eprint{author} 2017 \\
     47        \copyright\ Pat Neugraad 2017 \\
    5248        \end{center}
    5349\end{titlepage}
  • doc/theses/andrew_beach_MMath/uw-ethesis.cls

    rc28ea4e r4b30e8cc  
    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 %
    2621%   \ifformat{<format>}{<true>}{<false>}
    2722%     If the document's format is <format> than expands to <true> otherwise
     
    3227%     initial setup depends on the document format but they can be overriden
    3328%     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
    4729\NeedsTeXFormat{LaTeX2e}
    48 \ProvidesClass{uw-ethesis}[2020/10/25 v0.2 UW-eThesis Template Document Class]
     30\ProvidesClass{uw-ethesis}[2020/03/24 v0.1 UW-eThesis Template Document Class]
    4931
    5032\RequirePackage{etoolbox}
    51 \RequirePackage{xkeyval}
    5233
    5334% Requested Format:
    54 \newrobustcmd*{\ethesis@@format}{digital}
    55 \DeclareOption{print}{\renewrobustcmd*{\ethesis@@format}{print}}
    56 \DeclareOption{digital}{\renewrobustcmd*{\ethesis@@format}{digital}}
     35\newrobustcmd*{\ethesis@format}{digital}
     36\DeclareOption{print}{\renewrobustcmd*{\ethesis@format}{print}}
     37\DeclareOption{digital}{\renewrobustcmd*{\ethesis@format}{digital}}
    5738
    5839\ProcessOptions\relax
     
    10081% a recto page. This will often require an empty verso (left-hand side) page
    10182% that should not have the page number printed on it.
    102 \let\ethesis@origdoublepage\cleardoublepage
     83\let\origdoublepage\cleardoublepage
    10384\newcommand{\clearemptydoublepage}{%
    104   \clearpage{\pagestyle{empty}\ethesis@origdoublepage}}
     85  \clearpage{\pagestyle{empty}\origdoublepage}}
    10586\let\cleardoublepage\clearemptydoublepage
    10687
     
    10889\renewcommand*{\bibname}{References}
    10990
    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}}
     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}}
    13096
    13197% Includes the hyperref package loading a number of defaults.
     
    140106    pdfstartview={FitH},    % Fits the width of the page to the window.
    141107  }
    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}}}{}
     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}}}{}
    146112  \ifformat{print}{
    147113    \hypersetup{
  • doc/theses/thierry_delisle_PhD/comp_II/presentation.tex

    rc28ea4e r4b30e8cc  
    3636        \miniframeson
    3737}
    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 %------------------------------
     38\section{\CFA and Concurrency}
    4539\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}
    5640
    5741\end{frame}
     
    120104\begin{frame}{Priority Scheduling}
    121105        \begin{center}
    122                 {\large
     106        {\large
    123107                        Runs all ready threads in group \textit{A} before any ready threads in group \textit{B}.
    124108                }
     
    152136
    153137        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.
    181138\end{frame}
    182139%==============================
     
    233190        \begin{itemize}
    234191                \item Acquire for reading for normal scheduling operations.
    235                 \item Acquire for writing when resizing the array and creating/deleting internal queues.
     192                \item Acquire for right when resizing the array and creating/deleting internal queues.
    236193        \end{itemize}
    237194\end{frame}
     
    357314        Runtime system and scheduling are still open topics.
    358315        \newline
    359         \newline
    360316
    361317        This work offers a novel runtime and scheduling package.
    362         \newline
    363318        \newline
    364319
     
    381336
    382337%------------------------------
    383 \begin{frame}{}
     338\begin{frame}{Timeline}
    384339        \begin{center}
    385340                {\large Questions?}
  • doc/theses/thierry_delisle_PhD/comp_II/presentationstyle.sty

    rc28ea4e r4b30e8cc  
    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}
    2322
    2423%==============================
     
    3736\setbeamercolor{palette primary}{bg=colbg}
    3837\setbeamercolor{palette tertiary}{fg=red}
    39 \setbeamercolor{section in toc}{fg=white}
    40 \setbeamercolor{subsection in toc}{fg=gray}
    4138
    4239%==============================
  • doc/theses/thierry_delisle_PhD/thesis/Makefile

    rc28ea4e r4b30e8cc  
    1515        front \
    1616        intro \
    17         existing \
    1817        runtime \
    1918        core \
     
    2827        base \
    2928        empty \
    30         system \
    3129}
    3230
     
    3937## Define the documents that need to be made.
    4038all: thesis.pdf
    41 thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} glossary.tex local.bib
     39thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} glossary.tex
    4240
    4341DOCUMENT = thesis.pdf
  • doc/theses/thierry_delisle_PhD/thesis/fig/system.fig

    rc28ea4e r4b30e8cc  
    1 #FIG 3.2  Produced by xfig version 3.2.7b
     1#FIG 3.2  Produced by xfig version 3.2.5c
    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
     386 3225 4125 4650 4425
     396 4350 4200 4650 4350
     401 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4425 4275 15 15 4425 4275 4440 4290
     411 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4500 4275 15 15 4500 4275 4515 4290
     421 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4575 4275 15 15 4575 4275 4590 4290
     43-6
     441 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3450 4275 225 150 3450 4275 3675 4425
     451 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 4275 225 150 4050 4275 4275 4425
     46-6
     476 6675 4125 7500 4425
     486 7200 4200 7500 4350
     491 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7275 4275 15 15 7275 4275 7290 4290
     501 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7350 4275 15 15 7350 4275 7365 4290
     511 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7425 4275 15 15 7425 4275 7440 4290
     52-6
     531 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6900 4275 225 150 6900 4275 7125 4425
     54-6
    38556 6675 3525 8025 3975
    39562 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
     
    62791 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3975 2850 150 150 3975 2850 4125 2850
    63801 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 7200 2775 150 150 7200 2775 7350 2775
    64 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 4830
     811 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 4860
    65821 3 0 1 0 0 0 0 0 0.000 1 0.0000 7200 2775 30 30 7200 2775 7230 2805
    66831 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3525 3600 150 150 3525 3600 3675 3600
    67 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4625 4838 100 100 4625 4838 4725 4838
     841 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3875 4800 100 100 3875 4800 3975 4800
     851 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 4800 150 75 4650 4800 4800 4875
    68862 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    6987         2400 4200 2400 3750 1950 3750 1950 4200 2400 4200
     
    135153        1 1 1.00 45.00 90.00
    136154         7875 3750 7875 2325 7200 2325 7200 2550
     1552 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
     156         5850 4950 5850 4725 5625 4725 5625 4950 5850 4950
    1371572 2 1 1 -1 -1 0 0 -1 3.000 0 0 0 0 0 5
    138158         6975 4950 6750 4950 6750 4725 6975 4725 6975 4950
    139 2 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    140          5850 4950 5850 4725 5625 4725 5625 4950 5850 4950
    141 4 1 -1 0 0 0 10 0.0000 2 135 900 5550 4425 Processors\001
    142 4 1 -1 0 0 0 10 0.0000 2 165 1170 4200 3975 Ready Threads\001
    143 4 1 -1 0 0 0 10 0.0000 2 165 1440 7350 1725 Other Cluster(s)\001
    144 4 1 -1 0 0 0 10 0.0000 2 135 1080 4650 1725 User Cluster\001
    145 4 1 -1 0 0 0 10 0.0000 2 165 630 2175 3675 Manager\001
    146 4 1 -1 0 0 0 10 0.0000 2 135 1260 2175 3525 Discrete-event\001
    147 4 1 -1 0 0 0 10 0.0000 2 150 900 2175 4350 preemption\001
    148 4 0 -1 0 0 0 10 0.0000 2 135 630 7050 4875 cluster\001
    149 4 1 -1 0 0 0 10 0.0000 2 135 1350 4200 3225 Blocked Threads\001
    150 4 0 -1 0 0 0 10 0.0000 2 135 540 4800 4875 thread\001
    151 4 0 -1 0 0 0 10 0.0000 2 120 810 5925 4875 processor\001
    152 4 0 -1 0 0 0 10 0.0000 2 165 1710 2325 4875 generator/coroutine\001
     1594 1 -1 0 0 0 10 0.0000 2 105 720 5550 4425 Processors\001
     1604 1 -1 0 0 0 10 0.0000 2 120 1005 4200 3225 Blocked Tasks\001
     1614 1 -1 0 0 0 10 0.0000 2 150 870 4200 3975 Ready Tasks\001
     1624 1 -1 0 0 0 10 0.0000 2 135 1095 7350 1725 Other Cluster(s)\001
     1634 1 -1 0 0 0 10 0.0000 2 105 840 4650 1725 User Cluster\001
     1644 1 -1 0 0 0 10 0.0000 2 150 615 2175 3675 Manager\001
     1654 1 -1 0 0 0 10 0.0000 2 105 990 2175 3525 Discrete-event\001
     1664 1 -1 0 0 0 10 0.0000 2 135 795 2175 4350 preemption\001
     1674 0 -1 0 0 0 10 0.0000 2 150 1290 2325 4875 generator/coroutine\001
     1684 0 -1 0 0 0 10 0.0000 2 120 270 4050 4875 task\001
     1694 0 -1 0 0 0 10 0.0000 2 105 450 7050 4875 cluster\001
     1704 0 -1 0 0 0 10 0.0000 2 105 660 5925 4875 processor\001
     1714 0 -1 0 0 0 10 0.0000 2 105 555 4875 4875 monitor\001
  • doc/theses/thierry_delisle_PhD/thesis/glossary.tex

    rc28ea4e r4b30e8cc  
    11\makeglossaries
    22
    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}
     3\longnewglossaryentry{hthrd}
     4{name={hardware thread}}
     5{
     6Threads representing the underlying hardware directly.
    117
    12 % ----------------------------------
    13 % Definitions
     8\textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.}
     9}
    1410
    1511\longnewglossaryentry{thrd}
    16 {name={thread}}
     12{name={threads}}
    1713{
    1814Threads 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.
    1915
    2016\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 % ----------------------------------
    44 
    45 \longnewglossaryentry{hthrd}
    46 {name={hardware thread}}
    47 {
    48 Threads 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.
    49 
    50 \textit{Synonyms : }
    5117}
    5218
     
    9157}
    9258
     59\longnewglossaryentry{proc}
     60{name={virtual processor}}
     61{
    9362
     63}
     64
     65\longnewglossaryentry{Q}
     66{name={work-queue}}
     67{
     68
     69}
    9470
    9571\longnewglossaryentry{at}
     
    155131}
    156132
     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

    rc28ea4e r4b30e8cc  
    11\chapter{Scheduling Core}\label{core}
    22
    3 Before discussing scheduling in general, where it is important to address systems that are changing states, this document discusses scheduling in a somewhat ideal scenerio, where the system has reached a steady state. For this purpose, a steady state is loosely defined as a state where there are always \glspl{thrd} ready to run and but the system has the ressources necessary to accomplish the work. In short, the system is neither overloaded or underloaded.
     3This chapter addresses the need of scheduling on a somewhat ideal scenario
    44
    5 I believe it is important to discuss the steady state first because it is the easiest case to handle and, relatedly, the case in which the best performance is to be expected. As such, when the system is either overloaded or underloaded, a common approach is to try to adapt the system to the new load and return to the steady state. Flaws in the scheduling in the steady state tend therefore to be pervasive in all states.
     5\section{Existing Schedulers}
     6\subsection{Feedback Scheduling}
    67
    7 \section{Design Goals}
    8 As 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.
     8\subsection{Priority Scheduling}\label{priority}
    99
    10 For 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 
    16 Applied 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 
    18 In general, the expectation at the center of this model is that ready \glspl{thrd} do not interfere with eachother but simply share the hardware. This makes it easier to reason about threading because ready \glspl{thrd} can be taken in isolation and the effect of the scheduler can be virtually ignored. This expectation of \gls{thrd} independence means the scheduler is expected to offer 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 
    24 It 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 
    26 Similarly 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}.
     10\subsection{Work Stealing}
    3011
    3112\section{Design}
    32 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}. A strictly \glsxtrshort{fifo} rea
     13While 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}.
    3314
    3415\subsection{Sharding}
     
    3819                \input{base.pstex_t}
    3920        \end{center}
    40         \caption{Relaxed FIFO list}
     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.}
    4123        \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.
    4424\end{figure}
    4525
     
    4828Indeed, if the number of \glspl{thrd} does not far exceed the number of queues, it is probable that several of these queues are empty.
    4929Figure~\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.
     30This 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
     32Solutions 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
    5038
    5139
     
    5442                \input{empty.pstex_t}
    5543        \end{center}
    56         \caption{``More empty'' Relaxed FIFO list}
     44        \caption{``More empty'' state of the queue: the array contains many empty cells.}
    5745        \label{fig:empty}
    58         Emptier state of the queue: the array contains many empty cells, that is strictly FIFO lists containing no elements.
    5946\end{figure}
    60 
    61 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.
    62 
    63 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.
    64 
    65 \paragraph{Dense Information}
  • doc/theses/thierry_delisle_PhD/thesis/text/front.tex

    rc28ea4e r4b30e8cc  
    184184\phantomsection         % allows hyperref to link to the correct page
    185185
    186 % TODOs and missing citations
    187 % -----------------------------
    188186\listofcits
    189187\listoftodos
    190 \cleardoublepage
    191 \phantomsection         % allows hyperref to link to the correct page
    192188
    193189
  • doc/theses/thierry_delisle_PhD/thesis/text/intro.tex

    rc28ea4e r4b30e8cc  
    1 \chapter*{Introduction}\label{intro}
    2 \todo{A proper intro}
    3 
    4 The C programming language\cit{C}
    5 
    6 The \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.
    7 While 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 
    9 This 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.
     1\chapter{Introduction}
  • doc/theses/thierry_delisle_PhD/thesis/text/io.tex

    rc28ea4e r4b30e8cc  
    1 \chapter{User Level \glsxtrshort{io}}
    2 As 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.
     1\chapter{I/O}
    32
    43\section{Existing options}
    5 Since \glsxtrshort{io} operations are generally handled by the
    64
    75\subsection{\texttt{epoll}, \texttt{poll} and \texttt{select}}
     
    97\subsection{Linux's AIO}
    108
     9\subsection{\texttt{io\_uring}}
    1110
    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 
    26 Interestingly, in this e-mail answer, Linus goes on to describe
    27 ``a true \textit{asynchronous system call} interface''
    28 that does
    29 ``[an] arbitrary system call X with arguments A, B, C, D asynchronously using a kernel thread''
    30 in
    31 ``some kind of arbitrary \textit{queue up asynchronous system call} model''.
    32 This description is actually quite close to the interface of the interface described in the next section.
    33 
    34 \subsection{\texttt{io\_uring}}
    35 A 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.
    36 
    37 \subsection{Extra Kernel Threads}\label{io:morethreads}
    38 Finally, 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}.
     11\subsection{Extra Kernel Threads}
    3912
    4013\subsection{Discussion}
  • doc/theses/thierry_delisle_PhD/thesis/text/practice.tex

    rc28ea4e r4b30e8cc  
    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 the number of KTHREAD\_place \todo{add kthrd to glossary}, both manually and, to some extent automatically.
     4Indeed the \CFA runtime, supports expanding and shrinking
     5
     6the number of KTHREAD\_place
     7
     8, both manually and, to some extent automatically.
    59This entails that the scheduling algorithm must support these transitions.
    610
  • doc/theses/thierry_delisle_PhD/thesis/text/runtime.tex

    rc28ea4e r4b30e8cc  
    11\chapter{\CFA Runtime}
    2 This chapter offers an overview of the capabilities of the \CFA runtime prior to this work.
    32
    4 Threading 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 
    8 C 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 
    10 By 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.
     3\section{M:N Threading}
    114
    125\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}
    24 The \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}
    27 Prior 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 
    29 Given 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 
    31 One 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.
    326
    337\section{Interoperating with \texttt{C}}
    34 While \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 
    36 Languages 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 
    38 As 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 
    44 Because 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

    rc28ea4e r4b30e8cc  
    121121% installation instructions there.
    122122
    123 \usepackage{csquotes}
    124 \usepackage{indentfirst} % as any self-respecting frenchman would
    125 
    126123% Setting up the page margins...
    127124% uWaterloo thesis requirements specify a minimum of 1 inch (72pt) margin at the
     
    221218% separate documents, they would each start with the \chapter command, i.e,
    222219% do not contain \documentclass or \begin{document} and \end{document} commands.
    223 \part{Introduction}
    224220\input{text/intro.tex}
    225 \input{text/existing.tex}
    226221\input{text/runtime.tex}
    227 \part{Design}
    228222\input{text/core.tex}
    229223\input{text/practice.tex}
    230224\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}
    236225
    237226%----------------------------------------------------------------------
     
    256245\addcontentsline{toc}{chapter}{\textbf{References}}
    257246
    258 \bibliography{local}
     247\bibliography{uw-ethesis}
    259248% Tip 5: You can create multiple .bib files to organize your references.
    260249% Just list them all in the \bibliogaphy command, separated by commas (no spaces).
    261250
    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{*}
     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{*}
    265254
    266255% The \appendix statement indicates the beginning of the appendices.
  • libcfa/prelude/builtins.c

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

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

    rc28ea4e r4b30e8cc  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Oct 23 23:05:24 2020
    13 // Update Count     : 22
     12// Last Modified On : Tue May 26 22:06:09 2020
     13// Update Count     : 21
    1414//
    1515
     
    2424#include <unistd.h>
    2525#include <sys/mman.h>                                                                   // mprotect
     26extern "C" {
     27// use this define to make unwind.h play nice, definitely a hack
     28#define HIDE_EXPORTS
    2629#include <unwind.h>
     30#undef HIDE_EXPORTS
     31}
    2732
    2833#include "kernel_private.hfa"
    29 #include "exception.hfa"
    3034
    3135#define __CFA_INVOKE_PRIVATE__
     
    4549FORALL_DATA_INSTANCE(CoroutineCancelled, (dtype coroutine_t), (coroutine_t))
    4650
     51struct __cfaehm_node {
     52        struct _Unwind_Exception unwind_exception;
     53        struct __cfaehm_node * next;
     54        int handler_index;
     55};
     56
    4757forall(dtype T)
    4858void mark_exception(CoroutineCancelled(T) *) {}
     
    5060forall(dtype T)
    5161void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {
    52         dst->virtual_table = src->virtual_table;
    5362        dst->the_coroutine = src->the_coroutine;
    5463        dst->the_exception = src->the_exception;
     
    6574        verify( desc->cancellation );
    6675        desc->state = Cancelled;
    67         exception_t * except = __cfaehm_cancellation_exception( desc->cancellation );
     76        exception_t * except = (exception_t *)(1 + (__cfaehm_node *)desc->cancellation);
    6877
    6978        // TODO: Remove explitate vtable set once trac#186 is fixed.
     
    8392
    8493// minimum feasible stack size in bytes
    85 static const size_t MinStackSize = 1000;
     94#define MinStackSize 1000
    8695extern size_t __page_size;                              // architecture pagesize HACK, should go in proper runtime singleton
    8796
     
    208217                size = libFloor(create_size - stack_data_size - diff, libAlign());
    209218        } // if
    210         assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %zd bytes for a stack.", size, MinStackSize );
     219        assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", size, MinStackSize );
    211220
    212221        this->storage = (__stack_t *)((intptr_t)storage + size);
  • libcfa/src/concurrency/exception.cfa

    rc28ea4e r4b30e8cc  
    1010// Created On       : Mon Aug 17 10:41:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Oct 28 14:34:00 2020
    13 // Update Count     : 1
     12// Last Modified On : Tue Aug 25 14:41:00 2020
     13// Update Count     : 0
    1414//
    1515
    16 #define __cforall_thread__
     16extern "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}
    1722
     23#include "invoke.h"
    1824#include "exception.hfa"
    19 
    2025#include "coroutine.hfa"
    2126
    2227extern struct $thread * mainThread;
    23 extern "C" {
    24 extern void __cfactx_thrd_leave();
    25 }
    2628
    2729// Common pattern for all the stop functions, wait until the end then act.
     
    5052
    5153STOP_AT_END_FUNCTION(thread_cancelstop,
    52         __cfactx_thrd_leave();
    53         __cabi_abort( "Resumed cancelled thread" );
     54        // TODO: Instead pass information to the joiner.
     55        abort();
    5456)
    5557
     
    8385                stop_param = (void *)0x22;
    8486        } 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

    rc28ea4e r4b30e8cc  
    1616#pragma once
    1717
    18 // This is an internal bridge between the two modes and must be C compatable.
    19 
    20 #include <unwind.h>
    2118#include "bits/defs.hfa"
    2219#include "invoke.h"
    23 #include "exception.h"
    2420
    2521#ifdef __cforall
    2622extern "C" {
     23
     24#define HIDE_EXPORTS
    2725#endif
     26#include "unwind.h"
    2827
    2928struct exception_context_t * this_exception_context(void) OPTIONAL_THREAD;
     
    3332
    3433#ifdef __cforall
     34#undef HIDE_EXPORTS
    3535}
    3636#endif
  • libcfa/src/concurrency/invoke.h

    rc28ea4e r4b30e8cc  
    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
    163159                volatile int ticket;
    164160                enum __Coroutine_State state:8;
  • libcfa/src/concurrency/io/call.cfa.in

    rc28ea4e r4b30e8cc  
    4747        #include "kernel/fwd.hfa"
    4848
    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         ;
     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
    7582
    7683        extern [* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data );
  • libcfa/src/concurrency/io/setup.cfa

    rc28ea4e r4b30e8cc  
    149149                id.full_proc = false;
    150150                id.id = doregister(&id);
    151                 kernelTLS.this_proc_id = &id;
    152151                __cfaabi_dbg_print_safe( "Kernel : IO poller thread starting\n" );
    153152
     
    181180                                        kernelTLS.this_stats = io_ctx->self.curr_cluster->stats;
    182181                                #endif
    183                                 post( io_ctx->sem );
     182                                __post( io_ctx->sem, &id );
    184183                        }
    185184                }
     
    236235                        if( thrd.state == Ready || thrd.preempted != __NO_PREEMPTION ) {
    237236
    238                                 ready_schedule_lock();
     237                                ready_schedule_lock( (struct __processor_id_t *)active_processor() );
    239238
    240239                                        // This is the tricky case
     
    251250                                        // Fixup the thread state
    252251                                        thrd.state = Blocked;
    253                                         thrd.ticket = TICKET_BLOCKED;
     252                                        thrd.ticket = 0;
    254253                                        thrd.preempted = __NO_PREEMPTION;
    255254
    256                                 ready_schedule_unlock();
     255                                ready_schedule_unlock( (struct __processor_id_t *)active_processor() );
    257256
    258257                                // Pretend like the thread was blocked all along
     
    276275                        }
    277276                } else {
    278                         post( this.thrd.sem );
     277                        unpark( &thrd );
    279278                }
    280279
  • libcfa/src/concurrency/kernel.cfa

    rc28ea4e r4b30e8cc  
    108108static $thread * __next_thread_slow(cluster * this);
    109109static void __run_thread(processor * this, $thread * dst);
    110 static void __wake_one(cluster * cltr);
     110static void __wake_one(struct __processor_id_t * id, 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 );
    255254                /* 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
    256255                /* 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
     
    282281                if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) {
    283282                        // The thread was preempted, reschedule it and reset the flag
    284                         __schedule_thread( thrd_dst );
     283                        __schedule_thread( (__processor_id_t*)this, thrd_dst );
    285284                        break RUNNING;
    286285                }
     
    288287                if(unlikely(thrd_dst->state == Halted)) {
    289288                        // The thread has halted, it should never be scheduled/run again
    290                         // finish the thread
    291                         __thread_finish( thrd_dst );
     289                        // We may need to wake someone up here since
     290                        unpark( this->destroyer );
     291                        this->destroyer = 0p;
    292292                        break RUNNING;
    293293                }
     
    299299                int old_ticket = __atomic_fetch_sub(&thrd_dst->ticket, 1, __ATOMIC_SEQ_CST);
    300300                switch(old_ticket) {
    301                         case TICKET_RUNNING:
     301                        case 1:
    302302                                // This is case 1, the regular case, nothing more is needed
    303303                                break RUNNING;
    304                         case TICKET_UNBLOCK:
     304                        case 2:
    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( $thread * thrd ) {
     360void __schedule_thread( struct __processor_id_t * id, $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 );
    365364        /* paranoid */ #if defined( __CFA_WITH_VERIFY__ )
    366365        /* paranoid */  if( thrd->state == Blocked || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION,
     
    375374        if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready;
    376375
    377         ready_schedule_lock();
     376        ready_schedule_lock  ( id );
    378377                push( thrd->curr_cluster, thrd );
    379                 __wake_one(thrd->curr_cluster);
    380         ready_schedule_unlock();
     378                __wake_one(id, thrd->curr_cluster);
     379        ready_schedule_unlock( id );
    381380
    382381        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     
    385384// KERNEL ONLY
    386385static inline $thread * __next_thread(cluster * this) with( *this ) {
    387         /* paranoid */ verify( kernelTLS.this_proc_id );
    388         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    389 
    390         ready_schedule_lock();
     386        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     387
     388        ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
    391389                $thread * thrd = pop( this );
    392         ready_schedule_unlock();
    393 
    394         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    395         /* paranoid */ verify( kernelTLS.this_proc_id );
     390        ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
     391
     392        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    396393        return thrd;
    397394}
     
    399396// KERNEL ONLY
    400397static inline $thread * __next_thread_slow(cluster * this) with( *this ) {
    401         /* paranoid */ verify( kernelTLS.this_proc_id );
    402         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    403 
    404         ready_schedule_lock();
     398        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     399
     400        ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
    405401                $thread * thrd = pop_slow( this );
    406         ready_schedule_unlock();
    407 
    408         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    409         /* paranoid */ verify( kernelTLS.this_proc_id );
     402        ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
     403
     404        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    410405        return thrd;
    411406}
    412407
    413 void 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 );
     408// KERNEL ONLY unpark with out disabling interrupts
     409void __unpark(  struct __processor_id_t * id, $thread * thrd ) {
    421410        int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST);
    422411        switch(old_ticket) {
    423                 case TICKET_RUNNING:
     412                case 1:
    424413                        // Wake won the race, the thread will reschedule/rerun itself
    425414                        break;
    426                 case TICKET_BLOCKED:
     415                case 0:
    427416                        /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION );
    428417                        /* paranoid */ verify( thrd->state == Blocked );
    429418
    430419                        // Wake lost the race,
    431                         __schedule_thread( thrd );
     420                        __schedule_thread( id, thrd );
    432421                        break;
    433422                default:
    434423                        // This makes no sense, something is wrong abort
    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 );
     424                        abort();
     425        }
     426}
     427
     428void 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 );
    441434}
    442435
     
    455448}
    456449
    457 extern "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         }
     450// KERNEL ONLY
     451void __leave_thread() {
     452        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     453        returnToKernel();
     454        abort();
    481455}
    482456
     
    512486//=============================================================================================
    513487// Wake a thread from the front if there are any
    514 static void __wake_one(cluster * this) {
    515         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    516         /* paranoid */ verify( ready_schedule_islocked() );
     488static void __wake_one(struct __processor_id_t * id, cluster * this) {
     489        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     490        /* paranoid */ verify( ready_schedule_islocked( id ) );
    517491
    518492        // Check if there is a sleeping processor
     
    532506        #endif
    533507
    534         /* paranoid */ verify( ready_schedule_islocked() );
     508        /* paranoid */ verify( ready_schedule_islocked( id ) );
    535509        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    536510
     
    735709                this.print_halts = true;
    736710        }
    737 
    738         void print_stats_now( cluster & this, int flags ) {
    739                 __print_stats( this.stats, this.print_stats, true, this.name, (void*)&this );
    740         }
    741711#endif
    742712// Local Variables: //
  • libcfa/src/concurrency/kernel.hfa

    rc28ea4e r4b30e8cc  
    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;
    8185
    8286        // Preemption data
  • libcfa/src/concurrency/kernel/fwd.hfa

    rc28ea4e r4b30e8cc  
    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 __processor_id_t * volatile this_proc_id;
    40                         struct __stats_t        * volatile this_stats;
     37                        struct $thread    * volatile this_thread;
     38                        struct processor  * volatile this_processor;
     39                        struct __stats_t  * volatile this_stats;
    4140
    4241                        struct {
  • libcfa/src/concurrency/kernel/startup.cfa

    rc28ea4e r4b30e8cc  
    122122        NULL,
    123123        NULL,
    124         NULL,
    125124        { 1, false, false },
    126125};
     
    213212        //initialize the global state variables
    214213        kernelTLS.this_processor = mainProcessor;
    215         kernelTLS.this_proc_id   = (__processor_id_t*)mainProcessor;
    216214        kernelTLS.this_thread    = mainThread;
    217215
     
    229227        // Add the main thread to the ready queue
    230228        // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
    231         __schedule_thread(mainThread);
     229        __schedule_thread((__processor_id_t *)mainProcessor, mainThread);
    232230
    233231        // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
     
    326324        processor * proc = (processor *) arg;
    327325        kernelTLS.this_processor = proc;
    328         kernelTLS.this_proc_id   = (__processor_id_t*)proc;
    329326        kernelTLS.this_thread    = 0p;
    330327        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
     
    444441
    445442static void ?{}( $thread & this, current_stack_info_t * info) with( this ) {
    446         ticket = TICKET_RUNNING;
     443        ticket = 1;
    447444        state = Start;
    448445        self_cor{ info };
     
    477474        this.cltr = &_cltr;
    478475        full_proc = true;
     476        destroyer = 0p;
    479477        do_terminate = false;
    480478        preemption_alarm = 0p;
  • libcfa/src/concurrency/kernel_private.hfa

    rc28ea4e r4b30e8cc  
    3333}
    3434
    35 void __schedule_thread( $thread * )
     35void __schedule_thread( struct __processor_id_t *, $thread * )
    3636#if defined(NDEBUG) || (!defined(__CFA_DEBUG__) && !defined(__CFA_VERIFY__))
    37         __attribute__((nonnull (1)))
     37        __attribute__((nonnull (2)))
    3838#endif
    3939;
    4040
    41 //release/wake-up the following resources
    42 void __thread_finish( $thread * thrd );
     41//Block current thread and release/wake-up the following resources
     42void __leave_thread() __attribute__((noreturn));
    4343
    4444//-----------------------------------------------------------------------------
     
    6363)
    6464
    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
     65// KERNEL ONLY unpark with out disabling interrupts
     66void __unpark( struct __processor_id_t *, $thread * thrd );
     67
     68static 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}
    6885
    6986//-----------------------------------------------------------------------------
     
    180197// Reader side : acquire when using the ready queue to schedule but not
    181198//  creating/destroying queues
    182 static 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);
     199static 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);
    187202        /*paranoid*/ verify(iproc < ready);
    188203
     
    206221}
    207222
    208 static 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);
     223static 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);
    213226        /*paranoid*/ verify(iproc < ready);
    214227        /*paranoid*/ verify(data[iproc].lock);
     
    222235
    223236#ifdef __CFA_WITH_VERIFY__
    224         static inline bool ready_schedule_islocked(void) {
    225                 /*paranoid*/ verify( kernelTLS.this_proc_id );
    226                 __processor_id_t * proc = kernelTLS.this_proc_id;
     237        static inline bool ready_schedule_islocked( struct __processor_id_t * proc) {
    227238                return __scheduler_lock->data[proc->id].owned;
    228239        }
  • libcfa/src/concurrency/monitor.cfa

    rc28ea4e r4b30e8cc  
    281281}
    282282
    283 void __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 );
     283extern "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
     329forall( dtype T | is_thread(T) )
     330T & 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        }
    308337}
    309338
  • libcfa/src/concurrency/preemption.cfa

    rc28ea4e r4b30e8cc  
    3838// FwdDeclarations : timeout handlers
    3939static void preempt( processor   * this );
    40 static void timeout( $thread * this );
     40static void timeout( struct __processor_id_t * id, $thread * this );
    4141
    4242// FwdDeclarations : Signal handlers
     
    9191
    9292// Tick one frame of the Discrete Event Simulation for alarms
    93 static void tick_preemption(void) {
     93static void tick_preemption( struct __processor_id_t * id ) {
    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( node->thrd );
     111                        timeout( id, node->thrd );
    112112                }
    113113                else {
    114114                        bool unpark_thd = node->callback(*node);
    115                         if (unpark_thd) timeout( node->thrd );
     115                        if (unpark_thd) timeout( id, node->thrd );
    116116                }
    117117
     
    274274
    275275// reserved for future use
    276 static void timeout( $thread * this ) {
     276static void timeout( struct __processor_id_t * id, $thread * this ) {
    277277        #if !defined( __CFA_NO_STATISTICS__ )
    278278                kernelTLS.this_stats = this->curr_cluster->stats;
    279279        #endif
    280         unpark( this );
     280        __unpark( id, this );
    281281}
    282282
     
    417417        id.full_proc = false;
    418418        id.id = doregister(&id);
    419         kernelTLS.this_proc_id = &id;
    420419
    421420        // Block sigalrms to control when they arrive
     
    463462                        // __cfaabi_dbg_print_safe( "Kernel : Preemption thread tick\n" );
    464463                        lock( event_kernel->lock __cfaabi_dbg_ctx2 );
    465                         tick_preemption();
     464                        tick_preemption( &id );
    466465                        unlock( event_kernel->lock );
    467466                        break;
  • libcfa/src/concurrency/snzi.hfa

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

    rc28ea4e r4b30e8cc  
    1919
    2020#include "kernel_private.hfa"
    21 #include "exception.hfa"
    2221
    2322#define __CFA_INVOKE_PRIVATE__
     
    2928        context{ 0p, 0p };
    3029        self_cor{ name, storage, storageSize };
    31         ticket = TICKET_RUNNING;
     30        ticket = 1;
    3231        state = Start;
    3332        preempted = __NO_PREEMPTION;
     
    5958}
    6059
    61 FORALL_DATA_INSTANCE(ThreadCancelled, (dtype thread_t), (thread_t))
    62 
    63 forall(dtype T)
    64 void 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 
    70 forall(dtype T)
    71 const char * msg(ThreadCancelled(T) *) {
    72         return "ThreadCancelled";
    73 }
    74 
    75 forall(dtype T)
    76 static void default_thread_cancel_handler(ThreadCancelled(T) & ) {
    77         abort( "Unhandled thread cancellation.\n" );
    78 }
    79 
    80 forall(dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)))
    81 void ?{}( 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 
    113 void ^?{}( thread_dtor_guard_t & this ) {
    114         ^(this.mg){};
    115 }
    116 
    11760//-----------------------------------------------------------------------------
    11861// Starting and stopping threads
     
    12770        verify( this_thrd->context.SP );
    12871
    129         __schedule_thread( this_thrd );
     72        __schedule_thread( (__processor_id_t *)kernelTLS.this_processor, this_thrd);
    13073        enable_interrupts( __cfaabi_dbg_ctx );
    13174}
     
    15093}
    15194
    152 //-----------------------------------------------------------------------------
    153 forall(dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))
    154 T & join( T & this ) {
    155         thread_dtor_guard_t guard = { this, defaultResumptionHandler };
    156         return this;
    157 }
    158 
    15995// Local Variables: //
    16096// mode: c //
  • libcfa/src/concurrency/thread.hfa

    rc28ea4e r4b30e8cc  
    2222#include "kernel.hfa"
    2323#include "monitor.hfa"
    24 #include "exception.hfa"
    2524
    2625//-----------------------------------------------------------------------------
    2726// thread trait
    2827trait is_thread(dtype T) {
    29         void ^?{}(T& mutex this);
    30         void main(T& this);
    31         $thread* get_thread(T& this);
     28      void ^?{}(T& mutex this);
     29      void main(T& this);
     30      $thread* get_thread(T& this);
    3231};
    33 
    34 FORALL_DATA_EXCEPTION(ThreadCancelled, (dtype thread_t), (thread_t)) (
    35         thread_t * the_thread;
    36         exception_t * the_exception;
    37 );
    38 
    39 forall(dtype T)
    40 void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src);
    41 
    42 forall(dtype T)
    43 const char * msg(ThreadCancelled(T) *);
    4432
    4533// define that satisfies the trait without using the thread keyword
     
    7765static inline void ?{}($thread & this, const char * const name, struct cluster & cl )                   { this{ name, cl, 0p, 65000 }; }
    7866static inline void ?{}($thread & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; }
    79 
    80 struct thread_dtor_guard_t {
    81         monitor_dtor_guard_t mg;
    82 };
    83 
    84 forall( dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )
    85 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
    86 void ^?{}( thread_dtor_guard_t & this );
    8767
    8868//-----------------------------------------------------------------------------
     
    128108//----------
    129109// join
    130 forall( dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) )
     110forall( dtype T | is_thread(T) )
    131111T & join( T & this );
    132112
  • libcfa/src/exception.c

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

    rc28ea4e r4b30e8cc  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // exception.h -- Internal exception handling definitions.
     7// exception.h -- Builtins for exception handling.
    88//
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:11:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct 27 14:45:00 2020
    13 // Update Count     : 11
     12// Last Modified On : Tue May 19 14:17:00 2020
     13// Update Count     : 10
    1414//
    1515
    1616#pragma once
    1717
    18 // This could be considered several headers. All are internal to the exception
    19 // system but needed to depending on whether they are C/Cforall code and
    20 // whether or not they are part of the builtins.
    2118
    2219#ifdef __cforall
    2320extern "C" {
    2421#endif
    25 
    26 // Included in C code or the built-ins.
    27 #if !defined(__cforall) || defined(__cforall_builtins__)
    2822
    2923struct __cfaehm_base_exception_t;
     
    5347// Function catches termination exceptions.
    5448void __cfaehm_try_terminate(
    55         void (*try_block)(),
    56         void (*catch_block)(int index, exception_t * except),
    57         int (*match_block)(exception_t * except));
     49    void (*try_block)(),
     50    void (*catch_block)(int index, exception_t * except),
     51    int (*match_block)(exception_t * except));
    5852
    5953// Clean-up the exception in catch blocks.
     
    6256// Data structure creates a list of resume handlers.
    6357struct __cfaehm_try_resume_node {
    64         struct __cfaehm_try_resume_node * next;
    65         _Bool (*handler)(exception_t * except);
     58    struct __cfaehm_try_resume_node * next;
     59    _Bool (*handler)(exception_t * except);
    6660};
    6761
    6862// These act as constructor and destructor for the resume node.
    6963void __cfaehm_try_resume_setup(
    70         struct __cfaehm_try_resume_node * node,
    71         _Bool (*handler)(exception_t * except));
     64    struct __cfaehm_try_resume_node * node,
     65    _Bool (*handler)(exception_t * except));
    7266void __cfaehm_try_resume_cleanup(
    73         struct __cfaehm_try_resume_node * node);
     67    struct __cfaehm_try_resume_node * node);
    7468
    7569// Check for a standard way to call fake deconstructors.
    7670struct __cfaehm_cleanup_hook {};
    7771
    78 #endif
    79 
    80 // Included in C code and the library.
    81 #if !defined(__cforall) || !defined(__cforall_builtins__)
    82 struct __cfaehm_node {
    83         struct _Unwind_Exception unwind_exception;
    84         struct __cfaehm_node * next;
    85         int handler_index;
    86 };
    87 
    88 static inline exception_t * __cfaehm_cancellation_exception(
    89                 struct _Unwind_Exception * unwind_exception ) {
    90         return (exception_t *)(1 + (struct __cfaehm_node *)unwind_exception);
    91 }
    92 #endif
    93 
    9472#ifdef __cforall
    9573}
    96 
    97 // Built-ins not visible in C.
    98 #if defined(__cforall_builtins__)
    9974
    10075// Not all the built-ins can be expressed in C. These can't be
     
    149124
    150125#endif
    151 
    152 #endif
  • libcfa/src/stdlib.cfa

    rc28ea4e r4b30e8cc  
    5858
    5959forall( dtype T | sized(T) | { void ^?{}( T & ); } )
    60 void adelete( T arr[] ) {
     60void adelete( size_t dim, T arr[] ) {
    6161        if ( arr ) {                                                                            // ignore null
    62                 size_t dim = malloc_size( arr ) / sizeof( T );
    6362                for ( int i = dim - 1; i >= 0; i -= 1 ) {               // reverse allocation order, must be unsigned
    6463                        ^(arr[i]){};                                                            // run destructor
     
    6968
    7069forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } )
    71 void adelete( T arr[], Params rest ) {
     70void adelete( size_t dim, T arr[], Params rest ) {
    7271        if ( arr ) {                                                                            // ignore null
    73                 size_t dim = malloc_size( arr ) / sizeof( T );
    7472                for ( int i = dim - 1; i >= 0; i -= 1 ) {               // reverse allocation order, must be unsigned
    7573                        ^(arr[i]){};                                                            // run destructor
  • libcfa/src/stdlib.hfa

    rc28ea4e r4b30e8cc  
    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( T arr[] );
    266 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } ) void adelete( T arr[], Params rest );
     265forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );
     266forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } ) void adelete( size_t dim, T arr[], Params rest );
    267267
    268268//---------------------------------------
  • src/AST/Convert.cpp

    rc28ea4e r4b30e8cc  
    2525#include "AST/Init.hpp"
    2626#include "AST/Stmt.hpp"
    27 #include "AST/TranslationUnit.hpp"
    2827#include "AST/TypeSubstitution.hpp"
    2928
     
    4847
    4948//================================================================================================
    50 namespace ast {
     49namespace {
    5150
    5251// This is to preserve the FindSpecialDecls hack. It does not (and perhaps should not)
    5352// 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
    5753ast::Type * sizeType = nullptr;
    5854ast::FunctionDecl * dereferenceOperator = nullptr;
     
    6763        using Cache = std::unordered_map< const ast::Node *, BaseSyntaxNode * >;
    6864        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;
    7465
    7566        template<typename T>
     
    163154        }
    164155
    165         const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final {       
     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 );
    166161                if ( inCache( node ) ) {
    167162                        return nullptr;
    168163                }
    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 
    173164                auto decl = new ObjectDecl(
    174165                        node->name,
     
    177168                        bfwd,
    178169                        type->clone(),
    179                         nullptr, // prevent infinite loop
     170                        init,
    180171                        attr,
    181172                        Type::FuncSpecifiers( node->funcSpec.val )
    182173                );
    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;
     174                return declWithTypePostamble( decl, node );
    192175        }
    193176
     
    222205                decl->statements = get<CompoundStmt>().accept1( node->stmts );
    223206                decl->withExprs = get<Expression>().acceptL( node->withExprs );
    224                 if ( ast::dereferenceOperator == node ) {
     207                if ( dereferenceOperator == node ) {
    225208                        Validate::dereferenceOperator = decl;
    226209                }
    227                 if ( ast::dtorStructDestroy == node ) {
     210                if ( dtorStructDestroy == node ) {
    228211                        Validate::dtorStructDestroy = decl;
    229212                }
     
    284267                );
    285268
    286                 if ( ast::dtorStruct == node ) {
     269                if ( dtorStruct == node ) {
    287270                        Validate::dtorStruct = decl;
    288271                }
     
    337320
    338321        const ast::Stmt * stmtPostamble( Statement * stmt, const ast::Stmt * node ) {
    339                 // force statements in old tree to be unique.
    340                 // cache.emplace( node, stmt );
    341                 readonlyCache.emplace( node, stmt );
     322                cache.emplace( node, stmt );
    342323                stmt->location = node->location;
    343324                stmt->labels = makeLabelL( stmt, node->labels );
     
    356337                if ( inCache( node ) ) return nullptr;
    357338                auto stmt = new ExprStmt( nullptr );
     339                cache.emplace( node, stmt );
    358340                stmt->expr = get<Expression>().accept1( node->expr );
    359341                return stmtPostamble( stmt, node );
     
    10291011                auto stmts = node->stmts;
    10301012                // disable sharing between multiple StmtExprs explicitly.
    1031                 // this should no longer be true.
    1032 
     1013                if (inCache(stmts)) {
     1014                        stmts = ast::deepCopy(stmts.get());
     1015                }
    10331016                auto rslt = new StmtExpr(
    10341017                        get<CompoundStmt>().accept1(stmts)
     
    10371020                rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls);
    10381021                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                 }
    10431022
    10441023                auto expr = visitBaseExpr( node, rslt );
     
    10571036
    10581037                auto expr = visitBaseExpr( node, rslt );
    1059                 this->node = expr->clone();
     1038                this->node = expr;
    10601039                return nullptr;
    10611040        }
     
    11471126                auto type = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind };
    11481127                // I believe this should always be a BasicType.
    1149                 if ( ast::sizeType == node ) {
     1128                if ( sizeType == node ) {
    11501129                        Validate::SizeType = type;
    11511130                }
     
    14051384};
    14061385
    1407 std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit ) {
     1386std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > > && translationUnit ) {
    14081387        ConverterNewToOld c;
    14091388        std::list< Declaration * > decls;
    1410         for(auto d : translationUnit.decls) {
     1389        for(auto d : translationUnit) {
    14111390                decls.emplace_back( c.decl( d ) );
    14121391        }
     
    15501529
    15511530                // function type is now derived from parameter decls instead of storing them
    1552 
    1553                 /*
    15541531                auto ftype = new ast::FunctionType((ast::ArgumentFlag)old->type->isVarArgs, cv(old->type));
    15551532                ftype->params.reserve(paramVars.size());
     
    15631540                }
    15641541                ftype->forall = std::move(forall);
    1565                 */
    1566 
    1567                 // can function type have attributes? seems not to be the case.
    1568                 // visitType(old->type, ftype);
     1542                visitType(old->type, ftype);
    15691543
    15701544                auto decl = new ast::FunctionDecl{
     
    15721546                        old->name,
    15731547                        // GET_ACCEPT_1(type, FunctionType),
    1574                         std::move(forall),
    15751548                        std::move(paramVars),
    15761549                        std::move(returnVars),
     
    15791552                        { old->linkage.val },
    15801553                        GET_ACCEPT_V(attributes, Attribute),
    1581                         { old->get_funcSpec().val },
    1582                         old->type->isVarArgs
     1554                        { old->get_funcSpec().val }
    15831555                };
    15841556
    1585                 // decl->type = ftype;
     1557                decl->type = ftype;
    15861558                cache.emplace( old, decl );
    15871559
     
    15981570
    15991571                if ( Validate::dereferenceOperator == old ) {
    1600                         ast::dereferenceOperator = decl;
     1572                        dereferenceOperator = decl;
    16011573                }
    16021574
    16031575                if ( Validate::dtorStructDestroy == old ) {
    1604                         ast::dtorStructDestroy = decl;
     1576                        dtorStructDestroy = decl;
    16051577                }
    16061578        }
     
    16271599
    16281600                if ( Validate::dtorStruct == old ) {
    1629                         ast::dtorStruct = decl;
     1601                        dtorStruct = decl;
    16301602                }
    16311603        }
     
    25592531                // I believe this should always be a BasicType.
    25602532                if ( Validate::SizeType == old ) {
    2561                         ast::sizeType = type;
     2533                        sizeType = type;
    25622534                }
    25632535                visitType( old, type );
     
    28042776#undef GET_ACCEPT_1
    28052777
    2806 ast::TranslationUnit convert( const std::list< Declaration * > && translationUnit ) {
     2778std::list< ast::ptr< ast::Decl > > convert( const std::list< Declaration * > && translationUnit ) {
    28072779        ConverterOldToNew c;
    2808         ast::TranslationUnit unit;
     2780        std::list< ast::ptr< ast::Decl > > decls;
    28092781        for(auto d : translationUnit) {
    28102782                d->accept( c );
    2811                 unit.decls.emplace_back( c.decl() );
     2783                decls.emplace_back( c.decl() );
    28122784        }
    28132785        deleteAll(translationUnit);
    2814         return unit;
     2786        return decls;
    28152787}
  • src/AST/Convert.hpp

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

    rc28ea4e r4b30e8cc  
    4848
    4949// --- FunctionDecl
    50 
    51 FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name,
    52                 std::vector<ptr<TypeDecl>>&& forall,
    53                 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    54                 CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
    55                 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
    56         : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
    57           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 
    6950
    7051const Type * FunctionDecl::get_type() const { return type.get(); }
  • src/AST/Decl.hpp

    rc28ea4e r4b30e8cc  
    131131        std::vector< ptr<Expr> > withExprs;
    132132
    133         FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
     133        FunctionDecl( const CodeLocation & loc, const std::string & name,
    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 = {}, bool isVarArgs = false);
    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 = {})
     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

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

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

    rc28ea4e r4b30e8cc  
    6767// --- UntypedExpr
    6868
    69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) {
     69UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, Expr * arg ) {
    7070        assert( arg );
    7171
     
    9292}
    9393
    94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) {
     94UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs ) {
    9595        assert( lhs && rhs );
    9696
     
    102102        }
    103103        return ret;
    104 }
    105 
    106 // --- VariableExpr
    107 
    108 VariableExpr::VariableExpr( const CodeLocation & loc )
    109 : Expr( loc ), var( nullptr ) {}
    110 
    111 VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v )
    112 : Expr( loc ), var( v ) {
    113         assert( var );
    114         assert( var->get_type() );
    115         result = shallowCopy( var->get_type() );
    116 }
    117 
    118 bool VariableExpr::get_lvalue() const {
    119         // It isn't always an lvalue, but it is never an rvalue.
    120         return true;
    121 }
    122 
    123 VariableExpr * VariableExpr::functionPointer(
    124                 const CodeLocation & loc, const FunctionDecl * decl ) {
    125         // wrap usually-determined result type in a pointer
    126         VariableExpr * funcExpr = new VariableExpr{ loc, decl };
    127         funcExpr->result = new PointerType{ funcExpr->result };
    128         return funcExpr;
    129104}
    130105
     
    263238}
    264239
     240// --- VariableExpr
     241
     242VariableExpr::VariableExpr( const CodeLocation & loc )
     243: Expr( loc ), var( nullptr ) {}
     244
     245VariableExpr::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
     252bool VariableExpr::get_lvalue() const {
     253        // It isn't always an lvalue, but it is never an rvalue.
     254        return true;
     255}
     256
     257VariableExpr * 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

    rc28ea4e r4b30e8cc  
    226226
    227227        /// Creates a new dereference expression
    228         static UntypedExpr * createDeref( const CodeLocation & loc, const Expr * arg );
     228        static UntypedExpr * createDeref( const CodeLocation & loc, Expr * arg );
    229229        /// Creates a new assignment expression
    230         static UntypedExpr * createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs );
     230        static UntypedExpr * createAssign( const CodeLocation & loc, Expr * lhs, 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.
    253 class VariableExpr final : public Expr {
    254 public:
    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 ); }
    266 private:
    267         VariableExpr * clone() const override { return new VariableExpr{ *this }; }
    268249        MUTATE_FRIEND
    269250};
     
    411392};
    412393
     394/// A reference to a named variable.
     395class VariableExpr final : public Expr {
     396public:
     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 ); }
     408private:
     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 ), underlyer(ty) {}
     424        : Expr( loc, ty ), rep( r ), ival( i ) {}
    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 ), callExpr(call) { assert( call ); assert(call->result); }
     619        : Expr( loc, call->result ) { assert( call ); }
    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 
    746744        StmtExpr( const CodeLocation & loc, const CompoundStmt * ss );
    747745
  • src/AST/Fwd.hpp

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

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

    rc28ea4e r4b30e8cc  
    103103        /// Construct and run a pass on a translation unit.
    104104        template< typename... Args >
    105         static void run( TranslationUnit & decls, Args &&... args ) {
     105        static void run( std::list< ptr<Decl> > & 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( TranslationUnit & decls ) {
     121        static void run( std::list< ptr<Decl> > & 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 
    235230private:
    236231
     
    240235        const ast::Stmt * call_accept( const ast::Stmt * );
    241236        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 *);
    246237
    247238        template< typename node_t >
     
    266257        template<typename node_t, typename parent_t, typename child_t>
    267258        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);
    271259
    272260private:
     
    296284private:
    297285        bool inFunction = false;
    298         bool atFunctionTop = false;
    299286};
    300287
     
    302289template<typename core_t>
    303290void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor );
    304 
    305 template<typename core_t>
    306 void accept_all( ast::TranslationUnit &, ast::Pass<core_t> & visitor );
    307291
    308292//-------------------------------------------------------------------------------------------------
     
    387371struct WithVisitorRef {
    388372        Pass<core_t> * const visitor = nullptr;
    389 
    390         bool isInFunction() const {
    391                 return visitor->isInFunction();
    392         }
    393373};
    394374
  • src/AST/Pass.impl.hpp

    rc28ea4e r4b30e8cc  
    2020#include <unordered_map>
    2121
    22 #include "AST/TranslationUnit.hpp"
    2322#include "AST/TypeSubstitution.hpp"
    2423
     
    168167                __pedantic_pass_assert( stmt );
    169168
    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 
    178169                // add a few useful symbols to the scope
    179170                using __pass::empty;
     
    343334        }
    344335
    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 
    369336
    370337        template< typename core_t >
     
    431398        pass_visitor_stats.depth--;
    432399        if ( !errors.isEmpty() ) { throw errors; }
    433 }
    434 
    435 template< typename core_t >
    436 inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) {
    437         return ast::accept_all( unit.decls, visitor );
    438400}
    439401
     
    508470                                // foralls are still in function type
    509471                                maybe_accept( node, &FunctionDecl::type );
    510                                 // First remember that we are now within a function.
     472                                // function body needs to have the same scope as parameters - CompoundStmt will not enter
     473                                // a new scope if inFunction is true
    511474                                ValueGuard< bool > oldInFunction( inFunction );
    512475                                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;
    517476                                maybe_accept( node, &FunctionDecl::stmts );
    518477                                maybe_accept( node, &FunctionDecl::attributes );
     
    680639const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) {
    681640        VISIT_START( node );
    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);
     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);
    688647                });
    689                 ValueGuard< bool > guard2( atFunctionTop );
    690                 atFunctionTop = false;
     648                ValueGuard< bool > guard2( inFunction );
    691649                guard_scope guard3 { *this };
     650                inFunction = false;
    692651                maybe_accept( node, &CompoundStmt::kids );
    693         )
     652        })
    694653        VISIT_END( CompoundStmt, node );
    695654}
     
    744703                maybe_accept( node, &IfStmt::inits    );
    745704                maybe_accept( node, &IfStmt::cond     );
    746                 maybe_accept_as_compound( node, &IfStmt::thenPart );
    747                 maybe_accept_as_compound( node, &IfStmt::elsePart );
     705                maybe_accept( node, &IfStmt::thenPart );
     706                maybe_accept( node, &IfStmt::elsePart );
    748707        })
    749708
     
    762721                maybe_accept( node, &WhileStmt::inits );
    763722                maybe_accept( node, &WhileStmt::cond  );
    764                 maybe_accept_as_compound( node, &WhileStmt::body  );
     723                maybe_accept( node, &WhileStmt::body  );
    765724        })
    766725
     
    777736                // for statements introduce a level of scope (for the initialization)
    778737                guard_symtab guard { *this };
    779                 // xxx - old ast does not create WithStmtsToAdd scope for loop inits. should revisit this later.
    780738                maybe_accept( node, &ForStmt::inits );
    781739                maybe_accept( node, &ForStmt::cond  );
    782740                maybe_accept( node, &ForStmt::inc   );
    783                 maybe_accept_as_compound( node, &ForStmt::body  );
     741                maybe_accept( node, &ForStmt::body  );
    784742        })
    785743
     
    876834                maybe_accept( node, &CatchStmt::decl );
    877835                maybe_accept( node, &CatchStmt::cond );
    878                 maybe_accept_as_compound( node, &CatchStmt::body );
     836                maybe_accept( node, &CatchStmt::body );
    879837        })
    880838
  • src/AST/Pass.proto.hpp

    rc28ea4e r4b30e8cc  
    2222template<typename core_t>
    2323class Pass;
    24 
    25 class TranslationUnit;
    2624
    2725struct PureVisitor;
  • src/AST/SymbolTable.cpp

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

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

    rc28ea4e r4b30e8cc  
    157157
    158158template<typename decl_t>
    159 SueInstType<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 
    164 template<typename decl_t>
    165159bool SueInstType<decl_t>::isComplete() const {
    166160        return base ? base->body : false;
  • src/AST/Type.hpp

    rc28ea4e r4b30e8cc  
    302302class FunctionType final : public ParameterizedType {
    303303public:
     304//      std::vector<ptr<DeclWithType>> returns;
     305//      std::vector<ptr<DeclWithType>> params;
     306
    304307        std::vector<ptr<Type>> returns;
    305308        std::vector<ptr<Type>> params;
     
    342345        : ParameterizedType(q, std::move(as)), params(), name(n) {}
    343346
    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 
    349347        BaseInstType( const BaseInstType & o );
    350348
     
    371369
    372370        SueInstType(
    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 = {} );
     371                const decl_t * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
    378372
    379373        bool isComplete() const override;
  • src/AST/porting.md

    rc28ea4e r4b30e8cc  
    3030  * Base nodes now override `const Node * accept( Visitor & v ) const = 0` with, e.g. `const Stmt * accept( Visitor & v ) const override = 0`
    3131* `PassVisitor` is replaced with `ast::Pass`
    32   * Most one shot uses can use `ast::Pass::run` and `ast::Pass::read`.
    33 
    34 `WithConstTypeSubstitution`
    35 * `env` => `typeSubs`
    3632
    3733## Structural Changes ##
     
    150146  * allows `newObject` as just default settings
    151147
    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 
    157148`NamedTypeDecl`
    158149* `parameters` => `params`
     
    163154`AggregateDecl`
    164155* `parameters` => `params`
    165 
    166 `StructDecl`
    167 * `makeInst` replaced by better constructor on `StructInstType`.
    168156
    169157`Expr`
     
    257245* **TODO** move `kind`, `typeNames` into code generator
    258246
    259 `ReferenceToType` => `BaseInstType`
     247`ReferenceToType`
    260248* deleted `get_baseParameters()` from children
    261249  * replace with `aggr() ? aggr()->params : nullptr`
     
    273261* `returnVals` => `returns`
    274262* `parameters` => `params`
    275   * Both now just point at types.
    276263* `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`
    281264
    282265`TypeInstType`
  • src/Common/PassVisitor.h

    rc28ea4e r4b30e8cc  
    354354        virtual TypeSubstitution * mutate( TypeSubstitution * sub ) final;
    355355
    356         bool isInFunction() const {
    357                 return inFunction;
    358         }
    359 
    360356private:
    361357        bool inFunction = false;
    362         bool atFunctionTop = false;
    363358
    364359        template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor );
     
    531526public:
    532527        PassVisitor<pass_type> * const visitor = nullptr;
    533 
    534         bool isInFunction() const {
    535                 return visitor->isInFunction();
    536         }
    537528};
    538529
  • src/Common/PassVisitor.impl.h

    rc28ea4e r4b30e8cc  
    532532                        indexerAddId( &func );
    533533                        maybeAccept_impl( node->type, *this );
    534                         // First remember that we are now within a function.
     534                        // function body needs to have the same scope as parameters - CompoundStmt will not enter
     535                        // a new scope if inFunction is true
    535536                        ValueGuard< bool > oldInFunction( inFunction );
    536537                        inFunction = true;
    537                         // The function body needs to have the same scope as parameters.
    538                         // A CompoundStmt will not enter a new scope if atFunctionTop is true.
    539                         ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
    540                         atFunctionTop = true;
    541538                        maybeAccept_impl( node->statements, *this );
    542539                        maybeAccept_impl( node->attributes, *this );
     
    570567                        indexerAddId( &func );
    571568                        maybeAccept_impl( node->type, *this );
    572                         // First remember that we are now within a function.
     569                        // function body needs to have the same scope as parameters - CompoundStmt will not enter
     570                        // a new scope if inFunction is true
    573571                        ValueGuard< bool > oldInFunction( inFunction );
    574572                        inFunction = true;
    575                         // The function body needs to have the same scope as parameters.
    576                         // A CompoundStmt will not enter a new scope if atFunctionTop is true.
    577                         ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
    578                         atFunctionTop = true;
    579573                        maybeAccept_impl( node->statements, *this );
    580574                        maybeAccept_impl( node->attributes, *this );
     
    607601                        indexerAddId( &func );
    608602                        maybeMutate_impl( node->type, *this );
    609                         // First remember that we are now within a function.
     603                        // function body needs to have the same scope as parameters - CompoundStmt will not enter
     604                        // a new scope if inFunction is true
    610605                        ValueGuard< bool > oldInFunction( inFunction );
    611606                        inFunction = true;
    612                         // The function body needs to have the same scope as parameters.
    613                         // A CompoundStmt will not enter a new scope if atFunctionTop is true.
    614                         ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
    615                         atFunctionTop = true;
    616607                        maybeMutate_impl( node->statements, *this );
    617608                        maybeMutate_impl( node->attributes, *this );
     
    10161007        VISIT_START( node );
    10171008        {
    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(); } );
     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(); } );
    10211012                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1022                 atFunctionTop = false;
     1013                inFunction = false;
    10231014                visitStatementList( node->kids );
    10241015        }
     
    10301021        VISIT_START( node );
    10311022        {
    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(); } );
     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(); } );
    10351026                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1036                 atFunctionTop = false;
     1027                inFunction = false;
    10371028                visitStatementList( node->kids );
    10381029        }
     
    10441035        MUTATE_START( node );
    10451036        {
    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(); } );
     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(); } );
    10491040                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1050                 atFunctionTop = false;
     1041                inFunction = false;
    10511042                mutateStatementList( node->kids );
    10521043        }
  • src/Common/utility.h

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

    rc28ea4e r4b30e8cc  
    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 
    5648        //=============================================================================================
    5749        // Pass declarations
     
    127119                        "get_thread",
    128120                        "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
    129                         "ThreadCancelled",
     121                        "",
    130122                        true,
    131123                        AggregateDecl::Thread
     
    298290                std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first );
    299291                void validate( DeclarationWithType * );
    300                 void addDtorStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
    301                 void addStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
    302                 void addThreadDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args );
     292                void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
     293                void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
    303294
    304295                static void implement( std::list< Declaration * > & translationUnit ) {
     
    311302                StructDecl* guard_decl = nullptr;
    312303                StructDecl* dtor_guard_decl = nullptr;
    313                 StructDecl* thread_guard_decl = nullptr;
    314304
    315305                static std::unique_ptr< Type > generic_func;
     
    811801                bool first = false;
    812802                std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first );
    813                 bool const isDtor = CodeGen::isDestructor( decl->name );
     803                bool isDtor = CodeGen::isDestructor( decl->name );
    814804
    815805                // Is this function relevant to monitors
     
    859849
    860850                // Instrument the body
    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 );
     851                if( isDtor ) {
     852                        addDtorStatments( decl, body, mutexArgs );
    869853                }
    870854                else {
    871                         addStatements( decl, body, mutexArgs );
     855                        addStatments( decl, body, mutexArgs );
    872856                }
    873857        }
     
    886870                        assert( !dtor_guard_decl );
    887871                        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;
    892872                }
    893873        }
     
    928908        }
    929909
    930         void MutexKeyword::addDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
     910        void MutexKeyword::addDtorStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
    931911                Type * arg_type = args.front()->get_type()->clone();
    932912                arg_type->set_mutex( false );
     
    977957
    978958                //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
    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 ) {
     959                body->push_front( new DeclStmt( monitors) );
     960        }
     961
     962        void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
    1019963                ObjectDecl * monitors = new ObjectDecl(
    1020964                        "__monitors",
  • src/GenPoly/GenPoly.cc

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

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

    rc28ea4e r4b30e8cc  
    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 
    224220                // thread thunk parameters into call to actual function, naming thunk parameters as we go
    225221                UniqueName paramNamer( paramPrefix );
  • src/InitTweak/FixGlobalInit.cc

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

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

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

    rc28ea4e r4b30e8cc  
    2020
    2121class Declaration;
    22 namespace ast {
    23         class TranslationUnit;
    24 }
    2522
    2623namespace InitTweak {
    2724        /// replace constructor initializers with expression statements and unwrap basic C-style initializers
    2825        void fix( std::list< Declaration * > & translationUnit, bool inLibrary );
    29 
    30         void fix( ast::TranslationUnit & translationUnit, bool inLibrary);
    3126} // namespace
    3227
  • src/InitTweak/GenInit.cc

    rc28ea4e r4b30e8cc  
    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);
    292285        }
    293286
  • src/InitTweak/GenInit.h

    rc28ea4e r4b30e8cc  
    3333        /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
    3434        ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr );
    35         ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr);
    3635
    3736        /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
  • src/InitTweak/InitTweak.cc

    rc28ea4e r4b30e8cc  
    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 
    507500        bool tryConstruct( DeclarationWithType * dwt ) {
    508501                ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );
     
    518511        }
    519512
    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 
    534513        struct CallFinder_old {
    535514                CallFinder_old( const std::list< std::string > & names ) : names( names ) {}
     
    557536
    558537        struct CallFinder_new final {
    559                 std::vector< const ast::Expr * > matches;
     538                std::vector< ast::ptr< ast::Expr > > matches;
    560539                const std::vector< std::string > names;
    561540
     
    579558        }
    580559
    581         std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
     560        std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt ) {
    582561                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
    583562                maybe_accept( stmt, finder );
     
    717696                template <typename Predicate>
    718697                bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
    719                         std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt );
     698                        std::vector< ast::ptr< ast::Expr > > callExprs = collectCtorDtorCalls( stmt );
    720699                        return std::all_of( callExprs.begin(), callExprs.end(), pred );
    721700                }
     
    960939        }
    961940
    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 
    989941        struct ConstExprChecker : public WithShortCircuiting {
    990942                // most expressions are not const expr
     
    11031055                return isCopyFunction( decl, "?{}" );
    11041056        }
    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 
    11151057}
  • src/InitTweak/InitTweak.h

    rc28ea4e r4b30e8cc  
    3838        /// returns the first parameter of a constructor/destructor/assignment function
    3939        ObjectDecl * getParamThis( FunctionType * ftype );
    40         const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
    4140
    4241        /// generate a bitwise assignment operation.
    4342        ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );
    44 
    45         ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
    4643
    4744        /// transform Initializer into an argument list that can be passed to a call expression
     
    5148        /// True if the resolver should try to construct dwt
    5249        bool tryConstruct( DeclarationWithType * dwt );
    53         bool tryConstruct( const ast::DeclWithType * dwt );
    5450
    5551        /// True if the type can have a user-defined constructor
    5652        bool isConstructable( Type * t );
    57         bool isConstructable( const ast::Type * t );
    5853
    5954        /// True if the Initializer contains designations
     
    8479        /// get all Ctor/Dtor call expressions from a Statement
    8580        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
    86         std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
     81        std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt );
    8782
    8883        /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
     
    107102        bool isConstExpr( Expression * expr );
    108103        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 );
    120104
    121105        class InitExpander_old {
  • src/InitTweak/module.mk

    rc28ea4e r4b30e8cc  
    2323        InitTweak/GenInit.h \
    2424        InitTweak/InitTweak.cc \
    25         InitTweak/InitTweak.h \
    26         InitTweak/FixInitNew.cpp
     25        InitTweak/InitTweak.h
    2726
    2827SRCDEMANGLE += \
  • src/Parser/ParseNode.h

    rc28ea4e r4b30e8cc  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Oct 24 03:53:54 2020
    13 // Update Count     : 895
     12// Last Modified On : Mon Jul  6 09:33:32 2020
     13// Update Count     : 892
    1414//
    1515
     
    205205struct TypeData;
    206206
    207 struct DeclarationNode : public ParseNode {
     207class DeclarationNode : public ParseNode {
     208  public:
    208209        // These enumerations must harmonize with their names in DeclarationNode.cc.
    209210        enum BasicType { Void, Bool, Char, Int, Int128,
     
    303304        bool get_inLine() const { return inLine; }
    304305        DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
    305 
     306  public:
    306307        DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }
    307308
     
    359360//##############################################################################
    360361
    361 struct StatementNode final : public ParseNode {
     362class StatementNode final : public ParseNode {
     363  public:
    362364        StatementNode() { stmt = nullptr; }
    363365        StatementNode( Statement * stmt ) : stmt( stmt ) {}
     
    380382                os << stmt.get() << std::endl;
    381383        }
    382 
     384  private:
    383385        std::unique_ptr<Statement> stmt;
    384386}; // StatementNode
     
    424426Statement * build_finally( StatementNode * stmt );
    425427Statement * build_compound( StatementNode * first );
    426 StatementNode * maybe_build_compound( StatementNode * first );
    427428Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
    428429Statement * build_directive( std::string * directive );
  • src/Parser/StatementNode.cc

    rc28ea4e r4b30e8cc  
    1010// Created On       : Sat May 16 14:59:41 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Oct 24 04:20:55 2020
    13 // Update Count     : 383
     12// Last Modified On : Sat Aug  4 09:39:25 2018
     13// Update Count     : 363
    1414//
    1515
     
    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.
    351 StatementNode * maybe_build_compound( StatementNode * first ) {
    352         // Optimization: if the control-structure statement is a compound statement, do not wrap it.
    353         // e.g., if (...) {...} do not wrap the existing compound statement.
    354         if ( ! dynamic_cast<CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
    355                 CompoundStmt * cs = new CompoundStmt();
    356                 buildMoveList( first, cs->get_kids() );
    357                 return new StatementNode( cs );
    358         } // if
    359         return first;
    360 } // maybe_build_compound
    361 
    362347Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    363348        std::list< Expression * > out, in;
  • src/Parser/parser.yy

    rc28ea4e r4b30e8cc  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Oct 24 08:21:14 2020
    13 // Update Count     : 4624
     12// Last Modified On : Fri Oct  9 18:09:09 2020
     13// Update Count     : 4614
    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, maybe_build_compound( $5 ), nullptr ) ); }
     1082                { $$ = new StatementNode( build_if( $3, $5, nullptr ) ); }
    10831083        | IF '(' if_control_expression ')' statement ELSE statement
    1084                 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); }
     1084                { $$ = new StatementNode( build_if( $3, $5, $7 ) ); }
    10851085        ;
    10861086
     
    11301130
    11311131case_clause:                                                                                    // CFA
    1132         case_label_list statement                                       { $$ = $1->append_last_case( maybe_build_compound( $2 ) ); }
     1132        case_label_list statement                                       { $$ = $1->append_last_case( new StatementNode( build_compound( $2 ) ) ); }
    11331133        ;
    11341134
     
    11481148iteration_statement:
    11491149        WHILE '(' push if_control_expression ')' statement pop
    1150                 { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); }
     1150                { $$ = new StatementNode( build_while( $4, $6 ) ); }
    11511151        | WHILE '(' ')' statement                                                       // CFA => while ( 1 )
    1152                 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
     1152                { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), $4 ) ); }
    11531153        | DO statement WHILE '(' comma_expression ')' ';'
    1154                 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
     1154                { $$ = new StatementNode( build_do_while( $5, $2 ) ); }
    11551155        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    1156                 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
     1156                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), $2 ) ); }
    11571157        | FOR '(' push for_control_expression_list ')' statement pop
    1158                 { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); }
     1158                { $$ = new StatementNode( build_for( $4, $6 ) ); }
    11591159        | FOR '(' ')' statement                                                         // CFA => for ( ;; )
    1160                 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
     1160                { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), $4 ) ); }
    11611161        ;
    11621162
     
    13411341waitfor_clause:
    13421342        when_clause_opt waitfor statement                                       %prec THEN
    1343                 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1 ); }
     1343                { $$ = build_waitfor( $2, $3, $1 ); }
    13441344        | when_clause_opt waitfor statement WOR waitfor_clause
    1345                 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1, $5 ); }
     1345                { $$ = build_waitfor( $2, $3, $1, $5 ); }
    13461346        | when_clause_opt timeout statement                                     %prec THEN
    1347                 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1 ); }
     1347                { $$ = build_waitfor_timeout( $2, $3, $1 ); }
    13481348        | when_clause_opt ELSE statement
    1349                 { $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); }
     1349                { $$ = build_waitfor_timeout( nullptr, $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, maybe_build_compound( $3 ), $1, maybe_build_compound( $7 ), $5 ); }
     1354                { $$ = build_waitfor_timeout( $2, $3, $1, $7, $5 ); }
    13551355        ;
    13561356
  • src/ResolvExpr/Resolver.cc

    rc28ea4e r4b30e8cc  
    11051105                }
    11061106
    1107                
    1108         } // anonymous namespace
    1109 /// Establish post-resolver invariants for expressions
     1107                /// Establish post-resolver invariants for expressions
    11101108                void finishExpr(
    11111109                        ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
     
    11201118                        StripCasts_new::strip( expr );
    11211119                }
     1120        } // anonymous namespace
     1121
    11221122
    11231123        ast::ptr< ast::Expr > resolveInVoidContext(
     
    11391139        }
    11401140
    1141         /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
     1141        namespace {
     1142                /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
    11421143                /// context.
    11431144                ast::ptr< ast::Expr > findVoidExpression(
     
    11501151                        return newExpr;
    11511152                }
    1152 
    1153         namespace {
    1154                
    11551153
    11561154                /// resolve `untyped` to the expression whose candidate satisfies `pred` with the
     
    11641162                        CandidateRef choice =
    11651163                                findUnfinishedKindExpression( untyped, symtab, kind, pred, mode );
    1166                         ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
     1164                        finishExpr( choice->expr, choice->env, untyped->env );
    11671165                        return std::move( choice->expr );
    11681166                }
     
    12741272        // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver");
    12751273
    1276         void resolve( ast::TranslationUnit& translationUnit ) {
     1274        void resolve( std::list< ast::ptr< ast::Decl > >& translationUnit ) {
    12771275                ast::Pass< Resolver_new >::run( translationUnit );
    12781276        }
  • src/ResolvExpr/Resolver.h

    rc28ea4e r4b30e8cc  
    3535        class StmtExpr;
    3636        class SymbolTable;
    37         class TranslationUnit;
    3837        class Type;
    3938        class TypeEnvironment;
     
    5655
    5756        /// Checks types and binds syntactic constructs to typed representations
    58         void resolve( ast::TranslationUnit& translationUnit );
     57        void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit );
    5958        /// Searches expr and returns the first DeletedExpr found, otherwise nullptr
    6059        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr );
     
    6766        ast::ptr< ast::Expr > findSingleExpression(
    6867                const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab );
    69         ast::ptr< ast::Expr > findVoidExpression(
    70                 const ast::Expr * untyped, const ast::SymbolTable & symtab);
    7168        /// Resolves a constructor init expression
    72         ast::ptr< ast::Init > resolveCtorInit(
     69        ast::ptr< ast::Init > resolveCtorInit( 
    7370                const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab );
    7471        /// Resolves a statement expression
    75         ast::ptr< ast::Expr > resolveStmtExpr(
     72        ast::ptr< ast::Expr > resolveStmtExpr( 
    7673                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab );
    7774} // namespace ResolvExpr
  • src/SymTab/Autogen.cc

    rc28ea4e r4b30e8cc  
    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 
    246235        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
    247236        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
     
    255244                ftype->parameters.push_back( dstParam );
    256245                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));
    265246        }
    266247
  • src/SymTab/Autogen.h

    rc28ea4e r4b30e8cc  
    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);
    5957
    6058        /// generate the type of a copy constructor for paramType.
  • src/SynTree/Expression.h

    rc28ea4e r4b30e8cc  
    163163};
    164164
    165 /// VariableExpr represents an expression that simply refers to the value of a named variable.
    166 /// Does not take ownership of var.
    167 class VariableExpr : public Expression {
    168   public:
    169         DeclarationWithType * var;
    170 
    171         VariableExpr();
    172         VariableExpr( DeclarationWithType * var );
    173         VariableExpr( const VariableExpr & other );
    174         virtual ~VariableExpr();
    175 
    176         bool get_lvalue() const final;
    177 
    178         DeclarationWithType * get_var() const { return var; }
    179         void set_var( DeclarationWithType * newValue ) { var = newValue; }
    180 
    181         static VariableExpr * functionPointer( FunctionDecl * decl );
    182 
    183         virtual VariableExpr * clone() const override { return new VariableExpr( * this ); }
    184         virtual void accept( Visitor & v ) override { v.visit( this ); }
    185         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    186         virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    187         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    188 };
    189 
    190165// The following classes are used to represent expression types that cannot be converted into
    191166// function-call format.
     
    354329};
    355330
     331/// VariableExpr represents an expression that simply refers to the value of a named variable.
     332/// Does not take ownership of var.
     333class 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

    rc28ea4e r4b30e8cc  
    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()));
    352345                        translationUnit = convert( move( transUnit ) );
    353346                } else {
    354347                        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() ) );
    361348                }
    362349
     350                if ( exprp ) {
     351                        dump( translationUnit );
     352                        return EXIT_SUCCESS;
     353                } // if
     354
    363355                // fix ObjectDecl - replaces ConstructorInit nodes
     356                PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
    364357                if ( ctorinitp ) {
    365358                        dump ( translationUnit );
  • tests/.expect/const-init.txt

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

    rc28ea4e r4b30e8cc  
    5353
    5454# adjust CC to current flags
    55 CC = LC_ALL=C $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS} ${AST_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS} ${AST_FLAGS})
     55CC = LC_ALL=C $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_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} ${AST_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS} ${AST_FLAGS})
     62CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
    6363CFACCLINK = $(CFACCLOCAL) -quiet $(if $(test), 2> $(test), ) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g'))
    6464
  • tests/alloc.cfa

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

    rc28ea4e r4b30e8cc  
    1414//
    1515
     16#include <stdio.h>
    1617#include <complex.h>
    1718#ifdef __CFA__
  • tests/config.py.in

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

    rc28ea4e r4b30e8cc  
    1616/*
    1717
    18 These tests show non-crashing of generated code for constants with interesting initializers.
     18This test shows non-crashing of generated code for constants with interesting initizers.
    1919The potential for these to crash is compiler dependent.
    2020
    2121There are two cases:
    22 1. static constants in one compilation unit (tested here, in a few sub-cases)
     221. static constants in one compilation unit (tested here)
    23232. extern constants across compilation units (tested by libcfa being loadable, specifically
    24    the constant definitions in libcfa/src/limits.cfa, which almost every test exercises,
     24   the constant declarations 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 to fail, with most other tests passing, would be a situation only ever
     39For this test case 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
    4544static const char foo = -1;
    4645
    47 struct thing{};
    48 void ^?{}( thing & ) { printf("dtor\n"); }
    49 
    5046int main() {
    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");
     47    printf("done\n");
    6048}
  • tests/exceptions/cancel/coroutine.cfa

    rc28ea4e r4b30e8cc  
    11// Try cancelling a coroutine.
    22
     3#include <stdio.h>
    34#include <coroutine.hfa>
    45#include <exception.hfa>
  • tests/exceptions/conditional.cfa

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

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

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

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

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

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

    rc28ea4e r4b30e8cc  
    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
    8788
    8889        @staticmethod
     
    9697                self.flags  = """DEBUG_FLAGS=%s""" % ("-debug -O0" if value else "-nodebug -O2")
    9798                self.path   = "debug" if value else "nodebug"
    98 
    99 class AST:
    100         def __init__(self, ast):
    101                 if ast == "new":
    102                         self.target = ast
    103                         self.string = "New AST"
    104                         self.flags  = """AST_FLAGS=-XCFA,--new-ast"""
    105                 elif ast == "old":
    106                         self.target = ast
    107                         self.string = "Old AST"
    108                         self.flags  = """AST_FLAGS=-XCFA,--old-ast"""
    109                 elif ast == None:
    110                         self.target = "new" if config.NEWAST else "old"
    111                         self.string = "Default AST (%s)" % self.target
    112                         self.flags  = """AST_FLAGS="""
    113                 else:
    114                         print("""ERROR: Invalid ast configuration, must be "old", "new" or left unspecified, was %s""" % (value), file=sys.stderr)
    115                         sys.exit(1)
    116 
    117         def filter(self, tests):
    118 
    119                 return [test for test in tests if not test.astv or self.target == test.astv]
    12099
    121100class Install:
     
    141120
    142121def init( options ):
    143         global all_ast
    144122        global all_arch
    145123        global all_debug
    146124        global all_install
    147         global ast
    148125        global arch
     126        global archive
     127        global continue_
    149128        global debug
    150         global archive
    151         global install
    152 
    153         global continue_
    154129        global dry_run
    155130        global generating
     131        global install
    156132        global make
    157133        global output_width
     
    159135        global timeout2gdb
    160136
    161         all_ast      = [AST(o)          for o in list(dict.fromkeys(options.ast    ))] if options.ast  else [AST(None)]
    162137        all_arch     = [Architecture(o) for o in list(dict.fromkeys(options.arch   ))] if options.arch else [Architecture(None)]
    163138        all_debug    = [Debug(o)        for o in list(dict.fromkeys(options.debug  ))]
  • tests/pybin/test_run.py

    rc28ea4e r4b30e8cc  
    1111                self.path = ''
    1212                self.arch = ''
    13                 self.astv = ''
    1413
    1514        def toString(self):
    16                 return "{:25s} ({:5s} arch, {:s} ast: {:s})".format( self.name, self.arch if self.arch else "Any", self.astv if self.astv else "Any", self.target() )
     15                return "{:25s} ({:5s} {:s})".format( self.name, self.arch if self.arch else "Any", self.target() )
    1716
    1817        def prepare(self):
     
    2120
    2221        def expect(self):
    23                 arch = '' if not self.arch else ".%s" % self.arch
    24                 astv = '' if not self.astv else ".nast" if self.astv == "new" else ".oast"
    25                 return os.path.normpath( os.path.join(settings.SRCDIR  , self.path, ".expect", "%s%s%s.txt" % (self.name,astv,arch)) )
     22                return os.path.normpath( os.path.join(settings.SRCDIR  , self.path, ".expect", "%s%s.txt" % (self.name,'' if not self.arch else ".%s" % self.arch)) )
    2623
    2724        def error_log(self):
     
    4845
    4946        @staticmethod
    50         def new_target(target, arch, astv):
     47        def new_target(target, arch):
    5148                test = Test()
    5249                test.name = os.path.basename(target)
    5350                test.path = os.path.relpath (os.path.dirname(target), settings.SRCDIR)
    5451                test.arch = arch.target if arch else ''
    55                 test.astv = astv.target if astv else ''
    5652                return test
    5753
  • tests/pybin/tools.py

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

    rc28ea4e r4b30e8cc  
    2424
    2525        def match_test(path):
    26                 match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.nast|\.oast)?(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path)
     26                match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.[\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(4)[1:] if match.group(4) else None
    32 
    33                         astv = match.group(3)[1:] if match.group(3) else None
    34                         if astv == 'oast':
    35                                 test.astv = 'old'
    36                         elif astv == 'nast':
    37                                 test.astv = 'new'
    38                         elif astv:
    39                                 print('ERROR: "%s", expect file has astv but it is not "nast" or "oast"' % testname, file=sys.stderr)
    40                                 sys.exit(1)
    41 
     31                        test.arch = match.group(3)[1:] if match.group(3) else None
    4232                        expected.append(test)
    4333
     
    7666        if options.regenerate_expected :
    7767                for testname in options.tests :
    78                         testname = os.path.normpath( os.path.join(settings.SRCDIR, testname) )
    79 
     68                        testname = canonical_path( testname )
    8069                        # first check if this is a valid name to regenerate
    8170                        if Test.valid_name(testname):
    8271                                # this is a valid name, let's check if it already exists
    8372                                found = [test for test in all_tests if canonical_path( test.target() ) == testname]
    84                                 setup = itertools.product(settings.all_arch if options.arch else [None], settings.all_ast if options.ast else [None])
    8573                                if not found:
    86                                         # it's a new name, create it according to the name and specified architecture/ast version
    87                                         tests.extend( [Test.new_target(testname, arch, ast) for arch, ast in setup] )
     74                                        # it's a new name, create it according to the name and specified architecture
     75                                        if options.arch:
     76                                                # user specified one or multiple architectures, assume the tests will have architecture specific results
     77                                                tests.extend( [Test.new_target(testname, arch) for arch in settings.all_arch] )
     78                                        else:
     79                                                # user didn't specify an architecture, just create a cross platform test
     80                                                tests.append( Test.new_target( testname, None ) )
    8881                                elif len(found) == 1 and not found[0].arch:
    8982                                        # we found a single test, the user better be wanting to create a cross platform test
    9083                                        if options.arch:
    9184                                                print('ERROR: "%s", test has no specified architecture but --arch was specified, ignoring it' % testname, file=sys.stderr)
    92                                         elif options.ast:
    93                                                 print('ERROR: "%s", test has no specified ast version but --ast was specified, ignoring it' % testname, file=sys.stderr)
    9485                                        else:
    9586                                                tests.append( found[0] )
    9687                                else:
    9788                                        # this test is already cross platform, just add a test for each platform the user asked
    98                                         tests.extend( [Test.new_target(testname, arch, ast) for arch, ast in setup] )
     89                                        tests.extend( [Test.new_target(testname, arch) for arch in settings.all_arch] )
    9990
    10091                                        # print a warning if it users didn't ask for a specific architecture
    10192                                        if not options.arch:
    10293                                                print('WARNING: "%s", test has architecture specific expected files but --arch was not specified, regenerating only for current host' % testname, file=sys.stderr)
    103 
    104 
    105                                         # print a warning if it users didn't ask for a specific ast version
    106                                         if not options.ast:
    107                                                 print('WARNING: "%s", test has ast version specific expected files but --ast was not specified, regenerating only for current ast' % testname, file=sys.stderr)
    10894
    10995                        else :
     
    126112        # create a parser with the arguments for the tests script
    127113        parser = argparse.ArgumentParser(description='Script which runs cforall tests')
    128         parser.add_argument('--ast', help='Test for specific ast', type=comma_separated(str), default=None)
    129         parser.add_argument('--arch', help='Test for specific architecture', type=comma_separated(str), default=None)
    130114        parser.add_argument('--debug', help='Run all tests in debug or release', type=comma_separated(yes_no), default='yes')
    131115        parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=comma_separated(yes_no), default='no')
     116        parser.add_argument('--arch', help='Test for specific architecture', type=comma_separated(str), default=None)
    132117        parser.add_argument('--continue', help='When multiple specifications are passed (debug/install/arch), sets whether or not to continue if the last specification failed', type=yes_no, default='yes', dest='continue_')
    133118        parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=120)
     
    266251        except KeyboardInterrupt:
    267252                return False, ""
    268         # except Exception as ex:
    269         #       print("Unexpected error in worker thread running {}: {}".format(t.target(), ex), file=sys.stderr)
    270         #       sys.stderr.flush()
    271         #       return False, ""
     253        except Exception as ex:
     254                print("Unexpected error in worker thread running {}: {}".format(t.target(), ex), file=sys.stderr)
     255                sys.stderr.flush()
     256                return False, ""
    272257
    273258
     
    377362                # for each build configurations, run the test
    378363                with Timed() as total_dur:
    379                         for ast, arch, debug, install in itertools.product(settings.all_ast, settings.all_arch, settings.all_debug, settings.all_install):
    380                                 settings.ast     = ast
     364                        for arch, debug, install in itertools.product(settings.all_arch, settings.all_debug, settings.all_install):
    381365                                settings.arch    = arch
    382366                                settings.debug   = debug
     
    385369                                # filter out the tests for a different architecture
    386370                                # tests are the same across debug/install
    387                                 local_tests = settings.ast.filter( tests )
    388                                 local_tests = settings.arch.filter( local_tests )
     371                                local_tests = settings.arch.filter( tests )
    389372                                options.jobs, forceJobs = job_count( options, local_tests )
    390373                                settings.update_make_cmd(forceJobs, options.jobs)
     
    394377
    395378                                # print configuration
    396                                 print('%s %i tests on %i cores (%s:%s - %s)' % (
     379                                print('%s %i tests on %i cores (%s:%s)' % (
    397380                                        'Regenerating' if settings.generating else 'Running',
    398381                                        len(local_tests),
    399382                                        options.jobs,
    400                                         settings.ast.string,
    401383                                        settings.arch.string,
    402384                                        settings.debug.string
    403385                                ))
    404                                 if not local_tests :
    405                                         print('WARNING: No tests for this configuration')
    406                                         continue
    407386
    408387                                # otherwise run all tests and make sure to return the correct error code
Note: See TracChangeset for help on using the changeset viewer.