Changes in / [c28ea4e:4b30e8cc]
- Files:
-
- 4 added
- 25 deleted
- 101 edited
-
Jenkins/FullBuild (modified) (1 diff)
-
Jenkinsfile (modified) (4 diffs)
-
benchmark/readyQ/bench.go (deleted)
-
benchmark/readyQ/cycle.cfa (deleted)
-
benchmark/readyQ/cycle.cpp (deleted)
-
benchmark/readyQ/cycle.go (deleted)
-
benchmark/readyQ/rq_bench.hfa (deleted)
-
benchmark/readyQ/rq_bench.hpp (deleted)
-
benchmark/rmit.py (deleted)
-
configure.ac (modified) (1 diff)
-
doc/papers/concurrency/mail2 (modified) (2 diffs)
-
doc/proposals/vtable.md (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/thesis-frontpgs.tex (modified) (3 diffs)
-
doc/theses/andrew_beach_MMath/uw-ethesis.cls (modified) (5 diffs)
-
doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/cforall.cpp (added)
-
doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/cforall.hpp (deleted)
-
doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/fibre.cpp (added)
-
doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/fibre.hpp (deleted)
-
doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/pthread.cpp (added)
-
doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/pthread.hpp (deleted)
-
doc/theses/thierry_delisle_PhD/comp_II/presentation.tex (modified) (6 diffs)
-
doc/theses/thierry_delisle_PhD/comp_II/presentationstyle.sty (modified) (2 diffs)
-
doc/theses/thierry_delisle_PhD/thesis/Makefile (modified) (3 diffs)
-
doc/theses/thierry_delisle_PhD/thesis/fig/system.fig (modified) (4 diffs)
-
doc/theses/thierry_delisle_PhD/thesis/glossary.tex (modified) (3 diffs)
-
doc/theses/thierry_delisle_PhD/thesis/local.bib (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/text/core.tex (modified) (4 diffs)
-
doc/theses/thierry_delisle_PhD/thesis/text/existing.tex (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/text/front.tex (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/thesis/text/intro.tex (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/thesis/text/io.tex (modified) (2 diffs)
-
doc/theses/thierry_delisle_PhD/thesis/text/practice.tex (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/thesis/text/runtime.tex (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/thesis/thesis.tex (modified) (3 diffs)
-
libcfa/prelude/builtins.c (modified) (1 diff)
-
libcfa/src/concurrency/clib/cfathread.cfa (modified) (1 diff)
-
libcfa/src/concurrency/coroutine.cfa (modified) (7 diffs)
-
libcfa/src/concurrency/exception.cfa (modified) (3 diffs)
-
libcfa/src/concurrency/exception.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/invoke.h (modified) (1 diff)
-
libcfa/src/concurrency/io/call.cfa.in (modified) (1 diff)
-
libcfa/src/concurrency/io/setup.cfa (modified) (5 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (13 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (1 diff)
-
libcfa/src/concurrency/kernel/fwd.hfa (modified) (1 diff)
-
libcfa/src/concurrency/kernel/startup.cfa (modified) (6 diffs)
-
libcfa/src/concurrency/kernel_private.hfa (modified) (5 diffs)
-
libcfa/src/concurrency/monitor.cfa (modified) (1 diff)
-
libcfa/src/concurrency/preemption.cfa (modified) (6 diffs)
-
libcfa/src/concurrency/snzi.hfa (modified) (1 diff)
-
libcfa/src/concurrency/thread.cfa (modified) (5 diffs)
-
libcfa/src/concurrency/thread.hfa (modified) (3 diffs)
-
libcfa/src/exception.c (modified) (3 diffs)
-
libcfa/src/exception.h (modified) (4 diffs)
-
libcfa/src/stdhdr/unwind.h (deleted)
-
libcfa/src/stdlib.cfa (modified) (2 diffs)
-
libcfa/src/stdlib.hfa (modified) (1 diff)
-
src/AST/Convert.cpp (modified) (22 diffs)
-
src/AST/Convert.hpp (modified) (1 diff)
-
src/AST/Decl.cpp (modified) (1 diff)
-
src/AST/Decl.hpp (modified) (1 diff)
-
src/AST/DeclReplacer.cpp (modified) (3 diffs)
-
src/AST/DeclReplacer.hpp (modified) (1 diff)
-
src/AST/Expr.cpp (modified) (4 diffs)
-
src/AST/Expr.hpp (modified) (6 diffs)
-
src/AST/Fwd.hpp (modified) (1 diff)
-
src/AST/Node.hpp (modified) (1 diff)
-
src/AST/Pass.hpp (modified) (8 diffs)
-
src/AST/Pass.impl.hpp (modified) (10 diffs)
-
src/AST/Pass.proto.hpp (modified) (1 diff)
-
src/AST/SymbolTable.cpp (modified) (1 diff)
-
src/AST/SymbolTable.hpp (modified) (1 diff)
-
src/AST/TranslationUnit.hpp (deleted)
-
src/AST/Type.cpp (modified) (1 diff)
-
src/AST/Type.hpp (modified) (3 diffs)
-
src/AST/porting.md (modified) (5 diffs)
-
src/Common/PassVisitor.h (modified) (2 diffs)
-
src/Common/PassVisitor.impl.h (modified) (6 diffs)
-
src/Common/utility.h (modified) (1 diff)
-
src/Concurrency/Keywords.cc (modified) (9 diffs)
-
src/GenPoly/GenPoly.cc (modified) (9 diffs)
-
src/GenPoly/GenPoly.h (modified) (4 diffs)
-
src/GenPoly/Specialize.cc (modified) (1 diff)
-
src/InitTweak/FixGlobalInit.cc (modified) (5 diffs)
-
src/InitTweak/FixGlobalInit.h (modified) (2 diffs)
-
src/InitTweak/FixInit.cc (modified) (2 diffs)
-
src/InitTweak/FixInit.h (modified) (1 diff)
-
src/InitTweak/FixInitNew.cpp (deleted)
-
src/InitTweak/GenInit.cc (modified) (1 diff)
-
src/InitTweak/GenInit.h (modified) (1 diff)
-
src/InitTweak/InitTweak.cc (modified) (7 diffs)
-
src/InitTweak/InitTweak.h (modified) (4 diffs)
-
src/InitTweak/module.mk (modified) (1 diff)
-
src/Parser/ParseNode.h (modified) (6 diffs)
-
src/Parser/StatementNode.cc (modified) (2 diffs)
-
src/Parser/parser.yy (modified) (5 diffs)
-
src/ResolvExpr/Resolver.cc (modified) (6 diffs)
-
src/ResolvExpr/Resolver.h (modified) (3 diffs)
-
src/SymTab/Autogen.cc (modified) (2 diffs)
-
src/SymTab/Autogen.h (modified) (1 diff)
-
src/SynTree/Expression.h (modified) (2 diffs)
-
src/main.cc (modified) (1 diff)
-
tests/.expect/castError.oast.txt (deleted)
-
tests/.expect/castError.txt (added)
-
tests/.expect/const-init.txt (modified) (1 diff)
-
tests/Makefile.am (modified) (2 diffs)
-
tests/alloc.cfa (modified) (1 diff)
-
tests/complex.cfa (modified) (1 diff)
-
tests/config.py.in (modified) (1 diff)
-
tests/const-init.cfa (modified) (2 diffs)
-
tests/exceptions/cancel/.expect/thread.txt (deleted)
-
tests/exceptions/cancel/coroutine.cfa (modified) (1 diff)
-
tests/exceptions/cancel/thread.cfa (deleted)
-
tests/exceptions/conditional.cfa (modified) (1 diff)
-
tests/exceptions/except-io.hfa (modified) (1 diff)
-
tests/exceptions/trash.cfa (modified) (1 diff)
-
tests/global-monomorph.cfa (modified) (1 diff)
-
tests/meta/.expect/archVast.nast.arm64.txt (deleted)
-
tests/meta/.expect/archVast.nast.x64.txt (deleted)
-
tests/meta/.expect/archVast.nast.x86.txt (deleted)
-
tests/meta/.expect/archVast.oast.arm64.txt (deleted)
-
tests/meta/.expect/archVast.oast.x64.txt (deleted)
-
tests/meta/.expect/archVast.oast.x86.txt (deleted)
-
tests/meta/archVast.cfa (deleted)
-
tests/poly-d-cycle.cfa (modified) (1 diff)
-
tests/poly-o-cycle.cfa (modified) (1 diff)
-
tests/pybin/settings.py (modified) (4 diffs)
-
tests/pybin/test_run.py (modified) (3 diffs)
-
tests/pybin/tools.py (modified) (1 diff)
-
tests/test.py (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
Jenkins/FullBuild
rc28ea4e r4b30e8cc 17 17 18 18 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' ) }, 21 21 gcc_6_x86: { trigger_build( 'gcc-6', 'x86' ) }, 22 22 gcc_9_x64: { trigger_build( 'gcc-9', 'x64' ) }, -
Jenkinsfile
rc28ea4e r4b30e8cc 127 127 } 128 128 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}" 132 130 133 131 // Configure libcfa … … 361 359 public final CC_Desc Compiler 362 360 public final Arch_Desc Architecture 363 public final Boolean NewAST364 361 public final Boolean RunAllTests 365 362 public final Boolean RunBenchmark … … 413 410 414 411 this.IsSandbox = (branch == "jenkins-sandbox") 415 this.NewAST = param.NewAST416 412 this.RunAllTests = param.RunAllTests 417 413 this.RunBenchmark = param.RunBenchmark … … 474 470 ], \ 475 471 [$class: 'BooleanParameterDefinition', \ 476 description: 'If true, build compiler using new AST', \477 name: 'NewAST', \478 defaultValue: false, \479 ], \480 [$class: 'BooleanParameterDefinition', \481 472 description: 'If false, only the quick test suite is ran', \ 482 473 name: 'RunAllTests', \ 483 474 defaultValue: false, \ 484 ], 475 ], \ 485 476 [$class: 'BooleanParameterDefinition', \ 486 477 description: 'If true, jenkins also runs benchmarks', \ -
configure.ac
rc28ea4e r4b30e8cc 28 28 # New AST toggling support 29 29 AH_TEMPLATE([CFA_USE_NEW_AST],[Sets whether or not to use the new-ast, this is adefault value and can be overrided by --old-ast and --new-ast]) 30 DEFAULT_NEW_AST="False"31 30 AC_ARG_ENABLE(new-ast, 32 31 [ --enable-new-ast whether or not to use new ast as the default AST algorithm], 33 32 [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 ;; 36 35 *) AC_MSG_ERROR([bad value ${enableval} for --enable-new-ast]) ;; 37 36 esac],[newast=false]) 38 37 AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast) 39 AC_SUBST(DEFAULT_NEW_AST)40 38 41 39 #============================================================================== -
doc/papers/concurrency/mail2
rc28ea4e r4b30e8cc 1 2 1 Date: Wed, 26 Jun 2019 20:12:38 +0000 3 2 From: Aaron Thomas <onbehalfof@manuscriptcentral.com> … … 1075 1074 Software: Practice and Experience Editorial Office 1076 1075 1077 1078 1079 Date: Thu, 15 Oct 2020 13:48:52 +00001080 From: Richard Jones <onbehalfof@manuscriptcentral.com>1081 Reply-To: R.E.Jones@kent.ac.uk1082 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca1083 Subject: Software: Practice and Experience - Decision on Manuscript ID1084 SPE-19-0219.R31085 1086 15-Oct-20201087 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 Richard1100 1101 Prof. Richard Jones1102 Editor, Software: Practice and Experience1103 R.E.Jones@kent.ac.uk1104 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 +00001112 From: Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com>1113 Reply-To: speoffice@wiley.com1114 To: pabuhr@uwaterloo.ca1115 Subject: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c]1116 1117 16-Oct-20201118 1119 Dear Dr. Buhr,1120 1121 Manuscript id: SPE-19-0219.R31122 Manuscript title: Advanced Control-flow and Concurrency in Cforall1123 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 document1130 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 Office1147 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 +00001154 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 Regards1164 1165 Mayank Roy Chowdhury1166 Editorial Assistant1167 Software practice and Experience1168 ________________________________1169 From: Peter A. Buhr <pabuhr@uwaterloo.ca>1170 Sent: Sunday, October 18, 2020 2:00 PM1171 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 the1188 final version of the PDF and source files using the mechanism on the "File1189 Upload" page and submitted that.1190 1191 1192 1193 Date: Tue, 20 Oct 2020 13:28:37 +05301194 To: "Dr. Peter Buhr" <pabuhr@uwaterloo.ca>1195 From: jpcms@spi-global.com1196 Subject: Information: Production Editor Contact Software:Practice and Experience | Advanced Control-flow and Concurrency in C A1197 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 Wiley1207 1208 Article ID: SPE_29251209 Article DOI: 10.1002/SPE.29251210 1211 1212 1213 Date: Tue, 20 Oct 2020 10:33:04 +00001214 From: <cs-author@wiley.com>1215 To: <pabuhr@uwaterloo.ca>1216 Subject: In Production: Your article accepted in Software: Practice and Experience1217 1218 Dear Peter Buhr,1219 1220 Article ID: SPE29251221 Article DOI: 10.1002/spe.29251222 Internal Article ID: 169222131223 Article: Advanced Control-flow and Concurrency in C A1224 Journal: Software: Practice and Experience1225 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-new1233 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 article1237 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 Services1241 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 +00001247 From: <cs-author@wiley.com>1248 To: <pabuhr@uwaterloo.ca>1249 Subject: You have actions to complete in Author Services1250 1251 Dear Peter Buhr,1252 1253 Article ID: SPE29251254 Article DOI: 10.1002/spe.29251255 Internal Article ID: 169222131256 Article: Advanced Control-flow and Concurrency in C A1257 Journal: Software: Practice and Experience1258 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 Services1267 1268 1269 1270 Date: Thu, 22 Oct 2020 23:13:07 +00001271 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: SPE29251278 Article DOI: 10.1002/spe.29251279 Internal Article ID: 169222131280 Article: Advanced Control-flow and Concurrency in C A1281 Journal: Software: Practice and Experience1282 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 512 512 possibly like the one used to create the assertion. 513 513 514 ### Extension: Associated Types Use515 If the `associated_types.md` proposal is accepted the following trait could516 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 find525 the (possibly default) virtual table. It is required to construct instances526 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 the535 user has to explicately provide the table's name as it doesn't really have its536 own type name. If it does it is probably mangled.537 538 514 ### Virtual Tables as Types 539 515 Here we consider encoding plus the implementation of functions on it to be a -
doc/theses/andrew_beach_MMath/thesis-frontpgs.tex
rc28ea4e r4b30e8cc 5 5 % TITLE PAGE 6 6 %---------------------------------------------------------------------- 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 }15 7 16 8 \pagestyle{empty} … … 23 15 \vspace*{1.0cm} 24 16 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 29 23 by \\ 30 24 31 25 \vspace*{1.0cm} 32 26 33 {\Large \eprint{author}} \\ 27 \Large 28 Pat Neugraad \\ 34 29 35 30 \vspace*{3.0cm} 36 31 32 \normalsize 37 33 A thesis \\ 38 34 presented to the University of Waterloo \\ 39 35 in fulfillment of the \\ 40 36 thesis requirement for the degree of \\ 41 \eprint{degree}\\37 Doctor of Philosophy \\ 42 38 in \\ 43 \eprint{program}\\39 Zoology \\ 44 40 45 41 \vspace*{2.0cm} … … 49 45 \vspace*{1.0cm} 50 46 51 \copyright {} \eprint{author}2017 \\47 \copyright\ Pat Neugraad 2017 \\ 52 48 \end{center} 53 49 \end{titlepage} -
doc/theses/andrew_beach_MMath/uw-ethesis.cls
rc28ea4e r4b30e8cc 19 19 % 20 20 % Exported Names: 21 % \ethesissetup{<key-value-pairs>}22 % Preforms set-up (or a reconfiguration) of the document class. See the23 % Set-Up Keys section for the keys that may be passed in. Use commas to24 % seperate key-value-pairs.25 %26 21 % \ifformat{<format>}{<true>}{<false>} 27 22 % If the document's format is <format> than expands to <true> otherwise … … 32 27 % initial setup depends on the document format but they can be overriden 33 28 % 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. This37 % 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|phd46 % faculty=ahs|arts|eng|env|math|sci47 29 \NeedsTeXFormat{LaTeX2e} 48 \ProvidesClass{uw-ethesis}[2020/ 10/25 v0.2UW-eThesis Template Document Class]30 \ProvidesClass{uw-ethesis}[2020/03/24 v0.1 UW-eThesis Template Document Class] 49 31 50 32 \RequirePackage{etoolbox} 51 \RequirePackage{xkeyval}52 33 53 34 % 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}} 57 38 58 39 \ProcessOptions\relax … … 100 81 % a recto page. This will often require an empty verso (left-hand side) page 101 82 % that should not have the page number printed on it. 102 \let\ ethesis@origdoublepage\cleardoublepage83 \let\origdoublepage\cleardoublepage 103 84 \newcommand{\clearemptydoublepage}{% 104 \clearpage{\pagestyle{empty}\ ethesis@origdoublepage}}85 \clearpage{\pagestyle{empty}\origdoublepage}} 105 86 \let\cleardoublepage\clearemptydoublepage 106 87 … … 108 89 \renewcommand*{\bibname}{References} 109 90 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}} 130 96 131 97 % Includes the hyperref package loading a number of defaults. … … 140 106 pdfstartview={FitH}, % Fits the width of the page to the window. 141 107 } 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}}}{} 146 112 \ifformat{print}{ 147 113 \hypersetup{ -
doc/theses/thierry_delisle_PhD/comp_II/presentation.tex
rc28ea4e r4b30e8cc 36 36 \miniframeson 37 37 } 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} 45 39 \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 ~\newline50 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}56 40 57 41 \end{frame} … … 120 104 \begin{frame}{Priority Scheduling} 121 105 \begin{center} 122 {\large106 {\large 123 107 Runs all ready threads in group \textit{A} before any ready threads in group \textit{B}. 124 108 } … … 152 136 153 137 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 \newline161 162 \begin{itemize}163 \item Inappropriate for short lived threads.164 \item Overkill for cooperating threads.\newline165 \end{itemize}166 \end{column}167 \begin{column}{0.5\textwidth}168 \textbf{Priority Scheduling}169 \newline170 171 \begin{itemize}172 \item Allows lasting starvation.\newline173 \item Hard to reason about.\newline~\newline174 \end{itemize}175 \end{column}176 \end{columns}177 178 ~\newline179 ~\newline180 \CFA would benefit from something different.181 138 \end{frame} 182 139 %============================== … … 233 190 \begin{itemize} 234 191 \item Acquire for reading for normal scheduling operations. 235 \item Acquire for writingwhen resizing the array and creating/deleting internal queues.192 \item Acquire for right when resizing the array and creating/deleting internal queues. 236 193 \end{itemize} 237 194 \end{frame} … … 357 314 Runtime system and scheduling are still open topics. 358 315 \newline 359 \newline360 316 361 317 This work offers a novel runtime and scheduling package. 362 \newline363 318 \newline 364 319 … … 381 336 382 337 %------------------------------ 383 \begin{frame}{ }338 \begin{frame}{Timeline} 384 339 \begin{center} 385 340 {\large Questions?} -
doc/theses/thierry_delisle_PhD/comp_II/presentationstyle.sty
rc28ea4e r4b30e8cc 20 20 \setbeamertemplate{blocks}[rounded][shadow=false] 21 21 \newcommand\xrowht[2][0]{\addstackgap[.5\dimexpr#2\relax]{\vphantom{#1}}} 22 \setbeamertemplate{sections/subsections in toc}{\inserttocsectionnumber.~\inserttocsection}23 22 24 23 %============================== … … 37 36 \setbeamercolor{palette primary}{bg=colbg} 38 37 \setbeamercolor{palette tertiary}{fg=red} 39 \setbeamercolor{section in toc}{fg=white}40 \setbeamercolor{subsection in toc}{fg=gray}41 38 42 39 %============================== -
doc/theses/thierry_delisle_PhD/thesis/Makefile
rc28ea4e r4b30e8cc 15 15 front \ 16 16 intro \ 17 existing \18 17 runtime \ 19 18 core \ … … 28 27 base \ 29 28 empty \ 30 system \31 29 } 32 30 … … 39 37 ## Define the documents that need to be made. 40 38 all: thesis.pdf 41 thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} glossary.tex local.bib39 thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} glossary.tex 42 40 43 41 DOCUMENT = thesis.pdf -
doc/theses/thierry_delisle_PhD/thesis/fig/system.fig
rc28ea4e r4b30e8cc 1 #FIG 3.2 Produced by xfig version 3.2. 7b1 #FIG 3.2 Produced by xfig version 3.2.5c 2 2 Landscape 3 3 Center … … 36 36 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4500 3600 15 15 4500 3600 4515 3615 37 37 -6 38 6 3225 4125 4650 4425 39 6 4350 4200 4650 4350 40 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4425 4275 15 15 4425 4275 4440 4290 41 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4500 4275 15 15 4500 4275 4515 4290 42 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4575 4275 15 15 4575 4275 4590 4290 43 -6 44 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3450 4275 225 150 3450 4275 3675 4425 45 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 4275 225 150 4050 4275 4275 4425 46 -6 47 6 6675 4125 7500 4425 48 6 7200 4200 7500 4350 49 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7275 4275 15 15 7275 4275 7290 4290 50 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7350 4275 15 15 7350 4275 7365 4290 51 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7425 4275 15 15 7425 4275 7440 4290 52 -6 53 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6900 4275 225 150 6900 4275 7125 4425 54 -6 38 55 6 6675 3525 8025 3975 39 56 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2 … … 62 79 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3975 2850 150 150 3975 2850 4125 2850 63 80 1 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 48 3081 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 4860 65 82 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 7200 2775 30 30 7200 2775 7230 2805 66 83 1 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 84 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3875 4800 100 100 3875 4800 3975 4800 85 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 4800 150 75 4650 4800 4800 4875 68 86 2 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5 69 87 2400 4200 2400 3750 1950 3750 1950 4200 2400 4200 … … 135 153 1 1 1.00 45.00 90.00 136 154 7875 3750 7875 2325 7200 2325 7200 2550 155 2 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 137 157 2 2 1 1 -1 -1 0 0 -1 3.000 0 0 0 0 0 5 138 158 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 159 4 1 -1 0 0 0 10 0.0000 2 105 720 5550 4425 Processors\001 160 4 1 -1 0 0 0 10 0.0000 2 120 1005 4200 3225 Blocked Tasks\001 161 4 1 -1 0 0 0 10 0.0000 2 150 870 4200 3975 Ready Tasks\001 162 4 1 -1 0 0 0 10 0.0000 2 135 1095 7350 1725 Other Cluster(s)\001 163 4 1 -1 0 0 0 10 0.0000 2 105 840 4650 1725 User Cluster\001 164 4 1 -1 0 0 0 10 0.0000 2 150 615 2175 3675 Manager\001 165 4 1 -1 0 0 0 10 0.0000 2 105 990 2175 3525 Discrete-event\001 166 4 1 -1 0 0 0 10 0.0000 2 135 795 2175 4350 preemption\001 167 4 0 -1 0 0 0 10 0.0000 2 150 1290 2325 4875 generator/coroutine\001 168 4 0 -1 0 0 0 10 0.0000 2 120 270 4050 4875 task\001 169 4 0 -1 0 0 0 10 0.0000 2 105 450 7050 4875 cluster\001 170 4 0 -1 0 0 0 10 0.0000 2 105 660 5925 4875 processor\001 171 4 0 -1 0 0 0 10 0.0000 2 105 555 4875 4875 monitor\001 -
doc/theses/thierry_delisle_PhD/thesis/glossary.tex
rc28ea4e r4b30e8cc 1 1 \makeglossaries 2 2 3 % ---------------------------------- 4 % Acronyms 5 \newacronym{api}{API}{Application Programming Interface} 6 \newacronym{fifo}{FIFO}{First-In, First-Out} 7 \newacronym{io}{I/O}{Input and Output} 8 \newacronym{numa}{NUMA}{Non-Uniform Memory Access} 9 \newacronym{raii}{RAII}{Resource Acquisition Is Initialization} 10 \newacronym{tls}{TLS}{Thread Local Storage} 3 \longnewglossaryentry{hthrd} 4 {name={hardware thread}} 5 { 6 Threads representing the underlying hardware directly. 11 7 12 % ---------------------------------- 13 % Definitions 8 \textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.} 9 } 14 10 15 11 \longnewglossaryentry{thrd} 16 {name={thread }}12 {name={threads}} 17 13 { 18 14 Threads created and managed inside user-space. Each thread has its own stack and its own thread of execution. User-level threads are invisible to the underlying operating system. 19 15 20 16 \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 : }51 17 } 52 18 … … 91 57 } 92 58 59 \longnewglossaryentry{proc} 60 {name={virtual processor}} 61 { 93 62 63 } 64 65 \longnewglossaryentry{Q} 66 {name={work-queue}} 67 { 68 69 } 94 70 95 71 \longnewglossaryentry{at} … … 155 131 } 156 132 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 1 1 \chapter{Scheduling Core}\label{core} 2 2 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. 3 This chapter addresses the need of scheduling on a somewhat ideal scenario 4 4 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} 6 7 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} 9 9 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} 30 11 31 12 \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} rea13 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}. 33 14 34 15 \subsection{Sharding} … … 38 19 \input{base.pstex_t} 39 20 \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.} 41 23 \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.44 24 \end{figure} 45 25 … … 48 28 Indeed, if the number of \glspl{thrd} does not far exceed the number of queues, it is probable that several of these queues are empty. 49 29 Figure~\ref{fig:empty} shows an example with 2 \glspl{thrd} running on 8 queues, where the chances of getting an empty queue is 75\% per pick, meaning two random picks yield a \gls{thrd} only half the time. 30 This can lead to performance problems since picks that do not yield a \gls{thrd} are not useful and do not necessarily help make more informed guesses. 31 32 Solutions to this problem can take many forms, but they ultimately all have to encode where the threads are in some form. My results show that the density and locality of this encoding is generally the dominating factor in these scheme. 33 34 \paragraph{Dense Information} 35 36 37 50 38 51 39 … … 54 42 \input{empty.pstex_t} 55 43 \end{center} 56 \caption{``More empty'' Relaxed FIFO list}44 \caption{``More empty'' state of the queue: the array contains many empty cells.} 57 45 \label{fig:empty} 58 Emptier state of the queue: the array contains many empty cells, that is strictly FIFO lists containing no elements.59 46 \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 184 184 \phantomsection % allows hyperref to link to the correct page 185 185 186 % TODOs and missing citations187 % -----------------------------188 186 \listofcits 189 187 \listoftodos 190 \cleardoublepage191 \phantomsection % allows hyperref to link to the correct page192 188 193 189 -
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} 3 2 4 3 \section{Existing options} 5 Since \glsxtrshort{io} operations are generally handled by the6 4 7 5 \subsection{\texttt{epoll}, \texttt{poll} and \texttt{select}} … … 9 7 \subsection{Linux's AIO} 10 8 9 \subsection{\texttt{io\_uring}} 11 10 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} 39 12 40 13 \subsection{Discussion} -
doc/theses/thierry_delisle_PhD/thesis/text/practice.tex
rc28ea4e r4b30e8cc 2 2 The scheduling algorithm discribed in Chapter~\ref{core} addresses scheduling in a stable state. 3 3 However, 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. 4 Indeed the \CFA runtime, supports expanding and shrinking 5 6 the number of KTHREAD\_place 7 8 , both manually and, to some extent automatically. 5 9 This entails that the scheduling algorithm must support these transitions. 6 10 -
doc/theses/thierry_delisle_PhD/thesis/text/runtime.tex
rc28ea4e r4b30e8cc 1 1 \chapter{\CFA Runtime} 2 This chapter offers an overview of the capabilities of the \CFA runtime prior to this work.3 2 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} 11 4 12 5 \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.32 6 33 7 \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 121 121 % installation instructions there. 122 122 123 \usepackage{csquotes}124 \usepackage{indentfirst} % as any self-respecting frenchman would125 126 123 % Setting up the page margins... 127 124 % uWaterloo thesis requirements specify a minimum of 1 inch (72pt) margin at the … … 221 218 % separate documents, they would each start with the \chapter command, i.e, 222 219 % do not contain \documentclass or \begin{document} and \end{document} commands. 223 \part{Introduction}224 220 \input{text/intro.tex} 225 \input{text/existing.tex}226 221 \input{text/runtime.tex} 227 \part{Design}228 222 \input{text/core.tex} 229 223 \input{text/practice.tex} 230 224 \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}236 225 237 226 %---------------------------------------------------------------------- … … 256 245 \addcontentsline{toc}{chapter}{\textbf{References}} 257 246 258 \bibliography{ local}247 \bibliography{uw-ethesis} 259 248 % Tip 5: You can create multiple .bib files to organize your references. 260 249 % Just list them all in the \bibliogaphy command, separated by commas (no spaces). 261 250 262 % %The following statement causes the specified references to be added to the bibliography% even if they were not263 % %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{*} 265 254 266 255 % The \appendix statement indicates the beginning of the appendices. -
libcfa/prelude/builtins.c
rc28ea4e r4b30e8cc 9 9 // Author : Peter A. Buhr 10 10 // Created On : Fri Jul 21 16:21:03 2017 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue Oct 27 14:42:00202013 // Update Count : 11 111 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Oct 9 18:26:19 2020 13 // Update Count : 110 14 14 // 15 16 #define __cforall_builtins__17 15 18 16 // 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 59 59 void cfathread_setproccnt( int ncnt ) { 60 60 assert( ncnt >= 1 ); 61 adelete( procs);61 adelete(proc_cnt, procs); 62 62 63 63 proc_cnt = ncnt - 1; -
libcfa/src/concurrency/coroutine.cfa
rc28ea4e r4b30e8cc 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Oct 23 23:05:24202013 // Update Count : 2 212 // Last Modified On : Tue May 26 22:06:09 2020 13 // Update Count : 21 14 14 // 15 15 … … 24 24 #include <unistd.h> 25 25 #include <sys/mman.h> // mprotect 26 extern "C" { 27 // use this define to make unwind.h play nice, definitely a hack 28 #define HIDE_EXPORTS 26 29 #include <unwind.h> 30 #undef HIDE_EXPORTS 31 } 27 32 28 33 #include "kernel_private.hfa" 29 #include "exception.hfa"30 34 31 35 #define __CFA_INVOKE_PRIVATE__ … … 45 49 FORALL_DATA_INSTANCE(CoroutineCancelled, (dtype coroutine_t), (coroutine_t)) 46 50 51 struct __cfaehm_node { 52 struct _Unwind_Exception unwind_exception; 53 struct __cfaehm_node * next; 54 int handler_index; 55 }; 56 47 57 forall(dtype T) 48 58 void mark_exception(CoroutineCancelled(T) *) {} … … 50 60 forall(dtype T) 51 61 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) { 52 dst->virtual_table = src->virtual_table;53 62 dst->the_coroutine = src->the_coroutine; 54 63 dst->the_exception = src->the_exception; … … 65 74 verify( desc->cancellation ); 66 75 desc->state = Cancelled; 67 exception_t * except = __cfaehm_cancellation_exception( desc->cancellation);76 exception_t * except = (exception_t *)(1 + (__cfaehm_node *)desc->cancellation); 68 77 69 78 // TODO: Remove explitate vtable set once trac#186 is fixed. … … 83 92 84 93 // minimum feasible stack size in bytes 85 static const size_t MinStackSize = 1000; 94 #define MinStackSize 1000 86 95 extern size_t __page_size; // architecture pagesize HACK, should go in proper runtime singleton 87 96 … … 208 217 size = libFloor(create_size - stack_data_size - diff, libAlign()); 209 218 } // 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 ); 211 220 212 221 this->storage = (__stack_t *)((intptr_t)storage + size); -
libcfa/src/concurrency/exception.cfa
rc28ea4e r4b30e8cc 10 10 // Created On : Mon Aug 17 10:41:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Oct 28 14:34:00 202013 // Update Count : 112 // Last Modified On : Tue Aug 25 14:41:00 2020 13 // Update Count : 0 14 14 // 15 15 16 #define __cforall_thread__ 16 extern "C" { 17 // use this define to make unwind.h play nice, definitely a hack 18 #define HIDE_EXPORTS 19 #include <unwind.h> 20 #undef HIDE_EXPORTS 21 } 17 22 23 #include "invoke.h" 18 24 #include "exception.hfa" 19 20 25 #include "coroutine.hfa" 21 26 22 27 extern struct $thread * mainThread; 23 extern "C" {24 extern void __cfactx_thrd_leave();25 }26 28 27 29 // Common pattern for all the stop functions, wait until the end then act. … … 50 52 51 53 STOP_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(); 54 56 ) 55 57 … … 83 85 stop_param = (void *)0x22; 84 86 } else { 85 this_thread->self_cor.cancellation = unwind_exception;86 87 87 stop_func = thread_cancelstop; 88 88 stop_param = this_thread; -
libcfa/src/concurrency/exception.hfa
rc28ea4e r4b30e8cc 16 16 #pragma once 17 17 18 // This is an internal bridge between the two modes and must be C compatable.19 20 #include <unwind.h>21 18 #include "bits/defs.hfa" 22 19 #include "invoke.h" 23 #include "exception.h"24 20 25 21 #ifdef __cforall 26 22 extern "C" { 23 24 #define HIDE_EXPORTS 27 25 #endif 26 #include "unwind.h" 28 27 29 28 struct exception_context_t * this_exception_context(void) OPTIONAL_THREAD; … … 33 32 34 33 #ifdef __cforall 34 #undef HIDE_EXPORTS 35 35 } 36 36 #endif -
libcfa/src/concurrency/invoke.h
rc28ea4e r4b30e8cc 157 157 158 158 // current execution status for coroutine 159 // Possible values are:160 // - TICKET_BLOCKED (-1) thread is blocked161 // - TICKET_RUNNING ( 0) thread is running162 // - TICKET_UNBLOCK ( 1) thread should ignore next block163 159 volatile int ticket; 164 160 enum __Coroutine_State state:8; -
libcfa/src/concurrency/io/call.cfa.in
rc28ea4e r4b30e8cc 47 47 #include "kernel/fwd.hfa" 48 48 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 75 82 76 83 extern [* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ); -
libcfa/src/concurrency/io/setup.cfa
rc28ea4e r4b30e8cc 149 149 id.full_proc = false; 150 150 id.id = doregister(&id); 151 kernelTLS.this_proc_id = &id;152 151 __cfaabi_dbg_print_safe( "Kernel : IO poller thread starting\n" ); 153 152 … … 181 180 kernelTLS.this_stats = io_ctx->self.curr_cluster->stats; 182 181 #endif 183 post( io_ctx->sem);182 __post( io_ctx->sem, &id ); 184 183 } 185 184 } … … 236 235 if( thrd.state == Ready || thrd.preempted != __NO_PREEMPTION ) { 237 236 238 ready_schedule_lock( );237 ready_schedule_lock( (struct __processor_id_t *)active_processor() ); 239 238 240 239 // This is the tricky case … … 251 250 // Fixup the thread state 252 251 thrd.state = Blocked; 253 thrd.ticket = TICKET_BLOCKED;252 thrd.ticket = 0; 254 253 thrd.preempted = __NO_PREEMPTION; 255 254 256 ready_schedule_unlock( );255 ready_schedule_unlock( (struct __processor_id_t *)active_processor() ); 257 256 258 257 // Pretend like the thread was blocked all along … … 276 275 } 277 276 } else { 278 post( this.thrd.sem);277 unpark( &thrd ); 279 278 } 280 279 -
libcfa/src/concurrency/kernel.cfa
rc28ea4e r4b30e8cc 108 108 static $thread * __next_thread_slow(cluster * this); 109 109 static void __run_thread(processor * this, $thread * dst); 110 static void __wake_one( cluster * cltr);110 static void __wake_one(struct __processor_id_t * id, cluster * cltr); 111 111 112 112 static void push (__cluster_idles & idles, processor & proc); … … 252 252 /* paranoid */ verify( kernelTLS.this_thread == thrd_dst ); 253 253 /* paranoid */ verify( thrd_dst->context.SP ); 254 /* paranoid */ verify( thrd_dst->state != Halted );255 254 /* 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 256 255 /* 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 … … 282 281 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) { 283 282 // The thread was preempted, reschedule it and reset the flag 284 __schedule_thread( thrd_dst );283 __schedule_thread( (__processor_id_t*)this, thrd_dst ); 285 284 break RUNNING; 286 285 } … … 288 287 if(unlikely(thrd_dst->state == Halted)) { 289 288 // 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; 292 292 break RUNNING; 293 293 } … … 299 299 int old_ticket = __atomic_fetch_sub(&thrd_dst->ticket, 1, __ATOMIC_SEQ_CST); 300 300 switch(old_ticket) { 301 case TICKET_RUNNING:301 case 1: 302 302 // This is case 1, the regular case, nothing more is needed 303 303 break RUNNING; 304 case TICKET_UNBLOCK:304 case 2: 305 305 // This is case 2, the racy case, someone tried to run this thread before it finished blocking 306 306 // In this case, just run it again. … … 358 358 // Scheduler routines 359 359 // KERNEL ONLY 360 void __schedule_thread( $thread * thrd ) {360 void __schedule_thread( struct __processor_id_t * id, $thread * thrd ) { 361 361 /* paranoid */ verify( thrd ); 362 362 /* paranoid */ verify( thrd->state != Halted ); 363 363 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 364 /* paranoid */ verify( kernelTLS.this_proc_id );365 364 /* paranoid */ #if defined( __CFA_WITH_VERIFY__ ) 366 365 /* paranoid */ if( thrd->state == Blocked || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION, … … 375 374 if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready; 376 375 377 ready_schedule_lock ();376 ready_schedule_lock ( id ); 378 377 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 ); 381 380 382 381 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); … … 385 384 // KERNEL ONLY 386 385 static 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 ); 391 389 $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 ); 396 393 return thrd; 397 394 } … … 399 396 // KERNEL ONLY 400 397 static 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 ); 405 401 $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 ); 410 405 return thrd; 411 406 } 412 407 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 409 void __unpark( struct __processor_id_t * id, $thread * thrd ) { 421 410 int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST); 422 411 switch(old_ticket) { 423 case TICKET_RUNNING:412 case 1: 424 413 // Wake won the race, the thread will reschedule/rerun itself 425 414 break; 426 case TICKET_BLOCKED:415 case 0: 427 416 /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION ); 428 417 /* paranoid */ verify( thrd->state == Blocked ); 429 418 430 419 // Wake lost the race, 431 __schedule_thread( thrd );420 __schedule_thread( id, thrd ); 432 421 break; 433 422 default: 434 423 // 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 428 void unpark( $thread * thrd ) { 429 if( !thrd ) return; 430 431 disable_interrupts(); 432 __unpark( (__processor_id_t*)kernelTLS.this_processor, thrd ); 433 enable_interrupts( __cfaabi_dbg_ctx ); 441 434 } 442 435 … … 455 448 } 456 449 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 451 void __leave_thread() { 452 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 453 returnToKernel(); 454 abort(); 481 455 } 482 456 … … 512 486 //============================================================================================= 513 487 // 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( ) );488 static void __wake_one(struct __processor_id_t * id, cluster * this) { 489 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 490 /* paranoid */ verify( ready_schedule_islocked( id ) ); 517 491 518 492 // Check if there is a sleeping processor … … 532 506 #endif 533 507 534 /* paranoid */ verify( ready_schedule_islocked( ) );508 /* paranoid */ verify( ready_schedule_islocked( id ) ); 535 509 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 536 510 … … 735 709 this.print_halts = true; 736 710 } 737 738 void print_stats_now( cluster & this, int flags ) {739 __print_stats( this.stats, this.print_stats, true, this.name, (void*)&this );740 }741 711 #endif 742 712 // Local Variables: // -
libcfa/src/concurrency/kernel.hfa
rc28ea4e r4b30e8cc 79 79 // Handle to pthreads 80 80 pthread_t kernel_thread; 81 82 // RunThread data 83 // Action to do after a thread is ran 84 $thread * destroyer; 81 85 82 86 // Preemption data -
libcfa/src/concurrency/kernel/fwd.hfa
rc28ea4e r4b30e8cc 35 35 extern "Cforall" { 36 36 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; 41 40 42 41 struct { -
libcfa/src/concurrency/kernel/startup.cfa
rc28ea4e r4b30e8cc 122 122 NULL, 123 123 NULL, 124 NULL,125 124 { 1, false, false }, 126 125 }; … … 213 212 //initialize the global state variables 214 213 kernelTLS.this_processor = mainProcessor; 215 kernelTLS.this_proc_id = (__processor_id_t*)mainProcessor;216 214 kernelTLS.this_thread = mainThread; 217 215 … … 229 227 // Add the main thread to the ready queue 230 228 // 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); 232 230 233 231 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX … … 326 324 processor * proc = (processor *) arg; 327 325 kernelTLS.this_processor = proc; 328 kernelTLS.this_proc_id = (__processor_id_t*)proc;329 326 kernelTLS.this_thread = 0p; 330 327 kernelTLS.preemption_state.[enabled, disable_count] = [false, 1]; … … 444 441 445 442 static void ?{}( $thread & this, current_stack_info_t * info) with( this ) { 446 ticket = TICKET_RUNNING;443 ticket = 1; 447 444 state = Start; 448 445 self_cor{ info }; … … 477 474 this.cltr = &_cltr; 478 475 full_proc = true; 476 destroyer = 0p; 479 477 do_terminate = false; 480 478 preemption_alarm = 0p; -
libcfa/src/concurrency/kernel_private.hfa
rc28ea4e r4b30e8cc 33 33 } 34 34 35 void __schedule_thread( $thread * )35 void __schedule_thread( struct __processor_id_t *, $thread * ) 36 36 #if defined(NDEBUG) || (!defined(__CFA_DEBUG__) && !defined(__CFA_VERIFY__)) 37 __attribute__((nonnull ( 1)))37 __attribute__((nonnull (2))) 38 38 #endif 39 39 ; 40 40 41 // release/wake-up the following resources42 void __ thread_finish( $thread * thrd);41 //Block current thread and release/wake-up the following resources 42 void __leave_thread() __attribute__((noreturn)); 43 43 44 44 //----------------------------------------------------------------------------- … … 63 63 ) 64 64 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 66 void __unpark( struct __processor_id_t *, $thread * thrd ); 67 68 static inline bool __post(single_sem & this, struct __processor_id_t * id) { 69 for() { 70 struct $thread * expected = this.ptr; 71 if(expected == 1p) return false; 72 if(expected == 0p) { 73 if(__atomic_compare_exchange_n(&this.ptr, &expected, 1p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 74 return false; 75 } 76 } 77 else { 78 if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 79 __unpark( id, expected ); 80 return true; 81 } 82 } 83 } 84 } 68 85 69 86 //----------------------------------------------------------------------------- … … 180 197 // Reader side : acquire when using the ready queue to schedule but not 181 198 // 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); 199 static inline void ready_schedule_lock( struct __processor_id_t * proc) with(*__scheduler_lock) { 200 unsigned iproc = proc->id; 201 /*paranoid*/ verify(data[iproc].handle == proc); 187 202 /*paranoid*/ verify(iproc < ready); 188 203 … … 206 221 } 207 222 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); 223 static inline void ready_schedule_unlock( struct __processor_id_t * proc) with(*__scheduler_lock) { 224 unsigned iproc = proc->id; 225 /*paranoid*/ verify(data[iproc].handle == proc); 213 226 /*paranoid*/ verify(iproc < ready); 214 227 /*paranoid*/ verify(data[iproc].lock); … … 222 235 223 236 #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) { 227 238 return __scheduler_lock->data[proc->id].owned; 228 239 } -
libcfa/src/concurrency/monitor.cfa
rc28ea4e r4b30e8cc 281 281 } 282 282 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 ); 283 extern "C" { 284 // Leave the thread monitor 285 // last routine called by a thread. 286 // Should never return 287 void __cfactx_thrd_leave() { 288 $thread * thrd = TL_GET( this_thread ); 289 $monitor * this = &thrd->self_mon; 290 291 // Lock the monitor now 292 lock( this->lock __cfaabi_dbg_ctx2 ); 293 294 disable_interrupts(); 295 296 thrd->state = Halted; 297 298 /* paranoid */ verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this ); 299 300 // Leaving a recursion level, decrement the counter 301 this->recursion -= 1; 302 303 // If we haven't left the last level of recursion 304 // it must mean there is an error 305 if( this->recursion != 0) { abort( "Thread internal monitor has unbalanced recursion" ); } 306 307 // Fetch the next thread, can be null 308 $thread * new_owner = next_thread( this ); 309 310 // Release the monitor lock 311 unlock( this->lock ); 312 313 // Unpark the next owner if needed 314 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this ); 315 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 316 /* paranoid */ verify( ! kernelTLS.this_processor->destroyer ); 317 /* paranoid */ verify( thrd->state == Halted ); 318 319 kernelTLS.this_processor->destroyer = new_owner; 320 321 // Leave the thread 322 __leave_thread(); 323 324 // Control flow should never reach here! 325 } 326 } 327 328 // Join a thread 329 forall( dtype T | is_thread(T) ) 330 T & join( T & this ) { 331 $monitor * m = get_monitor(this); 332 void (*dtor)(T& mutex this) = ^?{}; 333 monitor_dtor_guard_t __guard = { &m, (fptr_t)dtor, true }; 334 { 335 return this; 336 } 308 337 } 309 338 -
libcfa/src/concurrency/preemption.cfa
rc28ea4e r4b30e8cc 38 38 // FwdDeclarations : timeout handlers 39 39 static void preempt( processor * this ); 40 static void timeout( $thread * this );40 static void timeout( struct __processor_id_t * id, $thread * this ); 41 41 42 42 // FwdDeclarations : Signal handlers … … 91 91 92 92 // Tick one frame of the Discrete Event Simulation for alarms 93 static void tick_preemption( void) {93 static void tick_preemption( struct __processor_id_t * id ) { 94 94 alarm_node_t * node = 0p; // Used in the while loop but cannot be declared in the while condition 95 95 alarm_list_t * alarms = &event_kernel->alarms; // Local copy for ease of reading … … 109 109 } 110 110 else if( node->type == User ) { 111 timeout( node->thrd );111 timeout( id, node->thrd ); 112 112 } 113 113 else { 114 114 bool unpark_thd = node->callback(*node); 115 if (unpark_thd) timeout( node->thrd );115 if (unpark_thd) timeout( id, node->thrd ); 116 116 } 117 117 … … 274 274 275 275 // reserved for future use 276 static void timeout( $thread * this ) {276 static void timeout( struct __processor_id_t * id, $thread * this ) { 277 277 #if !defined( __CFA_NO_STATISTICS__ ) 278 278 kernelTLS.this_stats = this->curr_cluster->stats; 279 279 #endif 280 unpark(this );280 __unpark( id, this ); 281 281 } 282 282 … … 417 417 id.full_proc = false; 418 418 id.id = doregister(&id); 419 kernelTLS.this_proc_id = &id;420 419 421 420 // Block sigalrms to control when they arrive … … 463 462 // __cfaabi_dbg_print_safe( "Kernel : Preemption thread tick\n" ); 464 463 lock( event_kernel->lock __cfaabi_dbg_ctx2 ); 465 tick_preemption( );464 tick_preemption( &id ); 466 465 unlock( event_kernel->lock ); 467 466 break; -
libcfa/src/concurrency/snzi.hfa
rc28ea4e r4b30e8cc 36 36 static inline void depart( __snzi_node_t & ); 37 37 38 static const int __snzi_half = -1; 38 #define __snzi_half -1 39 39 40 40 //-------------------------------------------------- -
libcfa/src/concurrency/thread.cfa
rc28ea4e r4b30e8cc 19 19 20 20 #include "kernel_private.hfa" 21 #include "exception.hfa"22 21 23 22 #define __CFA_INVOKE_PRIVATE__ … … 29 28 context{ 0p, 0p }; 30 29 self_cor{ name, storage, storageSize }; 31 ticket = TICKET_RUNNING;30 ticket = 1; 32 31 state = Start; 33 32 preempted = __NO_PREEMPTION; … … 59 58 } 60 59 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 117 60 //----------------------------------------------------------------------------- 118 61 // Starting and stopping threads … … 127 70 verify( this_thrd->context.SP ); 128 71 129 __schedule_thread( this_thrd);72 __schedule_thread( (__processor_id_t *)kernelTLS.this_processor, this_thrd); 130 73 enable_interrupts( __cfaabi_dbg_ctx ); 131 74 } … … 150 93 } 151 94 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 159 95 // Local Variables: // 160 96 // mode: c // -
libcfa/src/concurrency/thread.hfa
rc28ea4e r4b30e8cc 22 22 #include "kernel.hfa" 23 23 #include "monitor.hfa" 24 #include "exception.hfa"25 24 26 25 //----------------------------------------------------------------------------- 27 26 // thread trait 28 27 trait 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); 32 31 }; 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) *);44 32 45 33 // define that satisfies the trait without using the thread keyword … … 77 65 static inline void ?{}($thread & this, const char * const name, struct cluster & cl ) { this{ name, cl, 0p, 65000 }; } 78 66 static inline void ?{}($thread & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; } 79 80 struct thread_dtor_guard_t {81 monitor_dtor_guard_t mg;82 };83 84 forall( dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )85 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );86 void ^?{}( thread_dtor_guard_t & this );87 67 88 68 //----------------------------------------------------------------------------- … … 128 108 //---------- 129 109 // join 130 forall( dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))110 forall( dtype T | is_thread(T) ) 131 111 T & join( T & this ); 132 112 -
libcfa/src/exception.c
rc28ea4e r4b30e8cc 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue Oct 27 16:27:00202013 // Update Count : 3 511 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Aug 29 15:52:22 2020 13 // Update Count : 34 14 14 // 15 15 … … 17 17 #include <stddef.h> // for size_t 18 18 19 #include <unwind.h> // for struct _Unwind_Exception {...};20 21 19 #include "exception.h" 22 20 23 21 #include <stdlib.h> 24 22 #include <stdio.h> 23 #include <unwind.h> 25 24 #include <bits/debug.hfa> 26 25 #include "concurrency/invoke.h" … … 114 113 115 114 // MEMORY MANAGEMENT ========================================================= 115 116 struct __cfaehm_node { 117 struct _Unwind_Exception unwind_exception; 118 struct __cfaehm_node * next; 119 int handler_index; 120 }; 116 121 117 122 #define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node))) -
libcfa/src/exception.h
rc28ea4e r4b30e8cc 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // exception.h -- Internal exception handling definitions.7 // exception.h -- Builtins for exception handling. 8 8 // 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Jun 26 15:11:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 27 14:45:00 202013 // Update Count : 1 112 // Last Modified On : Tue May 19 14:17:00 2020 13 // Update Count : 10 14 14 // 15 15 16 16 #pragma once 17 17 18 // This could be considered several headers. All are internal to the exception19 // system but needed to depending on whether they are C/Cforall code and20 // whether or not they are part of the builtins.21 18 22 19 #ifdef __cforall 23 20 extern "C" { 24 21 #endif 25 26 // Included in C code or the built-ins.27 #if !defined(__cforall) || defined(__cforall_builtins__)28 22 29 23 struct __cfaehm_base_exception_t; … … 53 47 // Function catches termination exceptions. 54 48 void __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)); 58 52 59 53 // Clean-up the exception in catch blocks. … … 62 56 // Data structure creates a list of resume handlers. 63 57 struct __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); 66 60 }; 67 61 68 62 // These act as constructor and destructor for the resume node. 69 63 void __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)); 72 66 void __cfaehm_try_resume_cleanup( 73 struct __cfaehm_try_resume_node * node);67 struct __cfaehm_try_resume_node * node); 74 68 75 69 // Check for a standard way to call fake deconstructors. 76 70 struct __cfaehm_cleanup_hook {}; 77 71 78 #endif79 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 #endif93 94 72 #ifdef __cforall 95 73 } 96 97 // Built-ins not visible in C.98 #if defined(__cforall_builtins__)99 74 100 75 // Not all the built-ins can be expressed in C. These can't be … … 149 124 150 125 #endif 151 152 #endif -
libcfa/src/stdlib.cfa
rc28ea4e r4b30e8cc 58 58 59 59 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) 60 void adelete( T arr[] ) {60 void adelete( size_t dim, T arr[] ) { 61 61 if ( arr ) { // ignore null 62 size_t dim = malloc_size( arr ) / sizeof( T );63 62 for ( int i = dim - 1; i >= 0; i -= 1 ) { // reverse allocation order, must be unsigned 64 63 ^(arr[i]){}; // run destructor … … 69 68 70 69 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } ) 71 void adelete( T arr[], Params rest ) {70 void adelete( size_t dim, T arr[], Params rest ) { 72 71 if ( arr ) { // ignore null 73 size_t dim = malloc_size( arr ) / sizeof( T );74 72 for ( int i = dim - 1; i >= 0; i -= 1 ) { // reverse allocation order, must be unsigned 75 73 ^(arr[i]){}; // run destructor -
libcfa/src/stdlib.hfa
rc28ea4e r4b30e8cc 263 263 // Cforall allocation/deallocation and constructor/destructor, array types 264 264 forall( 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 );265 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] ); 266 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } ) void adelete( size_t dim, T arr[], Params rest ); 267 267 268 268 //--------------------------------------- -
src/AST/Convert.cpp
rc28ea4e r4b30e8cc 25 25 #include "AST/Init.hpp" 26 26 #include "AST/Stmt.hpp" 27 #include "AST/TranslationUnit.hpp"28 27 #include "AST/TypeSubstitution.hpp" 29 28 … … 48 47 49 48 //================================================================================================ 50 namespace ast{49 namespace { 51 50 52 51 // This is to preserve the FindSpecialDecls hack. It does not (and perhaps should not) 53 52 // 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 now57 53 ast::Type * sizeType = nullptr; 58 54 ast::FunctionDecl * dereferenceOperator = nullptr; … … 67 63 using Cache = std::unordered_map< const ast::Node *, BaseSyntaxNode * >; 68 64 Cache cache; 69 70 // Statements can no longer be shared.71 // however, since StmtExprResult is now implemented, need to still maintain72 // readonly references.73 Cache readonlyCache;74 65 75 66 template<typename T> … … 163 154 } 164 155 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 ); 166 161 if ( inCache( node ) ) { 167 162 return nullptr; 168 163 } 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 173 164 auto decl = new ObjectDecl( 174 165 node->name, … … 177 168 bfwd, 178 169 type->clone(), 179 nullptr, // prevent infinite loop170 init, 180 171 attr, 181 172 Type::FuncSpecifiers( node->funcSpec.val ) 182 173 ); 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 ); 192 175 } 193 176 … … 222 205 decl->statements = get<CompoundStmt>().accept1( node->stmts ); 223 206 decl->withExprs = get<Expression>().acceptL( node->withExprs ); 224 if ( ast::dereferenceOperator == node ) {207 if ( dereferenceOperator == node ) { 225 208 Validate::dereferenceOperator = decl; 226 209 } 227 if ( ast::dtorStructDestroy == node ) {210 if ( dtorStructDestroy == node ) { 228 211 Validate::dtorStructDestroy = decl; 229 212 } … … 284 267 ); 285 268 286 if ( ast::dtorStruct == node ) {269 if ( dtorStruct == node ) { 287 270 Validate::dtorStruct = decl; 288 271 } … … 337 320 338 321 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 ); 342 323 stmt->location = node->location; 343 324 stmt->labels = makeLabelL( stmt, node->labels ); … … 356 337 if ( inCache( node ) ) return nullptr; 357 338 auto stmt = new ExprStmt( nullptr ); 339 cache.emplace( node, stmt ); 358 340 stmt->expr = get<Expression>().accept1( node->expr ); 359 341 return stmtPostamble( stmt, node ); … … 1029 1011 auto stmts = node->stmts; 1030 1012 // 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 } 1033 1016 auto rslt = new StmtExpr( 1034 1017 get<CompoundStmt>().accept1(stmts) … … 1037 1020 rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls); 1038 1021 rslt->dtors = get<Expression>().acceptL(node->dtors); 1039 if (node->resultExpr) {1040 // this MUST be found by children visit1041 rslt->resultExpr = strict_dynamic_cast<ExprStmt *>(readonlyCache.at(node->resultExpr));1042 }1043 1022 1044 1023 auto expr = visitBaseExpr( node, rslt ); … … 1057 1036 1058 1037 auto expr = visitBaseExpr( node, rslt ); 1059 this->node = expr ->clone();1038 this->node = expr; 1060 1039 return nullptr; 1061 1040 } … … 1147 1126 auto type = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind }; 1148 1127 // I believe this should always be a BasicType. 1149 if ( ast::sizeType == node ) {1128 if ( sizeType == node ) { 1150 1129 Validate::SizeType = type; 1151 1130 } … … 1405 1384 }; 1406 1385 1407 std::list< Declaration * > convert( const ast::TranslationUnit&& translationUnit ) {1386 std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > > && translationUnit ) { 1408 1387 ConverterNewToOld c; 1409 1388 std::list< Declaration * > decls; 1410 for(auto d : translationUnit .decls) {1389 for(auto d : translationUnit) { 1411 1390 decls.emplace_back( c.decl( d ) ); 1412 1391 } … … 1550 1529 1551 1530 // function type is now derived from parameter decls instead of storing them 1552 1553 /*1554 1531 auto ftype = new ast::FunctionType((ast::ArgumentFlag)old->type->isVarArgs, cv(old->type)); 1555 1532 ftype->params.reserve(paramVars.size()); … … 1563 1540 } 1564 1541 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); 1569 1543 1570 1544 auto decl = new ast::FunctionDecl{ … … 1572 1546 old->name, 1573 1547 // GET_ACCEPT_1(type, FunctionType), 1574 std::move(forall),1575 1548 std::move(paramVars), 1576 1549 std::move(returnVars), … … 1579 1552 { old->linkage.val }, 1580 1553 GET_ACCEPT_V(attributes, Attribute), 1581 { old->get_funcSpec().val }, 1582 old->type->isVarArgs 1554 { old->get_funcSpec().val } 1583 1555 }; 1584 1556 1585 //decl->type = ftype;1557 decl->type = ftype; 1586 1558 cache.emplace( old, decl ); 1587 1559 … … 1598 1570 1599 1571 if ( Validate::dereferenceOperator == old ) { 1600 ast::dereferenceOperator = decl;1572 dereferenceOperator = decl; 1601 1573 } 1602 1574 1603 1575 if ( Validate::dtorStructDestroy == old ) { 1604 ast::dtorStructDestroy = decl;1576 dtorStructDestroy = decl; 1605 1577 } 1606 1578 } … … 1627 1599 1628 1600 if ( Validate::dtorStruct == old ) { 1629 ast::dtorStruct = decl;1601 dtorStruct = decl; 1630 1602 } 1631 1603 } … … 2559 2531 // I believe this should always be a BasicType. 2560 2532 if ( Validate::SizeType == old ) { 2561 ast::sizeType = type;2533 sizeType = type; 2562 2534 } 2563 2535 visitType( old, type ); … … 2804 2776 #undef GET_ACCEPT_1 2805 2777 2806 ast::TranslationUnitconvert( const std::list< Declaration * > && translationUnit ) {2778 std::list< ast::ptr< ast::Decl > > convert( const std::list< Declaration * > && translationUnit ) { 2807 2779 ConverterOldToNew c; 2808 ast::TranslationUnit unit;2780 std::list< ast::ptr< ast::Decl > > decls; 2809 2781 for(auto d : translationUnit) { 2810 2782 d->accept( c ); 2811 unit.decls.emplace_back( c.decl() );2783 decls.emplace_back( c.decl() ); 2812 2784 } 2813 2785 deleteAll(translationUnit); 2814 return unit;2786 return decls; 2815 2787 } -
src/AST/Convert.hpp
rc28ea4e r4b30e8cc 18 18 #include <list> 19 19 20 #include "AST/Node.hpp" 21 20 22 class Declaration; 21 23 namespace ast { 22 class TranslationUnit;24 class Decl; 23 25 }; 24 26 25 std::list< Declaration * > convert( const ast::TranslationUnit&& translationUnit );26 ast::TranslationUnitconvert( const std::list< Declaration * > && translationUnit );27 std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > > && translationUnit ); 28 std::list< ast::ptr< ast::Decl > > convert( const std::list< Declaration * > && translationUnit ); -
src/AST/Decl.cpp
rc28ea4e r4b30e8cc 48 48 49 49 // --- 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 69 50 70 51 const Type * FunctionDecl::get_type() const { return type.get(); } -
src/AST/Decl.hpp
rc28ea4e r4b30e8cc 131 131 std::vector< ptr<Expr> > withExprs; 132 132 133 FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,133 FunctionDecl( const CodeLocation & loc, const std::string & name, 134 134 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 135 135 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 ) {} 139 139 140 140 const Type * get_type() const override; -
src/AST/DeclReplacer.cpp
rc28ea4e r4b30e8cc 38 38 const ast::TypeInstType * previsit( const ast::TypeInstType * ); 39 39 }; 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 };50 40 } 51 41 … … 64 54 DeclMap declMap; 65 55 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 );71 56 } 72 57 … … 103 88 return ninst; 104 89 } 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 112 90 } 113 91 } -
src/AST/DeclReplacer.hpp
rc28ea4e r4b30e8cc 23 23 class DeclWithType; 24 24 class TypeDecl; 25 class Expr;26 25 27 26 namespace DeclReplacer { 28 27 using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >; 29 28 using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >; 30 using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >;31 29 32 30 const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false ); 33 31 const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false ); 34 32 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);36 33 } 37 34 } -
src/AST/Expr.cpp
rc28ea4e r4b30e8cc 67 67 // --- UntypedExpr 68 68 69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, constExpr * arg ) {69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, Expr * arg ) { 70 70 assert( arg ); 71 71 … … 92 92 } 93 93 94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, constExpr * rhs ) {94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs ) { 95 95 assert( lhs && rhs ); 96 96 … … 102 102 } 103 103 return ret; 104 }105 106 // --- VariableExpr107 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 pointer126 VariableExpr * funcExpr = new VariableExpr{ loc, decl };127 funcExpr->result = new PointerType{ funcExpr->result };128 return funcExpr;129 104 } 130 105 … … 263 238 } 264 239 240 // --- VariableExpr 241 242 VariableExpr::VariableExpr( const CodeLocation & loc ) 243 : Expr( loc ), var( nullptr ) {} 244 245 VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v ) 246 : Expr( loc ), var( v ) { 247 assert( var ); 248 assert( var->get_type() ); 249 result = shallowCopy( var->get_type() ); 250 } 251 252 bool VariableExpr::get_lvalue() const { 253 // It isn't always an lvalue, but it is never an rvalue. 254 return true; 255 } 256 257 VariableExpr * VariableExpr::functionPointer( 258 const CodeLocation & loc, const FunctionDecl * decl ) { 259 // wrap usually-determined result type in a pointer 260 VariableExpr * funcExpr = new VariableExpr{ loc, decl }; 261 funcExpr->result = new PointerType{ funcExpr->result }; 262 return funcExpr; 263 } 264 265 265 // --- ConstantExpr 266 266 -
src/AST/Expr.hpp
rc28ea4e r4b30e8cc 226 226 227 227 /// Creates a new dereference expression 228 static UntypedExpr * createDeref( const CodeLocation & loc, constExpr * arg );228 static UntypedExpr * createDeref( const CodeLocation & loc, Expr * arg ); 229 229 /// Creates a new assignment expression 230 static UntypedExpr * createAssign( const CodeLocation & loc, const Expr * lhs, constExpr * rhs );230 static UntypedExpr * createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs ); 231 231 232 232 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 247 247 private: 248 248 NameExpr * clone() const override { return new NameExpr{ *this }; } 249 MUTATE_FRIEND250 };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 function263 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 }; }268 249 MUTATE_FRIEND 269 250 }; … … 411 392 }; 412 393 394 /// A reference to a named variable. 395 class VariableExpr final : public Expr { 396 public: 397 readonly<DeclWithType> var; 398 399 VariableExpr( const CodeLocation & loc ); 400 VariableExpr( const CodeLocation & loc, const DeclWithType * v ); 401 402 bool get_lvalue() const final; 403 404 /// generates a function pointer for a given function 405 static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl ); 406 407 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 408 private: 409 VariableExpr * clone() const override { return new VariableExpr{ *this }; } 410 MUTATE_FRIEND 411 }; 412 413 413 /// A compile-time constant. 414 414 /// Mostly carries C-source text from parse to code-gen, without interpretation. E.g. strings keep their outer quotes and never have backslashes interpreted. … … 422 422 const CodeLocation & loc, const Type * ty, const std::string & r, 423 423 std::optional<unsigned long long> i ) 424 : Expr( loc, ty ), rep( r ), ival( i ) , underlyer(ty){}424 : Expr( loc, ty ), rep( r ), ival( i ) {} 425 425 426 426 /// Gets the integer value of this constant, if one is appropriate to its type. … … 617 617 618 618 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 ); } 620 620 621 621 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 742 742 std::vector<ptr<Expr>> dtors; ///< destructor(s) for return variable(s) 743 743 744 readonly<ExprStmt> resultExpr;745 746 744 StmtExpr( const CodeLocation & loc, const CompoundStmt * ss ); 747 745 -
src/AST/Fwd.hpp
rc28ea4e r4b30e8cc 137 137 typedef unsigned int UniqueId; 138 138 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 146 139 } -
src/AST/Node.hpp
rc28ea4e r4b30e8cc 49 49 50 50 bool unique() const { return strong_count == 1; } 51 bool isManaged() const {return strong_count > 0; }52 51 53 52 private: -
src/AST/Pass.hpp
rc28ea4e r4b30e8cc 103 103 /// Construct and run a pass on a translation unit. 104 104 template< typename... Args > 105 static void run( TranslationUnit& decls, Args &&... args ) {105 static void run( std::list< ptr<Decl> > & decls, Args &&... args ) { 106 106 Pass<core_t> visitor( std::forward<Args>( args )... ); 107 107 accept_all( decls, visitor ); … … 119 119 // Versions of the above for older compilers. 120 120 template< typename... Args > 121 static void run( TranslationUnit& decls ) {121 static void run( std::list< ptr<Decl> > & decls ) { 122 122 Pass<core_t> visitor; 123 123 accept_all( decls, visitor ); … … 228 228 template<typename core_type> 229 229 friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor ); 230 231 bool isInFunction() const {232 return inFunction;233 }234 235 230 private: 236 231 … … 240 235 const ast::Stmt * call_accept( const ast::Stmt * ); 241 236 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 *);246 237 247 238 template< typename node_t > … … 266 257 template<typename node_t, typename parent_t, typename child_t> 267 258 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);271 259 272 260 private: … … 296 284 private: 297 285 bool inFunction = false; 298 bool atFunctionTop = false;299 286 }; 300 287 … … 302 289 template<typename core_t> 303 290 void 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 );307 291 308 292 //------------------------------------------------------------------------------------------------- … … 387 371 struct WithVisitorRef { 388 372 Pass<core_t> * const visitor = nullptr; 389 390 bool isInFunction() const {391 return visitor->isInFunction();392 }393 373 }; 394 374 -
src/AST/Pass.impl.hpp
rc28ea4e r4b30e8cc 20 20 #include <unordered_map> 21 21 22 #include "AST/TranslationUnit.hpp"23 22 #include "AST/TypeSubstitution.hpp" 24 23 … … 168 167 __pedantic_pass_assert( stmt ); 169 168 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 178 169 // add a few useful symbols to the scope 179 170 using __pass::empty; … … 343 334 } 344 335 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::*child350 ) {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 369 336 370 337 template< typename core_t > … … 431 398 pass_visitor_stats.depth--; 432 399 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 );438 400 } 439 401 … … 508 470 // foralls are still in function type 509 471 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 511 474 ValueGuard< bool > oldInFunction( inFunction ); 512 475 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;517 476 maybe_accept( node, &FunctionDecl::stmts ); 518 477 maybe_accept( node, &FunctionDecl::attributes ); … … 680 639 const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) { 681 640 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); 688 647 }); 689 ValueGuard< bool > guard2( atFunctionTop ); 690 atFunctionTop = false; 648 ValueGuard< bool > guard2( inFunction ); 691 649 guard_scope guard3 { *this }; 650 inFunction = false; 692 651 maybe_accept( node, &CompoundStmt::kids ); 693 )652 }) 694 653 VISIT_END( CompoundStmt, node ); 695 654 } … … 744 703 maybe_accept( node, &IfStmt::inits ); 745 704 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 ); 748 707 }) 749 708 … … 762 721 maybe_accept( node, &WhileStmt::inits ); 763 722 maybe_accept( node, &WhileStmt::cond ); 764 maybe_accept _as_compound( node, &WhileStmt::body );723 maybe_accept( node, &WhileStmt::body ); 765 724 }) 766 725 … … 777 736 // for statements introduce a level of scope (for the initialization) 778 737 guard_symtab guard { *this }; 779 // xxx - old ast does not create WithStmtsToAdd scope for loop inits. should revisit this later.780 738 maybe_accept( node, &ForStmt::inits ); 781 739 maybe_accept( node, &ForStmt::cond ); 782 740 maybe_accept( node, &ForStmt::inc ); 783 maybe_accept _as_compound( node, &ForStmt::body );741 maybe_accept( node, &ForStmt::body ); 784 742 }) 785 743 … … 876 834 maybe_accept( node, &CatchStmt::decl ); 877 835 maybe_accept( node, &CatchStmt::cond ); 878 maybe_accept _as_compound( node, &CatchStmt::body );836 maybe_accept( node, &CatchStmt::body ); 879 837 }) 880 838 -
src/AST/Pass.proto.hpp
rc28ea4e r4b30e8cc 22 22 template<typename core_t> 23 23 class Pass; 24 25 class TranslationUnit;26 24 27 25 struct PureVisitor; -
src/AST/SymbolTable.cpp
rc28ea4e r4b30e8cc 335 335 } 336 336 337 338 void SymbolTable::addFunction ( const FunctionDecl * func) {339 addTypes( f unc->type->forall );340 addIds( f unc->returns );341 addIds( f unc->params );342 } 343 337 /* 338 void SymbolTable::addFunctionType( const FunctionType * ftype ) { 339 addTypes( ftype->forall ); 340 addIds( ftype->returns ); 341 addIds( ftype->params ); 342 } 343 */ 344 344 345 345 void SymbolTable::lazyInitScope() { -
src/AST/SymbolTable.hpp
rc28ea4e r4b30e8cc 145 145 146 146 /// 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 ); 148 148 149 149 private: -
src/AST/Type.cpp
rc28ea4e r4b30e8cc 157 157 158 158 template<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>165 159 bool SueInstType<decl_t>::isComplete() const { 166 160 return base ? base->body : false; -
src/AST/Type.hpp
rc28ea4e r4b30e8cc 302 302 class FunctionType final : public ParameterizedType { 303 303 public: 304 // std::vector<ptr<DeclWithType>> returns; 305 // std::vector<ptr<DeclWithType>> params; 306 304 307 std::vector<ptr<Type>> returns; 305 308 std::vector<ptr<Type>> params; … … 342 345 : ParameterizedType(q, std::move(as)), params(), name(n) {} 343 346 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 349 347 BaseInstType( const BaseInstType & o ); 350 348 … … 371 369 372 370 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 = {} ); 378 372 379 373 bool isComplete() const override; -
src/AST/porting.md
rc28ea4e r4b30e8cc 30 30 * Base nodes now override `const Node * accept( Visitor & v ) const = 0` with, e.g. `const Stmt * accept( Visitor & v ) const override = 0` 31 31 * `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`36 32 37 33 ## Structural Changes ## … … 150 146 * allows `newObject` as just default settings 151 147 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 157 148 `NamedTypeDecl` 158 149 * `parameters` => `params` … … 163 154 `AggregateDecl` 164 155 * `parameters` => `params` 165 166 `StructDecl`167 * `makeInst` replaced by better constructor on `StructInstType`.168 156 169 157 `Expr` … … 257 245 * **TODO** move `kind`, `typeNames` into code generator 258 246 259 `ReferenceToType` => `BaseInstType`247 `ReferenceToType` 260 248 * deleted `get_baseParameters()` from children 261 249 * replace with `aggr() ? aggr()->params : nullptr` … … 273 261 * `returnVals` => `returns` 274 262 * `parameters` => `params` 275 * Both now just point at types.276 263 * `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`281 264 282 265 `TypeInstType` -
src/Common/PassVisitor.h
rc28ea4e r4b30e8cc 354 354 virtual TypeSubstitution * mutate( TypeSubstitution * sub ) final; 355 355 356 bool isInFunction() const {357 return inFunction;358 }359 360 356 private: 361 357 bool inFunction = false; 362 bool atFunctionTop = false;363 358 364 359 template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor ); … … 531 526 public: 532 527 PassVisitor<pass_type> * const visitor = nullptr; 533 534 bool isInFunction() const {535 return visitor->isInFunction();536 }537 528 }; 538 529 -
src/Common/PassVisitor.impl.h
rc28ea4e r4b30e8cc 532 532 indexerAddId( &func ); 533 533 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 535 536 ValueGuard< bool > oldInFunction( inFunction ); 536 537 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;541 538 maybeAccept_impl( node->statements, *this ); 542 539 maybeAccept_impl( node->attributes, *this ); … … 570 567 indexerAddId( &func ); 571 568 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 573 571 ValueGuard< bool > oldInFunction( inFunction ); 574 572 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;579 573 maybeAccept_impl( node->statements, *this ); 580 574 maybeAccept_impl( node->attributes, *this ); … … 607 601 indexerAddId( &func ); 608 602 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 610 605 ValueGuard< bool > oldInFunction( inFunction ); 611 606 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;616 607 maybeMutate_impl( node->statements, *this ); 617 608 maybeMutate_impl( node->attributes, *this ); … … 1016 1007 VISIT_START( node ); 1017 1008 { 1018 // Do not enter a new scope if atFunctionTop is true, don't leave one either.1019 ValueGuard< bool > old AtFunctionTop( 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(); } ); 1021 1012 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1022 atFunctionTop= false;1013 inFunction = false; 1023 1014 visitStatementList( node->kids ); 1024 1015 } … … 1030 1021 VISIT_START( node ); 1031 1022 { 1032 // Do not enter a new scope if atFunctionTop is true, don't leave one either.1033 ValueGuard< bool > old AtFunctionTop( 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(); } ); 1035 1026 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1036 atFunctionTop= false;1027 inFunction = false; 1037 1028 visitStatementList( node->kids ); 1038 1029 } … … 1044 1035 MUTATE_START( node ); 1045 1036 { 1046 // Do not enter a new scope if atFunctionTop is true, don't leave one either.1047 ValueGuard< bool > old AtFunctionTop( 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(); } ); 1049 1040 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1050 atFunctionTop= false;1041 inFunction = false; 1051 1042 mutateStatementList( node->kids ); 1052 1043 } -
src/Common/utility.h
rc28ea4e r4b30e8cc 360 360 reverse_iterate_t( T & ref ) : ref(ref) {} 361 361 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(); } 366 365 }; 367 366 -
src/Concurrency/Keywords.cc
rc28ea4e r4b30e8cc 46 46 } 47 47 48 // Only detects threads constructed with the keyword thread.49 inline static bool isThread( DeclarationWithType * decl ) {50 Type * baseType = decl->get_type()->stripDeclarator();51 StructInstType * instType = dynamic_cast<StructInstType *>( baseType );52 if ( nullptr == instType ) { return false; }53 return instType->baseStruct->is_thread();54 }55 56 48 //============================================================================================= 57 49 // Pass declarations … … 127 119 "get_thread", 128 120 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n", 129 " ThreadCancelled",121 "", 130 122 true, 131 123 AggregateDecl::Thread … … 298 290 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first ); 299 291 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 * > &); 303 294 304 295 static void implement( std::list< Declaration * > & translationUnit ) { … … 311 302 StructDecl* guard_decl = nullptr; 312 303 StructDecl* dtor_guard_decl = nullptr; 313 StructDecl* thread_guard_decl = nullptr;314 304 315 305 static std::unique_ptr< Type > generic_func; … … 811 801 bool first = false; 812 802 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first ); 813 bool constisDtor = CodeGen::isDestructor( decl->name );803 bool isDtor = CodeGen::isDestructor( decl->name ); 814 804 815 805 // Is this function relevant to monitors … … 859 849 860 850 // 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 ); 869 853 } 870 854 else { 871 addStat ements( decl, body, mutexArgs );855 addStatments( decl, body, mutexArgs ); 872 856 } 873 857 } … … 886 870 assert( !dtor_guard_decl ); 887 871 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;892 872 } 893 873 } … … 928 908 } 929 909 930 void MutexKeyword::addDtorStat ements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {910 void MutexKeyword::addDtorStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) { 931 911 Type * arg_type = args.front()->get_type()->clone(); 932 912 arg_type->set_mutex( false ); … … 977 957 978 958 //$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 ) { 1019 963 ObjectDecl * monitors = new ObjectDecl( 1020 964 "__monitors", -
src/GenPoly/GenPoly.cc
rc28ea4e r4b30e8cc 46 46 } 47 47 48 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env) {49 for (auto ¶m : params) {50 auto paramType = param.strict_as<ast::TypeExpr>();51 if (isPolyType(paramType->type, env)) return true;52 }53 return false;54 }55 56 48 /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present 57 49 bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { … … 64 56 } 65 57 66 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap & tyVars, const ast::TypeSubstitution * env) {67 for (auto ¶m : params) {68 auto paramType = param.strict_as<ast::TypeExpr>();69 if (isPolyType(paramType->type, tyVars, env)) return true;70 }71 return false;72 }73 74 58 /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present 75 59 bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { … … 108 92 Type *newType = env->lookup( typeInst->get_name() ); 109 93 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;119 94 } 120 95 return type; … … 136 111 } 137 112 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 153 113 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { 154 114 type = replaceTypeInst( type, env ); … … 166 126 } 167 127 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;183 128 } 184 129 … … 504 449 } 505 450 506 namespace {507 // temporary hack to avoid re-implementing anything related to TyVarMap508 // 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 514 451 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) { 515 452 // is parameter is not polymorphic, don't need to box … … 522 459 } 523 460 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 box526 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 533 461 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) { 534 462 FunctionType * function = getFunctionType( appExpr->function->result ); … … 539 467 } 540 468 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 550 469 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) { 551 470 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}));556 471 } 557 472 … … 563 478 if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) { 564 479 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);577 480 } 578 481 } -
src/GenPoly/GenPoly.h
rc28ea4e r4b30e8cc 26 26 27 27 namespace GenPoly { 28 typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap; 28 29 29 typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;30 30 /// Replaces a TypeInstType by its referrent in the environment, if applicable 31 31 Type* replaceTypeInst( Type* type, const TypeSubstitution* env ); … … 33 33 /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided 34 34 Type *isPolyType( Type *type, const TypeSubstitution *env = 0 ); 35 const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr);36 35 37 36 /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided 38 37 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);40 38 41 39 /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided … … 86 84 /// true if arg requires boxing given exprTyVars 87 85 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);89 86 90 87 /// true if arg requires boxing in the call to appExpr 91 88 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);93 89 94 90 /// Adds the type variable `tyVar` to `tyVarMap` … … 97 93 /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap` 98 94 void makeTyVarMap( Type *type, TyVarMap &tyVarMap ); 99 void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap);100 95 101 96 /// Prints type variable map -
src/GenPoly/Specialize.cc
rc28ea4e r4b30e8cc 218 218 thunkFunc->get_attributes().push_back( new Attribute( "unused" ) ); 219 219 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 224 220 // thread thunk parameters into call to actual function, naming thunk parameters as we go 225 221 UniqueName paramNamer( paramPrefix ); -
src/InitTweak/FixGlobalInit.cc
rc28ea4e r4b30e8cc 34 34 #include "SynTree/Visitor.h" // for acceptAll, Visitor 35 35 36 #include "AST/Expr.hpp"37 #include "AST/Node.hpp"38 #include "AST/Pass.hpp"39 40 36 namespace InitTweak { 41 37 class GlobalFixer : public WithShortCircuiting { … … 54 50 FunctionDecl * initFunction; 55 51 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;70 52 }; 71 53 … … 109 91 } 110 92 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 } // if123 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 } // if132 }133 134 93 void GlobalFixer::previsit( ObjectDecl *objDecl ) { 135 94 std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids(); … … 153 112 } // if 154 113 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. 156 130 initStatements.push_back( ctor ); 157 131 objDecl->init = nullptr; … … 165 139 } // if 166 140 delete ctorInit; 167 } // if168 }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-NULL175 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, but180 // non-intrinsic dtors must be called181 destroyStmts.push_front( dtor );182 // ctorInit->dtor = nullptr;183 } // if184 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 okay193 mutDecl->init = nullptr;194 } // if195 // delete ctorInit;196 141 } // if 197 142 } -
src/InitTweak/FixGlobalInit.h
rc28ea4e r4b30e8cc 19 19 #include <string> // for string 20 20 21 #include <AST/Fwd.hpp>22 23 24 21 class Declaration; 25 22 … … 29 26 /// function is for library code. 30 27 void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ); 31 void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary );32 28 } // namespace 33 29 -
src/InitTweak/FixInit.cc
rc28ea4e r4b30e8cc 219 219 }; 220 220 221 struct SplitExpressions : public WithShortCircuiting, /*public WithTypeSubstitution, */public WithStmtsToAdd {221 struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution, public WithStmtsToAdd { 222 222 /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places. 223 223 static void split( std::list< Declaration * > &translationUnit ); … … 802 802 if ( Statement * ctor = ctorInit->get_ctor() ) { 803 803 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 810 804 // originally wanted to take advantage of gcc nested functions, but 811 805 // we get memory errors with this approach. To remedy this, the static -
src/InitTweak/FixInit.h
rc28ea4e r4b30e8cc 20 20 21 21 class Declaration; 22 namespace ast {23 class TranslationUnit;24 }25 22 26 23 namespace InitTweak { 27 24 /// replace constructor initializers with expression statements and unwrap basic C-style initializers 28 25 void fix( std::list< Declaration * > & translationUnit, bool inLibrary ); 29 30 void fix( ast::TranslationUnit & translationUnit, bool inLibrary);31 26 } // namespace 32 27 -
src/InitTweak/GenInit.cc
rc28ea4e r4b30e8cc 283 283 assert( stmts.size() <= 1 ); 284 284 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);292 285 } 293 286 -
src/InitTweak/GenInit.h
rc28ea4e r4b30e8cc 33 33 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument 34 34 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);36 35 37 36 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer -
src/InitTweak/InitTweak.cc
rc28ea4e r4b30e8cc 498 498 } 499 499 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 507 500 bool tryConstruct( DeclarationWithType * dwt ) { 508 501 ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt ); … … 518 511 } 519 512 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_extern526 && 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 534 513 struct CallFinder_old { 535 514 CallFinder_old( const std::list< std::string > & names ) : names( names ) {} … … 557 536 558 537 struct CallFinder_new final { 559 std::vector< const ast::Expr *> matches;538 std::vector< ast::ptr< ast::Expr > > matches; 560 539 const std::vector< std::string > names; 561 540 … … 579 558 } 580 559 581 std::vector< const ast::Expr *> collectCtorDtorCalls( const ast::Stmt * stmt ) {560 std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt ) { 582 561 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; 583 562 maybe_accept( stmt, finder ); … … 717 696 template <typename Predicate> 718 697 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 ); 720 699 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 721 700 } … … 960 939 } 961 940 962 // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards963 // 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 989 941 struct ConstExprChecker : public WithShortCircuiting { 990 942 // most expressions are not const expr … … 1103 1055 return isCopyFunction( decl, "?{}" ); 1104 1056 } 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 1115 1057 } -
src/InitTweak/InitTweak.h
rc28ea4e r4b30e8cc 38 38 /// returns the first parameter of a constructor/destructor/assignment function 39 39 ObjectDecl * getParamThis( FunctionType * ftype ); 40 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);41 40 42 41 /// generate a bitwise assignment operation. 43 42 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ); 44 45 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);46 43 47 44 /// transform Initializer into an argument list that can be passed to a call expression … … 51 48 /// True if the resolver should try to construct dwt 52 49 bool tryConstruct( DeclarationWithType * dwt ); 53 bool tryConstruct( const ast::DeclWithType * dwt );54 50 55 51 /// True if the type can have a user-defined constructor 56 52 bool isConstructable( Type * t ); 57 bool isConstructable( const ast::Type * t );58 53 59 54 /// True if the Initializer contains designations … … 84 79 /// get all Ctor/Dtor call expressions from a Statement 85 80 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 ); 87 82 88 83 /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call … … 107 102 bool isConstExpr( Expression * expr ); 108 103 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" in116 /// .section .data,"a"117 /// .section .data#,"a"118 /// to avoid assembler warning "ignoring changed section attributes for .data"119 void addDataSectonAttribute( ObjectDecl * objDecl );120 104 121 105 class InitExpander_old { -
src/InitTweak/module.mk
rc28ea4e r4b30e8cc 23 23 InitTweak/GenInit.h \ 24 24 InitTweak/InitTweak.cc \ 25 InitTweak/InitTweak.h \ 26 InitTweak/FixInitNew.cpp 25 InitTweak/InitTweak.h 27 26 28 27 SRCDEMANGLE += \ -
src/Parser/ParseNode.h
rc28ea4e r4b30e8cc 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Oct 24 03:53:54202013 // Update Count : 89 512 // Last Modified On : Mon Jul 6 09:33:32 2020 13 // Update Count : 892 14 14 // 15 15 … … 205 205 struct TypeData; 206 206 207 struct DeclarationNode : public ParseNode { 207 class DeclarationNode : public ParseNode { 208 public: 208 209 // These enumerations must harmonize with their names in DeclarationNode.cc. 209 210 enum BasicType { Void, Bool, Char, Int, Int128, … … 303 304 bool get_inLine() const { return inLine; } 304 305 DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; } 305 306 public: 306 307 DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); } 307 308 … … 359 360 //############################################################################## 360 361 361 struct StatementNode final : public ParseNode { 362 class StatementNode final : public ParseNode { 363 public: 362 364 StatementNode() { stmt = nullptr; } 363 365 StatementNode( Statement * stmt ) : stmt( stmt ) {} … … 380 382 os << stmt.get() << std::endl; 381 383 } 382 384 private: 383 385 std::unique_ptr<Statement> stmt; 384 386 }; // StatementNode … … 424 426 Statement * build_finally( StatementNode * stmt ); 425 427 Statement * build_compound( StatementNode * first ); 426 StatementNode * maybe_build_compound( StatementNode * first );427 428 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr ); 428 429 Statement * build_directive( std::string * directive ); -
src/Parser/StatementNode.cc
rc28ea4e r4b30e8cc 10 10 // Created On : Sat May 16 14:59:41 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Oct 24 04:20:55 202013 // Update Count : 3 8312 // Last Modified On : Sat Aug 4 09:39:25 2018 13 // Update Count : 363 14 14 // 15 15 … … 345 345 } // build_compound 346 346 347 // A single statement in a control structure is always converted to a compound statement so subsequent generated code348 // can be placed within this compound statement. Otherwise, code generation has to constantly check for a single349 // statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a350 // 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_ptr355 CompoundStmt * cs = new CompoundStmt();356 buildMoveList( first, cs->get_kids() );357 return new StatementNode( cs );358 } // if359 return first;360 } // maybe_build_compound361 362 347 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) { 363 348 std::list< Expression * > out, in; -
src/Parser/parser.yy
rc28ea4e r4b30e8cc 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Oct 24 08:21:14202013 // Update Count : 46 2412 // Last Modified On : Fri Oct 9 18:09:09 2020 13 // Update Count : 4614 14 14 // 15 15 … … 1080 1080 IF '(' if_control_expression ')' statement %prec THEN 1081 1081 // 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 ) ); } 1083 1083 | 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 ) ); } 1085 1085 ; 1086 1086 … … 1130 1130 1131 1131 case_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 ) ) ); } 1133 1133 ; 1134 1134 … … 1148 1148 iteration_statement: 1149 1149 WHILE '(' push if_control_expression ')' statement pop 1150 { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 )) ); }1150 { $$ = new StatementNode( build_while( $4, $6 ) ); } 1151 1151 | 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 ) ); } 1153 1153 | DO statement WHILE '(' comma_expression ')' ';' 1154 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 )) ); }1154 { $$ = new StatementNode( build_do_while( $5, $2 ) ); } 1155 1155 | 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 ) ); } 1157 1157 | 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 ) ); } 1159 1159 | 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 ) ); } 1161 1161 ; 1162 1162 … … 1341 1341 waitfor_clause: 1342 1342 when_clause_opt waitfor statement %prec THEN 1343 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1 ); }1343 { $$ = build_waitfor( $2, $3, $1 ); } 1344 1344 | 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 ); } 1346 1346 | when_clause_opt timeout statement %prec THEN 1347 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1 ); }1347 { $$ = build_waitfor_timeout( $2, $3, $1 ); } 1348 1348 | when_clause_opt ELSE statement 1349 { $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); }1349 { $$ = build_waitfor_timeout( nullptr, $3, $1 ); } 1350 1350 // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless) 1351 1351 | when_clause_opt timeout statement WOR ELSE statement 1352 1352 { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; } 1353 1353 | 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 ); } 1355 1355 ; 1356 1356 -
src/ResolvExpr/Resolver.cc
rc28ea4e r4b30e8cc 1105 1105 } 1106 1106 1107 1108 } // anonymous namespace 1109 /// Establish post-resolver invariants for expressions 1107 /// Establish post-resolver invariants for expressions 1110 1108 void finishExpr( 1111 1109 ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env, … … 1120 1118 StripCasts_new::strip( expr ); 1121 1119 } 1120 } // anonymous namespace 1121 1122 1122 1123 1123 ast::ptr< ast::Expr > resolveInVoidContext( … … 1139 1139 } 1140 1140 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` 1142 1143 /// context. 1143 1144 ast::ptr< ast::Expr > findVoidExpression( … … 1150 1151 return newExpr; 1151 1152 } 1152 1153 namespace {1154 1155 1153 1156 1154 /// resolve `untyped` to the expression whose candidate satisfies `pred` with the … … 1164 1162 CandidateRef choice = 1165 1163 findUnfinishedKindExpression( untyped, symtab, kind, pred, mode ); 1166 ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );1164 finishExpr( choice->expr, choice->env, untyped->env ); 1167 1165 return std::move( choice->expr ); 1168 1166 } … … 1274 1272 // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver"); 1275 1273 1276 void resolve( ast::TranslationUnit& translationUnit ) {1274 void resolve( std::list< ast::ptr< ast::Decl > >& translationUnit ) { 1277 1275 ast::Pass< Resolver_new >::run( translationUnit ); 1278 1276 } -
src/ResolvExpr/Resolver.h
rc28ea4e r4b30e8cc 35 35 class StmtExpr; 36 36 class SymbolTable; 37 class TranslationUnit;38 37 class Type; 39 38 class TypeEnvironment; … … 56 55 57 56 /// 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 ); 59 58 /// Searches expr and returns the first DeletedExpr found, otherwise nullptr 60 59 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ); … … 67 66 ast::ptr< ast::Expr > findSingleExpression( 68 67 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);71 68 /// Resolves a constructor init expression 72 ast::ptr< ast::Init > resolveCtorInit( 69 ast::ptr< ast::Init > resolveCtorInit( 73 70 const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab ); 74 71 /// Resolves a statement expression 75 ast::ptr< ast::Expr > resolveStmtExpr( 72 ast::ptr< ast::Expr > resolveStmtExpr( 76 73 const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab ); 77 74 } // namespace ResolvExpr -
src/SymTab/Autogen.cc
rc28ea4e r4b30e8cc 233 233 } 234 234 235 // shallow copy the pointer list for return236 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 246 235 /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *) 247 236 FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) { … … 255 244 ftype->parameters.push_back( dstParam ); 256 245 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));265 246 } 266 247 -
src/SymTab/Autogen.h
rc28ea4e r4b30e8cc 55 55 /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic 56 56 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);59 57 60 58 /// generate the type of a copy constructor for paramType. -
src/SynTree/Expression.h
rc28ea4e r4b30e8cc 163 163 }; 164 164 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 190 165 // The following classes are used to represent expression types that cannot be converted into 191 166 // function-call format. … … 354 329 }; 355 330 331 /// VariableExpr represents an expression that simply refers to the value of a named variable. 332 /// Does not take ownership of var. 333 class VariableExpr : public Expression { 334 public: 335 DeclarationWithType * var; 336 337 VariableExpr(); 338 VariableExpr( DeclarationWithType * var ); 339 VariableExpr( const VariableExpr & other ); 340 virtual ~VariableExpr(); 341 342 bool get_lvalue() const final; 343 344 DeclarationWithType * get_var() const { return var; } 345 void set_var( DeclarationWithType * newValue ) { var = newValue; } 346 347 static VariableExpr * functionPointer( FunctionDecl * decl ); 348 349 virtual VariableExpr * clone() const override { return new VariableExpr( * this ); } 350 virtual void accept( Visitor & v ) override { v.visit( this ); } 351 virtual void accept( Visitor & v ) const override { v.visit( this ); } 352 virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 353 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 354 }; 355 356 356 /// ConstantExpr represents an expression that simply refers to the value of a constant 357 357 class ConstantExpr : public Expression { -
src/main.cc
rc28ea4e r4b30e8cc 343 343 auto transUnit = convert( move( translationUnit ) ); 344 344 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 345 if ( exprp ) {346 translationUnit = convert( move( transUnit ) );347 dump( translationUnit );348 return EXIT_SUCCESS;349 } // if350 351 PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));352 345 translationUnit = convert( move( transUnit ) ); 353 346 } else { 354 347 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() ) );361 348 } 362 349 350 if ( exprp ) { 351 dump( translationUnit ); 352 return EXIT_SUCCESS; 353 } // if 354 363 355 // fix ObjectDecl - replaces ConstructorInit nodes 356 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) ); 364 357 if ( ctorinitp ) { 365 358 dump ( translationUnit ); -
tests/.expect/const-init.txt
rc28ea4e r4b30e8cc 1 almost done 2 dtor 1 done -
tests/Makefile.am
rc28ea4e r4b30e8cc 53 53 54 54 # 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})55 CC = LC_ALL=C $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS}) 56 56 CFACC = $(CC) 57 57 … … 60 60 61 61 # 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})62 CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS}) 63 63 CFACCLINK = $(CFACCLOCAL) -quiet $(if $(test), 2> $(test), ) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g')) 64 64 -
tests/alloc.cfa
rc28ea4e r4b30e8cc 342 342 for ( i; dim ) { printf( "%d %g, ", stp1[i].x, stp1[i].y ); } 343 343 printf( "\n" ); 344 adelete( stp, stp1 );344 adelete( dim, stp, dim, stp1 ); 345 345 346 346 // extras -
tests/complex.cfa
rc28ea4e r4b30e8cc 14 14 // 15 15 16 #include <stdio.h> 16 17 #include <complex.h> 17 18 #ifdef __CFA__ -
tests/config.py.in
rc28ea4e r4b30e8cc 9 9 HOSTARCH = "@host_cpu@" 10 10 DISTRIBUTE = @HAS_DISTCC@ 11 NEWAST = @DEFAULT_NEW_AST@ -
tests/const-init.cfa
rc28ea4e r4b30e8cc 16 16 /* 17 17 18 Th ese tests show non-crashing of generated code for constants with interesting initializers.18 This test shows non-crashing of generated code for constants with interesting initizers. 19 19 The potential for these to crash is compiler dependent. 20 20 21 21 There are two cases: 22 1. static constants in one compilation unit (tested here , in a few sub-cases)22 1. static constants in one compilation unit (tested here) 23 23 2. extern constants across compilation units (tested by libcfa being loadable, specifically 24 the constant de finitions in libcfa/src/limits.cfa, which almost every test exercises,24 the constant declarations in libcfa/src/limits.cfa, which almost every test exercises, 25 25 including "hello;" but notably, the "limits" test does not exercise it because that test 26 26 is compile-only) … … 37 37 GCC-10 on Ubuntu 20.04 Has crashed Has crashed 38 38 39 For this test to fail, with most other tests passing, would be a situation only ever39 For this test case to fail, with most other tests passing, would be a situation only ever 40 40 observed with GCC-8. 41 41 42 42 */ 43 43 44 // initailized by generated function, called before main45 44 static const char foo = -1; 46 45 47 struct thing{};48 void ^?{}( thing & ) { printf("dtor\n"); }49 50 46 int 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"); 60 48 } -
tests/exceptions/cancel/coroutine.cfa
rc28ea4e r4b30e8cc 1 1 // Try cancelling a coroutine. 2 2 3 #include <stdio.h> 3 4 #include <coroutine.hfa> 4 5 #include <exception.hfa> -
tests/exceptions/conditional.cfa
rc28ea4e r4b30e8cc 5 5 6 6 #include <exception.hfa> 7 #include <stdio.h> 7 8 8 9 VTABLE_DECLARATION(num_error)( -
tests/exceptions/except-io.hfa
rc28ea4e r4b30e8cc 1 1 // Common tools for the exception tests. 2 3 #include <stdio.h> 2 4 3 5 // Echo when a destructor is run and an area/block is left. -
tests/exceptions/trash.cfa
rc28ea4e r4b30e8cc 2 2 3 3 #include <exception.hfa> 4 #include <stdio.h> 4 5 5 6 TRIVIAL_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> 2 5 3 6 forall(dtype T) -
tests/poly-d-cycle.cfa
rc28ea4e r4b30e8cc 1 1 // Check that a cycle of polymorphic dtype structures can be instancated. 2 3 #include <stdio.h> 2 4 3 5 forall(dtype T) -
tests/poly-o-cycle.cfa
rc28ea4e r4b30e8cc 1 1 // Check that a cycle of polymorphic otype structures can be instancated. 2 3 #include <stdio.h> 2 4 3 5 forall(otype T) -
tests/pybin/settings.py
rc28ea4e r4b30e8cc 85 85 def filter(self, tests): 86 86 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 87 88 88 89 @staticmethod … … 96 97 self.flags = """DEBUG_FLAGS=%s""" % ("-debug -O0" if value else "-nodebug -O2") 97 98 self.path = "debug" if value else "nodebug" 98 99 class AST:100 def __init__(self, ast):101 if ast == "new":102 self.target = ast103 self.string = "New AST"104 self.flags = """AST_FLAGS=-XCFA,--new-ast"""105 elif ast == "old":106 self.target = ast107 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.target112 self.flags = """AST_FLAGS="""113 else:114 print("""ERROR: Invalid ast configuration, must be "old", "new" or left unspecified, was %s""" % (value), file=sys.stderr)115 sys.exit(1)116 117 def filter(self, tests):118 119 return [test for test in tests if not test.astv or self.target == test.astv]120 99 121 100 class Install: … … 141 120 142 121 def init( options ): 143 global all_ast144 122 global all_arch 145 123 global all_debug 146 124 global all_install 147 global ast148 125 global arch 126 global archive 127 global continue_ 149 128 global debug 150 global archive151 global install152 153 global continue_154 129 global dry_run 155 130 global generating 131 global install 156 132 global make 157 133 global output_width … … 159 135 global timeout2gdb 160 136 161 all_ast = [AST(o) for o in list(dict.fromkeys(options.ast ))] if options.ast else [AST(None)]162 137 all_arch = [Architecture(o) for o in list(dict.fromkeys(options.arch ))] if options.arch else [Architecture(None)] 163 138 all_debug = [Debug(o) for o in list(dict.fromkeys(options.debug ))] -
tests/pybin/test_run.py
rc28ea4e r4b30e8cc 11 11 self.path = '' 12 12 self.arch = '' 13 self.astv = ''14 13 15 14 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.astvelse "Any", self.target() )15 return "{:25s} ({:5s} {:s})".format( self.name, self.arch if self.arch else "Any", self.target() ) 17 16 18 17 def prepare(self): … … 21 20 22 21 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)) ) 26 23 27 24 def error_log(self): … … 48 45 49 46 @staticmethod 50 def new_target(target, arch , astv):47 def new_target(target, arch): 51 48 test = Test() 52 49 test.name = os.path.basename(target) 53 50 test.path = os.path.relpath (os.path.dirname(target), settings.SRCDIR) 54 51 test.arch = arch.target if arch else '' 55 test.astv = astv.target if astv else ''56 52 return test 57 53 -
tests/pybin/tools.py
rc28ea4e r4b30e8cc 181 181 '-s' if silent else None, 182 182 test_param, 183 settings.ast.flags,184 183 settings.arch.flags, 185 184 settings.debug.flags, -
tests/test.py
rc28ea4e r4b30e8cc 24 24 25 25 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) 27 27 if match : 28 28 test = Test() 29 29 test.name = match.group(2) 30 30 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 42 32 expected.append(test) 43 33 … … 76 66 if options.regenerate_expected : 77 67 for testname in options.tests : 78 testname = os.path.normpath( os.path.join(settings.SRCDIR, testname) ) 79 68 testname = canonical_path( testname ) 80 69 # first check if this is a valid name to regenerate 81 70 if Test.valid_name(testname): 82 71 # this is a valid name, let's check if it already exists 83 72 found = [test for test in all_tests if canonical_path( test.target() ) == testname] 84 setup = itertools.product(settings.all_arch if options.arch else [None], settings.all_ast if options.ast else [None])85 73 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 ) ) 88 81 elif len(found) == 1 and not found[0].arch: 89 82 # we found a single test, the user better be wanting to create a cross platform test 90 83 if options.arch: 91 84 print('ERROR: "%s", test has no specified architecture but --arch was specified, ignoring it' % testname, file=sys.stderr) 92 elif options.ast:93 print('ERROR: "%s", test has no specified ast version but --ast was specified, ignoring it' % testname, file=sys.stderr)94 85 else: 95 86 tests.append( found[0] ) 96 87 else: 97 88 # 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] ) 99 90 100 91 # print a warning if it users didn't ask for a specific architecture 101 92 if not options.arch: 102 93 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 version106 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)108 94 109 95 else : … … 126 112 # create a parser with the arguments for the tests script 127 113 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)130 114 parser.add_argument('--debug', help='Run all tests in debug or release', type=comma_separated(yes_no), default='yes') 131 115 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) 132 117 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_') 133 118 parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=120) … … 266 251 except KeyboardInterrupt: 267 252 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, "" 272 257 273 258 … … 377 362 # for each build configurations, run the test 378 363 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): 381 365 settings.arch = arch 382 366 settings.debug = debug … … 385 369 # filter out the tests for a different architecture 386 370 # 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 ) 389 372 options.jobs, forceJobs = job_count( options, local_tests ) 390 373 settings.update_make_cmd(forceJobs, options.jobs) … … 394 377 395 378 # print configuration 396 print('%s %i tests on %i cores (%s:%s - %s)' % (379 print('%s %i tests on %i cores (%s:%s)' % ( 397 380 'Regenerating' if settings.generating else 'Running', 398 381 len(local_tests), 399 382 options.jobs, 400 settings.ast.string,401 383 settings.arch.string, 402 384 settings.debug.string 403 385 )) 404 if not local_tests :405 print('WARNING: No tests for this configuration')406 continue407 386 408 387 # otherwise run all tests and make sure to return the correct error code
Note:
See TracChangeset
for help on using the changeset viewer.