Changeset 579263a
- Timestamp:
- Jun 26, 2017, 4:48:35 PM (6 years ago)
- Branches:
- aaron-thesis, arm-eh, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- bb1cd95
- Parents:
- e4d829b (diff), 2a7b3ca (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 22 added
- 6 deleted
- 89 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
re4d829b r579263a 13 13 libcfa/Makefile 14 14 src/Makefile 15 version15 /version 16 16 17 17 # genereted by premake -
configure
re4d829b r579263a 6251 6251 6252 6252 6253 ac_config_files="$ac_config_files Makefile src/driver/Makefile src/Makefile src/benchmark/Makefile src/examples/Makefile src/tests/Makefile src/ prelude/Makefile src/libcfa/Makefile"6253 ac_config_files="$ac_config_files Makefile src/driver/Makefile src/Makefile src/benchmark/Makefile src/examples/Makefile src/tests/Makefile src/tests/preempt_longrun/Makefile src/prelude/Makefile src/libcfa/Makefile" 6254 6254 6255 6255 … … 7019 7019 "src/examples/Makefile") CONFIG_FILES="$CONFIG_FILES src/examples/Makefile" ;; 7020 7020 "src/tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/tests/Makefile" ;; 7021 "src/tests/preempt_longrun/Makefile") CONFIG_FILES="$CONFIG_FILES src/tests/preempt_longrun/Makefile" ;; 7021 7022 "src/prelude/Makefile") CONFIG_FILES="$CONFIG_FILES src/prelude/Makefile" ;; 7022 7023 "src/libcfa/Makefile") CONFIG_FILES="$CONFIG_FILES src/libcfa/Makefile" ;; -
configure.ac
re4d829b r579263a 235 235 src/examples/Makefile 236 236 src/tests/Makefile 237 src/tests/preempt_longrun/Makefile 237 238 src/prelude/Makefile 238 239 src/libcfa/Makefile -
doc/LaTeXmacros/common.tex
re4d829b r579263a 11 11 %% Created On : Sat Apr 9 10:06:17 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Mon May 15 18:03:29201714 %% Update Count : 3 0213 %% Last Modified On : Sun Jun 18 20:32:32 2017 14 %% Update Count : 319 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 36 36 % Names used in the document. 37 37 38 \newcommand{\CFA}{\textrm{C}\raisebox{\depth}{\rotatebox{180}{\textsf{A}}}\xspace} % Cforall symbolic name 38 \newcommand{\CFAIcon}{\textrm{C}\raisebox{\depth}{\rotatebox{180}{\textsf{A}}}\xspace} % Cforall symbolic name 39 \newcommand{\CFA}{\protect\CFAIcon} % safe for section/caption 39 40 \newcommand{\CFL}{\textrm{Cforall}\xspace} % Cforall symbolic name 40 41 \newcommand{\Celeven}{\textrm{C11}\xspace} % C11 symbolic name … … 241 242 belowskip=3pt, 242 243 % replace/adjust listing characters that look bad in sanserif 243 literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0. 075ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1244 literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1 244 245 {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1 245 {__}{\_\,\_}2 {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex\textgreater}2 246 {___}{\_\,\_\,\_}3, 246 {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex\textgreater}2, 247 247 moredelim=**[is][\color{red}]{®}{®}, % red highlighting ®...® (registered trademark symbol) emacs: C-q M-. 248 248 moredelim=**[is][\color{blue}]{ß}{ß}, % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_ -
doc/proposals/concurrency/Makefile
re4d829b r579263a 13 13 annex/glossary \ 14 14 text/intro \ 15 text/cforall \ 15 16 text/basics \ 16 17 text/concurrency \ -
doc/proposals/concurrency/build/bump_ver.sh
re4d829b r579263a 1 1 #!/bin/bash 2 if [ ! -f build/version ]; then3 echo "0.0.0" > build/version2 if [ ! -f version ]; then 3 echo "0.0.0" > version 4 4 fi 5 5 6 sed -r 's/([0-9]+\.[0-9]+.)([0-9]+)/echo "\1\$((\2+1))" > version/ge' build/version > /dev/null6 sed -r 's/([0-9]+\.[0-9]+.)([0-9]+)/echo "\1\$((\2+1))" > version/ge' version > /dev/null -
doc/proposals/concurrency/text/basics.tex
re4d829b r579263a 7 7 8 8 \section{Basics of concurrency} 9 At its core, concurrency is based on having multiple call stacks and potentially multiple threads of execution for these stacks. Concurrency alone without parallelism only requires having multiple call stacks (or contexts) for a single thread of execution and switching between these call stacks on a regular basis. A minimal concurrency product can be achieved by creating coroutines which instead of context switching between each other, always ask an oracle where to context switch next. While coroutines do not technically require a stack, stackfull coroutines are the closest abstraction to a practical "naked"" call stack. When writing concurrency in terms of coroutines, the oracle effectively becomes a scheduler and the whole system now follows a cooperative threading model \cit. The oracle/scheduler can either be a stackless or stackfull entity and correspondingly require one or two context switches to run a different coroutine but in any case a subset of concurrency related challenges start to appear. For the complete set of concurrency challenges to be present, the only feature missing is preemption. Indeed, concurrency challenges appear with the lack of determinism. Guaranteeing mutual-exclusion or synchronisation are simply ways of limiting the lack of determinism in the system. A scheduler introduces order of execution uncertainty while preemption introduces incertainty about when context-switches occur. Now it is important to understand that uncertainty is not necessarily undesireable, uncertainty can often be used by systems to significantly increase performance and is often the basis of giving the user the illusion that hundred of tasks are running in parallel. Optimal performance in concurrent applications is often obtained by having as little determinism as correctness will allow\cit.9 At its core, concurrency is based on having call-stacks and potentially multiple threads of execution for these stacks. Concurrency without parallelism only requires having multiple call stacks (or contexts) for a single thread of execution, and switching between these call stacks on a regular basis. A minimal concurrency product can be achieved by creating coroutines, which instead of context switching between each other, always ask an oracle where to context switch next. While coroutines do not technically require a stack, stackfull coroutines are the closest abstraction to a practical "naked"" call stack. When writing concurrency in terms of coroutines, the oracle effectively becomes a scheduler and the whole system now follows a cooperative threading-model \cit. The oracle/scheduler can either be a stackless or stackfull entity and correspondingly require one or two context switches to run a different coroutine. In any case, a subset of concurrency related challenges start to appear. For the complete set of concurrency challenges to occur, the only feature missing is preemption. Indeed, concurrency challenges appear with non-determinism. Guaranteeing mutual-exclusion or synchronisation are simply ways of limiting the lack of determinism in a system. A scheduler introduces order of execution uncertainty, while preemption introduces incertainty about where context-switches occur. Now it is important to understand that uncertainty is not necessarily undesireable; uncertainty can often be used by systems to significantly increase performance and is often the basis of giving a user the illusion that tasks are running in parallel. Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows\cit. 10 10 11 11 \section{\protect\CFA 's Thread Building Blocks} 12 % As a system-level language, \CFA should offer both performance and flexibilty as its primary goals, simplicity and user-friendliness being a secondary concern. Therefore, the core of parallelism in \CFA should prioritize power and efficiency. With this said, deconstructing popular paradigms in order to get simple building blocks yields \glspl{uthread} as the core parallelism block. \Glspl{pool} and other parallelism paradigms can then be built on top of the underlying threading model. 13 One of the important features that is missing to C is threading. On modern architectures, the lack of threading is becoming less and less forgivable\cite{Sutter05, Sutter05b} and therefore any modern programming language should have the proper tools to allow users to write performant concurrent and/or parallel programs. As an extension of C, \CFA needs to express these concepts an a way that is as natural as possible to programmers used to imperative languages. And being a system level language means programmers will expect to be able to choose precisely which features they need and which cost they are willing to pay. 14 15 \section{Coroutines A stepping stone}\label{coroutine} 16 While the main focus of this proposal is concurrency and parallelism, as mentionned above it is important to adress coroutines which are actually a significant underlying aspect of the concurrency system. Indeed, while having nothing todo with parallelism and arguably little to do with concurrency, coroutines need to deal with context-switchs and and other context management operations. Therefore, this proposal includes coroutines both as an intermediate step for the implementation of threads and a first class feature of \CFA. Furthermore, many design challenges of threads are at least partially present in designing coroutines, which makes the design effort that much more relevant. The core API of coroutines revolve around two features independent call stacks and \code{suspend}/\code{resume}. 12 One of the important features that is missing in C is threading. On modern architectures, a lack of threading is becoming less and less forgivable\cite{Sutter05, Sutter05b}, and therefore modern programming languages must have the proper tools to allow users to write performant concurrent and/or parallel programs. As an extension of C, \CFA needs to express these concepts in a way that is as natural as possible to programmers used to imperative languages. And being a system-level language means programmers expect to choose precisely which features they need and which cost they are willing to pay. 13 14 \section{Coroutines: A stepping stone}\label{coroutine} 15 While the main focus of this proposal is concurrency and parallelism, as mentionned above it is important to adress coroutines, which are actually a significant underlying aspect of a concurrency system. Indeed, while having nothing todo with parallelism and arguably little to do with concurrency, coroutines need to deal with context-switchs and and other context-management operations. Therefore, this proposal includes coroutines both as an intermediate step for the implementation of threads, and a first class feature of \CFA. Furthermore, many design challenges of threads are at least partially present in designing coroutines, which makes the design effort that much more relevant. The core API of coroutines revolve around two features: independent call stacks and \code{suspend}/\code{resume}. 17 16 18 17 Here is an example of a solution to the fibonnaci problem using \CFA coroutines: … … 26 25 } 27 26 27 // main automacically called on first resume 28 28 void main(Fibonacci* this) { 29 29 int fn1, fn2; // retained between resumes … … 59 59 60 60 \subsection{Construction} 61 One important design challenge for coroutines and threads (shown in section \ref{threads}) is that the runtime system needs to run some code after the user-constructor runs. In the case of the coroutines this challenge is simpler since there is no loss of determinism brough by preemption or scheduling, however, the underlying challenge remains the same for coroutines and threads.62 63 The runtime system needs to create the coroutine's stack and more importantly prepare it for the first resumption. The timing of the creation is non trivial since users both expect to have fully constructed objects once execution enters the coroutine main and to be able to resume the coroutine from the constructor (Obviously we only solve cases where these two statements don't conflict). There are several solutions to this problem but the chosen options effectively forces the design of the coroutine.64 65 Furthermore, \CFA faces an extra challenge which is that polymorphique routines rely oninvisible thunks when casted to non-polymorphic routines and these thunks have function scope. For example, the following code, while looking benign, can run into undefined behaviour because of thunks:61 One important design challenge for coroutines and threads (shown in section \ref{threads}) is that the runtime system needs to run code after the user-constructor runs. In the case of coroutines, this challenge is simpler since there is no non-determinism from preemption or scheduling. However, the underlying challenge remains the same for coroutines and threads. 62 63 The runtime system needs to create the coroutine's stack and more importantly prepare it for the first resumption. The timing of the creation is non-trivial since users both expect to have fully constructed objects once execution enters the coroutine main and to be able to resume the coroutine from the constructor. Like for regular objects, constructors can still leak coroutines before they are ready. There are several solutions to this problem but the chosen options effectively forces the design of the coroutine. 64 65 Furthermore, \CFA faces an extra challenge as polymorphic routines create invisible thunks when casted to non-polymorphic routines and these thunks have function scope. For example, the following code, while looking benign, can run into undefined behaviour because of thunks: 66 66 67 67 \begin{cfacode} … … 78 78 } 79 79 \end{cfacode} 80 Indeed, the generated C code\footnote{Code trimmed down for brevity} shows that a local thunk is created in orderto hold type information:80 The generated C code\footnote{Code trimmed down for brevity} creates a local thunk to hold type information: 81 81 82 82 \begin{ccode} … … 95 95 } 96 96 \end{ccode} 97 The problem in th e this example is that there is a race condition between the start of the execution of \code{noop} on the other thread and the stack frame of \code{bar} being destroyed. This extra challenge limits which solutions are viable because storing the function pointer for too long only increases the chances that the race will end in undefined behavior; i.e. the stack based thunk being destroyed before it was used.97 The problem in this example is a race condition between the start of the execution of \code{noop} on the other thread and the stack frame of \code{bar} being destroyed. This extra challenge limits which solutions are viable because storing the function pointer for too long only increases the chances that the race will end in undefined behavior; i.e. the stack based thunk being destroyed before it was used. This challenge is an extension of challenges that come with second-class routines. Indeed, GCC nested routines also have the limitation that the routines cannot be passed outside of the scope of the functions these were declared in. The case of coroutines and threads is simply an extension of this problem to multiple call-stacks. 98 98 99 99 \subsection{Alternative: Composition} 100 One solution to this challenge would be to use inheritence,100 One solution to this challenge would be to use composition/containement, 101 101 102 102 \begin{cfacode} 103 103 struct Fibonacci { 104 104 int fn; // used for communication 105 coroutine c; 105 coroutine c; //composition 106 106 }; 107 107 … … 111 111 } 112 112 \end{cfacode} 113 114 There are two downsides to this approach. The first, which is relatively minor, is that the base class needs to be made aware of the main routine pointer, regardless of whether we use a parameter or a virtual pointer, this means the coroutine data must be made larger to store a value that is actually a compile time constant (The address of the main routine). The second problem which is both subtle but significant, is that now users can get the initialisation order of there coroutines wrong. Indeed, every field of a \CFA struct will be constructed but in the order of declaration, unless users explicitly write otherwise. This means that users who forget to initialize a the coroutine at the right time may resume the coroutine with an uninitilized object. For coroutines, this is unlikely to be a problem, for threads however, this is a significant problem. 113 There are two downsides to this approach. The first, which is relatively minor, is that the base class needs to be made aware of the main routine pointer, regardless of whether a parameter or a virtual pointer is used, this means the coroutine data must be made larger to store a value that is actually a compile time constant (address of the main routine). The second problem, which is both subtle and significant, is that now users can get the initialisation order of there coroutines wrong. Indeed, every field of a \CFA struct is constructed but in declaration order, unless users explicitly write otherwise. This semantics means that users who forget to initialize a the coroutine may resume the coroutine with an uninitilized object. For coroutines, this is unlikely to be a problem, for threads however, this is a significant problem. 115 114 116 115 \subsection{Alternative: Reserved keyword} … … 122 121 }; 123 122 \end{cfacode} 124 125 123 This mean the compiler can solve problems by injecting code where needed. The downside of this approach is that it makes coroutine a special case in the language. Users who would want to extend coroutines or build their own for various reasons can only do so in ways offered by the language. Furthermore, implementing coroutines without language supports also displays the power of \CFA. 126 124 While this is ultimately the option used for idiomatic \CFA code, coroutines and threads can both be constructed by users without using the language support. The reserved keywords are only present to improve ease of use for the common cases. … … 128 126 \subsection{Alternative: Lamda Objects} 129 127 130 For coroutines as for threads, many implementations are based on routine pointers or function objects\cit. For example, Boost implements coroutines in terms of four functor object types \code{asymmetric_coroutine<>::pull_type}, \code{asymmetric_coroutine<>::push_type}, \code{symmetric_coroutine<>::call_type}, \code{symmetric_coroutine<>::yield_type}. Often, the canonical threading paradigm in languages is based on function pointers, pthread being one of the most well known example. The main problem of these approach is that the thread usage is limited to a generic handle that must otherwise be wrapped in a custom type. Since the custom type is simple to write and \CFA and solves several issues, added support for routine/lambda based coroutines adds very little. 131 132 \subsection{Trait based coroutines} 133 134 Finally the underlying approach, which is the one closest to \CFA idioms, is to use trait-based lazy coroutines. This approach defines a coroutine as \say{anything that \say{satisfies the trait \code{is_coroutine} and is used as a coroutine} is a coroutine}. 128 For coroutines as for threads, many implementations are based on routine pointers or function objects\cit. For example, Boost implements coroutines in terms of four functor object types: 129 \begin{cfacode} 130 asymmetric_coroutine<>::pull_type 131 asymmetric_coroutine<>::push_type 132 symmetric_coroutine<>::call_type 133 symmetric_coroutine<>::yield_type 134 \end{cfacode} 135 Often, the canonical threading paradigm in languages is based on function pointers, pthread being one of the most well known examples. The main problem of this approach is that the thread usage is limited to a generic handle that must otherwise be wrapped in a custom type. Since the custom type is simple to write in \CFA and solves several issues, added support for routine/lambda based coroutines adds very little. 136 137 A variation of this would be to use an simple function pointer in the same way pthread does for threads : 138 \begin{cfacode} 139 void foo( coroutine_t cid, void * arg ) { 140 int * value = (int *)arg; 141 //Coroutine body 142 } 143 144 int main() { 145 int value = 0; 146 coroutine_t cid = coroutine_create( &foo, (void*)&value ); 147 coroutine_resume( &cid ); 148 } 149 \end{cfacode} 150 This semantic is more common for thread interfaces than coroutines but would work equally well. As discussed in section \ref{threads}, this approach is superseeded by static approaches in terms of expressivity. 151 152 \subsection{Alternative: Trait-based coroutines} 153 154 Finally the underlying approach, which is the one closest to \CFA idioms, is to use trait-based lazy coroutines. This approach defines a coroutine as anything that satisfies the trait \code{is_coroutine} and is used as a coroutine is a coroutine. 135 155 136 156 \begin{cfacode} … … 140 160 }; 141 161 \end{cfacode} 142 143 This entails that an object is not a coroutine until \code{resume} (or \code{prime}) is called on the object. Correspondingly, any object that is passed to \code{resume} is a coroutine since it must satisfy the \code{is_coroutine} trait to compile. The advantage of this approach is that users can easily create different types of coroutines, for example, changing the memory foot print of a coroutine is trivial when implementing the \code{get_coroutine} routine. The \CFA keyword \code{coroutine} only has the effect of implementing the getter and forward declarations required for users to only have to implement the main routine. 162 This ensures an object is not a coroutine until \code{resume} (or \code{prime}) is called on the object. Correspondingly, any object that is passed to \code{resume} is a coroutine since it must satisfy the \code{is_coroutine} trait to compile. The advantage of this approach is that users can easily create different types of coroutines, for example, changing the memory foot print of a coroutine is trivial when implementing the \code{get_coroutine} routine. The \CFA keyword \code{coroutine} only has the effect of implementing the getter and forward declarations required for users to only have to implement the main routine. 163 164 \begin{center} 165 \begin{tabular}{c c c} 166 \begin{cfacode}[tabsize=3] 167 coroutine MyCoroutine { 168 int someValue; 169 }; 170 \end{cfacode} & == & \begin{cfacode}[tabsize=3] 171 struct MyCoroutine { 172 int someValue; 173 coroutine_desc __cor; 174 }; 175 176 static inline 177 coroutine_desc * get_coroutine( 178 struct MyCoroutine * this 179 ) { 180 return &this->__cor; 181 } 182 183 void main(struct MyCoroutine * this); 184 \end{cfacode} 185 \end{tabular} 186 \end{center} 187 144 188 145 189 146 190 \section{Thread Interface}\label{threads} 147 The basic building blocks of multi-threading in \CFA are \glspl{cfathread}. B y default these are implemented as \glspl{uthread}, and as such, offer a flexible and lightweight threading interface (lightweight compared to \glspl{kthread}). A thread can be declared using a SUEdeclaration \code{thread} as follows:191 The basic building blocks of multi-threading in \CFA are \glspl{cfathread}. Both use and kernel threads are supported, where user threads are the concurrency mechanism and kernel threads are the parallel mechanism. User threads offer a flexible and lightweight interface. A thread can be declared using a struct declaration \code{thread} as follows: 148 192 149 193 \begin{cfacode} … … 151 195 \end{cfacode} 152 196 153 Likefor coroutines, the keyword is a thin wrapper arount a \CFA trait:197 As for coroutines, the keyword is a thin wrapper arount a \CFA trait: 154 198 155 199 \begin{cfacode} … … 170 214 \end{cfacode} 171 215 172 In this example, threads of type \code{foo} will start there execution in the \code{void main(foo*)} routine which in this case prints \code{"Hello World!"}. While this proposoal encourages this approach which enforces strongly typeprogramming, users may prefer to use the routine based thread semantics for the sake of simplicity. With these semantics it is trivial to write a thread type that takes a function pointer as parameter and executes it on its stack asynchronously216 In this example, threads of type \code{foo} start execution in the \code{void main(foo*)} routine which prints \code{"Hello World!"}. While this proposoal encourages this approach to enforce strongly-typed programming, users may prefer to use the routine based thread semantics for the sake of simplicity. With these semantics it is trivial to write a thread type that takes a function pointer as parameter and executes it on its stack asynchronously 173 217 \begin{cfacode} 174 218 typedef void (*voidFunc)(void); … … 201 245 void main() { 202 246 World w; 203 //Thread runforks here204 205 //Printing "Hello " and "World!" will be run concurrently247 //Thread forks here 248 249 //Printing "Hello " and "World!" are run concurrently 206 250 sout | "Hello " | endl; 207 251 … … 210 254 \end{cfacode} 211 255 212 This semantic has several advantages over explicit semantics typesafety is guaranteed, a thread is always started and stopped exaclty once and users cannot make any progamming errors. However, one of the apparent drawbacks of this system is that threads now always form a lattice, that is they are always destroyed in opposite order of construction. While this seems like a significant limitation, existing \CFA semantics can solve this problem. Indeed, using dynamic allocation to create threads will naturally let threads outlive the scope in which the thread was created much like dynamically allocating memory will let objects outlive the scope in which thy were created 256 This semantic has several advantages over explicit semantics typesafety is guaranteed, a thread is always started and stopped exaclty once and users cannot make any progamming errors. Another advantage of this semantic is that it naturally scale to multiple threads meaning basic synchronisation is very simple 257 258 \begin{cfacode} 259 thread MyThread { 260 //... 261 }; 262 263 //main 264 void main(MyThread* this) { 265 //... 266 } 267 268 void foo() { 269 MyThread thrds[10]; 270 //Start 10 threads at the beginning of the scope 271 272 DoStuff(); 273 274 //Wait for the 10 threads to finish 275 } 276 \end{cfacode} 277 278 However, one of the apparent drawbacks of this system is that threads now always form a lattice, that is they are always destroyed in opposite order of construction because of block structure. However, storage allocation os not limited to blocks; dynamic allocation can create threads that outlive the scope in which the thread is created much like dynamically allocating memory lets objects outlive the scope in which they are created 213 279 214 280 \begin{cfacode} … … 241 307 } 242 308 \end{cfacode} 243 244 Another advantage of this semantic is that it naturally scale to multiple threads meaning basic synchronisation is very simple245 246 \begin{cfacode}247 thread MyThread {248 //...249 };250 251 //main252 void main(MyThread* this) {253 //...254 }255 256 void foo() {257 MyThread thrds[10];258 //Start 10 threads at the beginning of the scope259 260 DoStuff();261 262 //Wait for the 10 threads to finish263 }264 \end{cfacode} -
doc/proposals/concurrency/text/concurrency.tex
re4d829b r579263a 4 4 % ====================================================================== 5 5 % ====================================================================== 6 Several tool can be used to solve concurrency challenges. Since many of these challenges appear with the use of mutable shared-state, some languages and libraries simply disallow mutable shared-state (Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, Akka (Scala)~\cite{Akka}). In these paradigms, interaction among concurrent objects relies on message passing~\cite{Thoth,Harmony,V-Kernel} or other paradigms that closely relate to networking concepts (channels\cit for example). However, in languages that use routine calls as their core abstraction-mechanism, these approaches force a clear distinction between concurrent and non-concurrent paradigms (i.e., message passing versus routine call). This distinction in turn means that, in order to be effective, programmers need to learn two sets of designs patterns. This distinction can be hidden away in library code, effective use of the librairy still has to take both paradigms into account. Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on basic constructs like routine calls and shared objects. At a lower level, non-concurrent paradigms are often implemented as locks and atomic operations. Many such mechanisms have been proposed, including semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}. However, for productivity reasons it is desireable to have a higher-level construct be the core concurrency paradigm~\cite{HPP:Study}. An approach that is worth mentionning because it is gaining in popularity is transactionnal memory~\cite{Dice10}[Check citation]. While this approach is even pursued by system languages like \CC\cit, the performance and feature set is currently too restrictive to add such a paradigm to a language like C or \CC\cit, which is why it was rejected as the core paradigm for concurrency in \CFA. One of the most natural, elegant, and efficient mechanisms for synchronization and communication, especially for shared memory systems, is the \emph{monitor}. Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}. Many programming languages---e.g., Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}---provide monitors as explicit language constructs. In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors. For these reasons, this project proposes monitors as the core concurrency-construct. 6 Several tool can be used to solve concurrency challenges. Since many of these challenges appear with the use of mutable shared-state, some languages and libraries simply disallow mutable shared-state (Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, Akka (Scala)~\cite{Akka}). In these paradigms, interaction among concurrent objects relies on message passing~\cite{Thoth,Harmony,V-Kernel} or other paradigms that closely relate to networking concepts (channels\cit for example). However, in languages that use routine calls as their core abstraction-mechanism, these approaches force a clear distinction between concurrent and non-concurrent paradigms (i.e., message passing versus routine call). This distinction in turn means that, in order to be effective, programmers need to learn two sets of designs patterns. While this distinction can be hidden away in library code, effective use of the librairy still has to take both paradigms into account. 7 8 Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on basic constructs like routine calls and shared objects. At the lowest level, concurrent paradigms are implemented as atomic operations and locks. Many such mechanisms have been proposed, including semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}. However, for productivity reasons it is desireable to have a higher-level construct be the core concurrency paradigm~\cite{HPP:Study}. 9 10 An approach that is worth mentionning because it is gaining in popularity is transactionnal memory~\cite{Dice10}[Check citation]. While this approach is even pursued by system languages like \CC\cit, the performance and feature set is currently too restrictive to be the main concurrency paradigm for general purpose language, which is why it was rejected as the core paradigm for concurrency in \CFA. 11 12 One of the most natural, elegant, and efficient mechanisms for synchronization and communication, especially for shared memory systems, is the \emph{monitor}. Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}. Many programming languages---e.g., Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}---provide monitors as explicit language constructs. In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors. For these reasons, this project proposes monitors as the core concurrency-construct. 7 13 8 14 \section{Basics} 9 The basic features that concurrency tools neet to offer is support for mutual-exclusion and synchronisation. Mutual-exclusion is the concept that only a fixed number of threads can access a critical section at any given time, where a critical section is the group of instructions on an associated portion of data that requires the limited access. On the other hand, synchronization enforces relative ordering of execution and synchronization tools are used to guarantee that event \textit{X} always happens before \textit{Y}.15 Non-determinism requires concurrent systems to offer support for mutual-exclusion and synchronisation. Mutual-exclusion is the concept that only a fixed number of threads can access a critical section at any given time, where a critical section is a group of instructions on an associated portion of data that requires the restricted access. On the other hand, synchronization enforces relative ordering of execution and synchronization tools numerous mechanisms to establish timing relationships among threads. 10 16 11 17 \subsection{Mutual-Exclusion} 12 As mentionned above, mutual-exclusion is the guarantee that only a fix number of threads can enter a critical section at once. However, many solution exists for mutual exclusion which vary in terms of performance, flexibility and ease of use. Methods range from low level locks, which are fast and flexible but require significant attention to be correct, to higher level mutual-exclusion methods, which sacrifice some performance in order to improve ease of use. Often by either guaranteeing some problems cannot occur (e.g. being deadlock free) or by offering a more explicit coupling between data and corresponding critical section. For example, the \CC \code{std::atomic<T>} which offer an easy way to express mutual-exclusion on a restricted set of features (.e.g: reading/writing large types atomically). Another challenge with low level locks is composability. Locks are said to not be composable because it takes careful organising for multiple locks to be used and oncewhile preventing deadlocks. Easing composability is another feature higher-level mutual-exclusion mechanisms often offer.18 As mentionned above, mutual-exclusion is the guarantee that only a fix number of threads can enter a critical section at once. However, many solution exists for mutual exclusion which vary in terms of performance, flexibility and ease of use. Methods range from low-level locks, which are fast and flexible but require significant attention to be correct, to higher-level mutual-exclusion methods, which sacrifice some performance in order to improve ease of use. Ease of use comes by either guaranteeing some problems cannot occur (e.g., being deadlock free) or by offering a more explicit coupling between data and corresponding critical section. For example, the \CC \code{std::atomic<T>} which offer an easy way to express mutual-exclusion on a restricted set of operations (.e.g: reading/writing large types atomically). Another challenge with low-level locks is composability. Locks are not composable because it takes careful organising for multiple locks to be used while preventing deadlocks. Easing composability is another feature higher-level mutual-exclusion mechanisms often offer. 13 19 14 20 \subsection{Synchronization} 15 As for mutual-exclusion, low level synchronisation primitive often offer g reat performance and good flexibility at the cost of ease of use. Again, higher-level mechanism often simplify usage by adding better coupling between synchronization and data, for examplemessage passing, or offering simple solution to otherwise involved challenges. An example of this is barging. As mentionned above synchronization can be expressed as guaranteeing that event \textit{X} always happens before \textit{Y}. Most of the time synchronisation happens around a critical section, where threads most acquire said critical section in a certain order. However, it may also be desired to be able to guarantee that event \textit{Z} does not occur between \textit{X} and \textit{Y}. This is called barging, where event \textit{X} tries to effect event \textit{Y} but anoter thread races to grab the critical section and emits \textit{Z} before \textit{Y}. Preventing or detecting barging is an involved challenge with low-level locks, which can be made much easier by higher-level constructs.21 As for mutual-exclusion, low level synchronisation primitive often offer good performance and good flexibility at the cost of ease of use. Again, higher-level mechanism often simplify usage by adding better coupling between synchronization and data, .eg., message passing, or offering simple solution to otherwise involved challenges. An example of this is barging. As mentionned above synchronization can be expressed as guaranteeing that event \textit{X} always happens before \textit{Y}. Most of the time synchronisation happens around a critical section, where threads most acquire said critical section in a certain order. However, it may also be desired to be able to guarantee that event \textit{Z} does not occur between \textit{X} and \textit{Y}. This is called barging, where event \textit{X} tries to effect event \textit{Y} but anoter thread races to grab the critical section and emits \textit{Z} before \textit{Y}. Preventing or detecting barging is an involved challenge with low-level locks, which can be made much easier by higher-level constructs. 16 22 17 23 % ====================================================================== … … 20 26 % ====================================================================== 21 27 % ====================================================================== 22 A monitor is a set of routines that ensure mutual exclusion when accessing shared state. This concept is generally associated with Object-Oriented Languages like Java~\cite{Java} or \uC~\cite{uC++book} but does not strictly require OO Psemantics. The only requirements is the ability to declare a handle to a shared object and a set of routines that act on it :28 A monitor is a set of routines that ensure mutual exclusion when accessing shared state. This concept is generally associated with Object-Oriented Languages like Java~\cite{Java} or \uC~\cite{uC++book} but does not strictly require OO semantics. The only requirements is the ability to declare a handle to a shared object and a set of routines that act on it : 23 29 \begin{cfacode} 24 30 typedef /*some monitor type*/ monitor; … … 36 42 % ====================================================================== 37 43 % ====================================================================== 38 The above monitor example displays some of the intrinsic characteristics. Indeed, it is necessary to use pass-by-reference over pass-by-value for monitor routines. This semantics is important because at their core, monitors are implicit mutual-exclusion objects (locks), and these objects cannot be copied. Therefore, monitors are implicitly non-copyable.39 40 Another aspect to consider is when a monitor acquires its mutual exclusion. For example, a monitor may need to be passed through multiple helper routines that do not acquire the monitor mutual-exclusion on entry. Pass through can be bothgeneric helper routines (\code{swap}, \code{sort}, etc.) or specific helper routines like the following to implement an atomic counter :44 The above monitor example displays some of the intrinsic characteristics. First, it is necessary to use pass-by-reference over pass-by-value for monitor routines. This semantics is important because at their core, monitors are implicit mutual-exclusion objects (locks), and these objects cannot be copied. Therefore, monitors are implicitly non-copyable objects. 45 46 Another aspect to consider is when a monitor acquires its mutual exclusion. For example, a monitor may need to be passed through multiple helper routines that do not acquire the monitor mutual-exclusion on entry. Pass through can occur for generic helper routines (\code{swap}, \code{sort}, etc.) or specific helper routines like the following to implement an atomic counter : 41 47 42 48 \begin{cfacode} … … 46 52 size_t ++?(counter_t & mutex this); //increment 47 53 48 //need for mutex is platform dependent here54 //need for mutex is platform dependent 49 55 void ?{}(size_t * this, counter_t & mutex cnt); //conversion 50 56 \end{cfacode} … … 52 58 Here, the constructor(\code{?\{\}}) uses the \code{nomutex} keyword to signify that it does not acquire the monitor mutual-exclusion when constructing. This semantics is because an object not yet constructed should never be shared and therefore does not require mutual exclusion. The prefix increment operator uses \code{mutex} to protect the incrementing process from race conditions. Finally, there is a conversion operator from \code{counter_t} to \code{size_t}. This conversion may or may not require the \code{mutex} keyword depending on whether or not reading an \code{size_t} is an atomic operation. 53 59 54 Having both \code{mutex} and \code{nomutex} keywords could be argued to be redundant based on the meaning of a routine having neither of these keywords. For example, given a routine without qualifiers \code{void foo(counter_t & this)} then it is reasonable that it should default to the safest option \code{mutex}. On the other hand, the option of having routine \code{void foo(counter_t & this)} mean \code{nomutex} is unsafe by default and may easily cause subtle errors. In fact\code{nomutex} is the "normal" parameter behaviour, with the \code{nomutex} keyword effectively stating explicitly that "this routine is not special". Another alternative is to make having exactly one of these keywords mandatory, which would provide the same semantics but without the ambiguity of supporting routines neither keyword. Mandatory keywords would also have the added benefit of being self-documented but at the cost of extra typing. While there are several benefits to mandatory keywords, they do bring a few challenges. Mandatory keywords in \CFA would imply that the compiler must know without a doubt wheter or not a parameter is a monitor or not. Since \CFA relies heavily on traits as an abstraction mechanism, the distinction between a type that is a monitor and a type that looks like a monitor can become blurred. For this reason, \CFA only has the \code{mutex} keyword.60 Having both \code{mutex} and \code{nomutex} keywords is redundant based on the meaning of a routine having neither of these keywords. For example, given a routine without qualifiers \code{void foo(counter_t & this)}, then it is reasonable that it should default to the safest option \code{mutex}, whereas assuming \code{nomutex} is unsafe and may cause subtle errors. In fact, \code{nomutex} is the "normal" parameter behaviour, with the \code{nomutex} keyword effectively stating explicitly that "this routine is not special". Another alternative is to make having exactly one of these keywords mandatory, which would provide the same semantics but without the ambiguity of supporting routines neither keyword. Mandatory keywords would also have the added benefit of being self-documented but at the cost of extra typing. While there are several benefits to mandatory keywords, they do bring a few challenges. Mandatory keywords in \CFA would imply that the compiler must know without a doubt wheter or not a parameter is a monitor or not. Since \CFA relies heavily on traits as an abstraction mechanism, the distinction between a type that is a monitor and a type that looks like a monitor can become blurred. For this reason, \CFA only has the \code{mutex} keyword. 55 61 56 62 … … 60 66 int f2(const monitor & mutex m); 61 67 int f3(monitor ** mutex m); 62 int f4(monitor * [] mutex m);68 int f4(monitor * mutex m []); 63 69 int f5(graph(monitor*) & mutex m); 64 70 \end{cfacode} … … 68 74 int f1(monitor & mutex m); //Okay : recommanded case 69 75 int f2(monitor * mutex m); //Okay : could be an array but probably not 70 int f3(monitor [] mutex m); //Not Okay : Array of unkown length76 int f3(monitor mutex m []); //Not Okay : Array of unkown length 71 77 int f4(monitor ** mutex m); //Not Okay : Could be an array 72 int f5(monitor * [] mutex m); //Not Okay : Array of unkown length78 int f5(monitor * mutex m []); //Not Okay : Array of unkown length 73 79 \end{cfacode} 74 80 -
doc/proposals/concurrency/text/intro.tex
re4d829b r579263a 3 3 % ====================================================================== 4 4 5 This proposal provides a minimal concurrency API that is simple, efficient and can be reused to build higher-level features. The simplest possible concurrency core is a thread and a lock but this low-level approach is hard to master. An easier approach for users is to support higher-level constructs as the basis of the concurrency in \CFA. Indeed, for highly productive parallel programming, high-level approaches are much more popular~\cite{HPP:Study}. Examples are task based, message passing and implicit threading.5 This proposal provides a minimal concurrency API that is simple, efficient and can be reused to build higher-level features. The simplest possible concurrency system is a thread and a lock but this low-level approach is hard to master. An easier approach for users is to support higher-level constructs as the basis of the concurrency, in \CFA. Indeed, for highly productive parallel programming, high-level approaches are much more popular~\cite{HPP:Study}. Examples are task based, message passing and implicit threading. Therefore a high-level approach is adapted in \CFA 6 6 7 There are actually two problems that need to be solved in the design of concurrency for a programming language: which concurrency tools are available to the users and which parallelism tools are available. While these two concepts are often seen together, they are in fact distinct concepts that require different sorts oftools~\cite{Buhr05a}. Concurrency tools need to handle mutual exclusion and synchronization, while parallelism tools are about performance, cost and resource utilization.7 There are actually two problems that need to be solved in the design of concurrency for a programming language: which concurrency and which parallelism tools are available to the users. While these two concepts are often combined, they are in fact distinct concepts that require different tools~\cite{Buhr05a}. Concurrency tools need to handle mutual exclusion and synchronization, while parallelism tools are about performance, cost and resource utilization. -
doc/proposals/concurrency/thesis.tex
re4d829b r579263a 77 77 \fancyhf{} 78 78 \cfoot{\thepage} 79 \rfoot{v\input{ build/version}}79 \rfoot{v\input{version}} 80 80 81 81 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% … … 94 94 95 95 \input{intro} 96 97 \input{cforall} 96 98 97 99 \input{basics} -
doc/rob_thesis/intro.tex
re4d829b r579263a 3 3 %====================================================================== 4 4 5 \section{\ CFA Background}5 \section{\protect\CFA Background} 6 6 \label{s:background} 7 7 \CFA \footnote{Pronounced ``C-for-all'', and written \CFA or Cforall.} is a modern non-object-oriented extension to the C programming language. … … 370 370 \end{tabular} 371 371 \end{center} 372 \caption{\label{table:types} The different kinds of type parameters in \ CFA}372 \caption{\label{table:types} The different kinds of type parameters in \protect\CFA} 373 373 \end{table} 374 374 -
doc/rob_thesis/thesis.tex
re4d829b r579263a 66 66 % ,monochrome % toggle black and white mode 67 67 }{xcolor} 68 \PassOptionsToPackage{pdftex}{graphicx} 68 69 \documentclass[letterpaper,12pt,titlepage,oneside,final]{book} 69 70 -
doc/user/user.tex
re4d829b r579263a 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Fri Jun 2 10:07:51 201714 %% Update Count : 2 12813 %% Last Modified On : Fri Jun 16 12:00:01 2017 14 %% Update Count : 2433 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 43 43 \usepackage[pagewise]{lineno} 44 44 \renewcommand{\linenumberfont}{\scriptsize\sffamily} 45 \input{common} % bespoke macros used in the document45 \input{common} % common CFA document macros 46 46 \usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref} 47 47 \usepackage{breakurl} … … 110 110 \renewcommand{\subsectionmark}[1]{\markboth{\thesubsection\quad #1}{\thesubsection\quad #1}} 111 111 \pagenumbering{roman} 112 \linenumbers % comment out to turn off line numbering112 %\linenumbers % comment out to turn off line numbering 113 113 114 114 \maketitle … … 454 454 the type suffixes ©U©, ©L©, etc. may start with an underscore ©1_U©, ©1_ll© or ©1.0E10_f©. 455 455 \end{enumerate} 456 It is significantly easier to read and enter long constants when they are broken up into smaller groupings (m ost cultures use commaor period among digits for the same purpose).456 It is significantly easier to read and enter long constants when they are broken up into smaller groupings (many cultures use comma and/or period among digits for the same purpose). 457 457 This extension is backwards compatible, matches with the use of underscore in variable names, and appears in \Index*{Ada} and \Index*{Java} 8. 458 458 … … 464 464 \begin{cfa} 465 465 int ®`®otype®`® = 3; §\C{// make keyword an identifier}§ 466 double ®`® choose®`® = 3.5;467 \end{cfa} 468 Programs can be converted easily by enclosing keyword identifiers in backquotes, and the backquotes can be removed later when the identifier name is changed to anon-keyword name.466 double ®`®forall®`® = 3.5; 467 \end{cfa} 468 Existing C programs with keyword clashes can be converted by enclosing keyword identifiers in backquotes, and eventually the identifier name can be changed to a non-keyword name. 469 469 \VRef[Figure]{f:InterpositionHeaderFile} shows how clashes in C header files (see~\VRef{s:StandardHeaders}) can be handled using preprocessor \newterm{interposition}: ©#include_next© and ©-I filename©: 470 470 … … 473 473 // include file uses the CFA keyword "otype". 474 474 #if ! defined( otype ) §\C{// nesting ?}§ 475 #define otype `otype`475 #define otype ®`®otype®`® §\C{// make keyword an identifier}§ 476 476 #define __CFA_BFD_H__ 477 477 #endif // ! otype … … 497 497 \begin{tabular}{@{}ll@{}} 498 498 \begin{cfa} 499 int * x[5]499 int * x[5] 500 500 \end{cfa} 501 501 & … … 508 508 For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way: 509 509 \begin{cfa} 510 int (*f())[5] {...}; §\C{}§511 ... (*f())[3] += 1; 510 int ®(*®f®())[®5®]® {...}; §\C{definition}§ 511 ... ®(*®f®())[®3®]® += 1; §\C{usage}§ 512 512 \end{cfa} 513 513 Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}). … … 516 516 \CFA provides its own type, variable and routine declarations, using a different syntax. 517 517 The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type. 518 In the following example, \R{red} is for the base type and \B{blue} is for thequalifiers.518 In the following example, \R{red} is the base type and \B{blue} is qualifiers. 519 519 The \CFA declarations move the qualifiers to the left of the base type, \ie move the blue to the left of the red, while the qualifiers have the same meaning but are ordered left to right to specify a variable's type. 520 520 \begin{quote2} … … 534 534 \end{tabular} 535 535 \end{quote2} 536 The only exception is bit fieldspecification, which always appear to the right of the base type.536 The only exception is \Index{bit field} specification, which always appear to the right of the base type. 537 537 % Specifically, the character ©*© is used to indicate a pointer, square brackets ©[©\,©]© are used to represent an array or function return value, and parentheses ©()© are used to indicate a routine parameter. 538 538 However, unlike C, \CFA type declaration tokens are distributed across all variables in the declaration list. … … 583 583 \begin{cfa} 584 584 int z[ 5 ]; 585 char * w[ 5 ];586 double (* v)[ 5 ];585 char * w[ 5 ]; 586 double (* v)[ 5 ]; 587 587 struct s { 588 588 int f0:3; 589 int * f1;590 int * f2[ 5 ]589 int * f1; 590 int * f2[ 5 ] 591 591 }; 592 592 \end{cfa} … … 637 637 \begin{cfa} 638 638 int extern x[ 5 ]; 639 const int static * y;639 const int static * y; 640 640 \end{cfa} 641 641 & … … 658 658 \begin{cfa} 659 659 y = (®int *®)x; 660 i = sizeof(®int * [ 5 ]®);660 i = sizeof(®int * [ 5 ]®); 661 661 \end{cfa} 662 662 \end{tabular} … … 672 672 C provides a \newterm{pointer type}; 673 673 \CFA adds a \newterm{reference type}. 674 These types may be derived from a object or routine type, called the \newterm{referenced type}.674 These types may be derived from an object or routine type, called the \newterm{referenced type}. 675 675 Objects of these types contain an \newterm{address}, which is normally a location in memory, but may also address memory-mapped registers in hardware devices. 676 676 An integer constant expression with the value 0, or such an expression cast to type ©void *©, is called a \newterm{null-pointer constant}.\footnote{ … … 729 729 730 730 A \Index{pointer}/\Index{reference} object is a generalization of an object variable-name, \ie a mutable address that can point to more than one memory location during its lifetime. 731 (Similarly, an integer variable can contain multiple integer literals during its lifetime versus an integer constant representing a single literal during its lifetime, and like a variable name, may not occupy storage asthe literal is embedded directly into instructions.)731 (Similarly, an integer variable can contain multiple integer literals during its lifetime versus an integer constant representing a single literal during its lifetime, and like a variable name, may not occupy storage if the literal is embedded directly into instructions.) 732 732 Hence, a pointer occupies memory to store its current address, and the pointer's value is loaded by dereferencing, \eg: 733 733 \begin{quote2} … … 758 758 \begin{cfa} 759 759 p1 = p2; §\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}§ 760 p2 = p1 + x; §\C{// p2 = p1 + x\ \ rather than\ \ *p 1= *p1 + x}§760 p2 = p1 + x; §\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}§ 761 761 \end{cfa} 762 762 even though the assignment to ©p2© is likely incorrect, and the programmer probably meant: … … 765 765 ®*®p2 = ®*®p1 + x; §\C{// pointed-to value assignment / operation}§ 766 766 \end{cfa} 767 The C semantics work swell for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©).767 The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©). 768 768 769 769 However, in most other situations, the pointed-to value is requested more often than the pointer address. … … 799 799 For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}): 800 800 \begin{cfa} 801 (&®*®)r1 = &x; §\C{// (\&*) cancel giving address ofr1 not variable pointed-to by r1}§801 (&®*®)r1 = &x; §\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}§ 802 802 \end{cfa} 803 803 Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}): 804 804 \begin{cfa} 805 (&(&®*®)®*®)r3 = &(&®*®)r2; §\C{// (\&*) cancel giving address of r2, (\&(\&*)*) cancel giving address ofr3}§805 (&(&®*®)®*®)r3 = &(&®*®)r2; §\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}§ 806 806 \end{cfa} 807 807 Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth. … … 824 824 As for a pointer type, a reference type may have qualifiers: 825 825 \begin{cfa} 826 const int cx = 5; §\C{// cannot change cx;}§827 const int & cr = cx; §\C{// cannot change what cr points to}§828 ®&®cr = &cx; §\C{// can change cr}§829 cr = 7; §\C{// error, cannot change cx}§830 int & const rc = x; §\C{// must be initialized}§831 ®&®rc = &x; §\C{// error, cannot change rc}§832 const int & const crc = cx; §\C{// must be initialized}§833 crc = 7; §\C{// error, cannot change cx}§834 ®&®crc = &cx; §\C{// error, cannot change crc}§835 \end{cfa} 836 Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced into the reference}:837 \begin{cfa} 838 int & const cr = *0; §\C{// where 0 is the int * zero}§839 \end{cfa} 840 Note, constant reference-types do not prevent addressing errorsbecause of explicit storage-management:826 const int cx = 5; §\C{// cannot change cx;}§ 827 const int & cr = cx; §\C{// cannot change what cr points to}§ 828 ®&®cr = &cx; §\C{// can change cr}§ 829 cr = 7; §\C{// error, cannot change cx}§ 830 int & const rc = x; §\C{// must be initialized}§ 831 ®&®rc = &x; §\C{// error, cannot change rc}§ 832 const int & const crc = cx; §\C{// must be initialized}§ 833 crc = 7; §\C{// error, cannot change cx}§ 834 ®&®crc = &cx; §\C{// error, cannot change crc}§ 835 \end{cfa} 836 Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}: 837 \begin{cfa} 838 int & const cr = *0; §\C{// where 0 is the int * zero}§ 839 \end{cfa} 840 Note, constant reference-types do not prevent \Index{addressing errors} because of explicit storage-management: 841 841 \begin{cfa} 842 842 int & const cr = *malloc(); 843 843 cr = 5; 844 delete &cr;845 cr = 7; §\C{// unsound pointer dereference}§846 \end{cfa} 847 848 Finally, the position of the ©const© qualifier \emph{after} the pointer/reference qualifier causes confuse for C programmers.844 free( &cr ); 845 cr = 7; §\C{// unsound pointer dereference}§ 846 \end{cfa} 847 848 The position of the ©const© qualifier \emph{after} the pointer/reference qualifier causes confuse for C programmers. 849 849 The ©const© qualifier cannot be moved before the pointer/reference qualifier for C style-declarations; 850 \CFA-style declarations attempt to address this issue:850 \CFA-style declarations (see \VRef{s:Declarations}) attempt to address this issue: 851 851 \begin{quote2} 852 852 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} … … 863 863 \end{tabular} 864 864 \end{quote2} 865 where the \CFA declaration is read left-to-right (see \VRef{s:Declarations}). 865 where the \CFA declaration is read left-to-right. 866 867 Finally, like pointers, references are usable and composable with other type operators and generators. 868 \begin{cfa} 869 int w, x, y, z, & ar[3] = { x, y, z }; §\C{// initialize array of references}§ 870 &ar[1] = &w; §\C{// change reference array element}§ 871 typeof( ar[1] ) p; §\C{// (gcc) is int, i.e., the type of referenced object}§ 872 typeof( &ar[1] ) q; §\C{// (gcc) is int \&, i.e., the type of reference}§ 873 sizeof( ar[1] ) == sizeof( int ); §\C{// is true, i.e., the size of referenced object}§ 874 sizeof( &ar[1] ) == sizeof( int *) §\C{// is true, i.e., the size of a reference}§ 875 \end{cfa} 866 876 867 877 In contrast to \CFA reference types, \Index*[C++]{\CC{}}'s reference types are all ©const© references, preventing changes to the reference address, so only value assignment is possible, which eliminates half of the \Index{address duality}. 878 Also, \CC does not allow \Index{array}s\index{array!reference} of reference\footnote{ 879 The reason for disallowing arrays of reference is unknown, but possibly comes from references being ethereal (like a textual macro), and hence, replaceable by the referant object.} 868 880 \Index*{Java}'s reference types to objects (all Java objects are on the heap) are like C pointers, which always manipulate the address, and there is no (bit-wise) object assignment, so objects are explicitly cloned by shallow or deep copying, which eliminates half of the address duality. 881 882 883 \subsection{Initialization} 869 884 870 885 \Index{Initialization} is different than \Index{assignment} because initialization occurs on the empty (uninitialized) storage on an object, while assignment occurs on possibly initialized storage of an object. … … 872 887 Because the object being initialized has no value, there is only one meaningful semantics with respect to address duality: it must mean address as there is no pointed-to value. 873 888 In contrast, the left-hand side of assignment has an address that has a duality. 874 Therefore, for pointer/reference initialization, the initializing value must be an address (\Index{lvalue}) not a value (\Index{rvalue}). 875 \begin{cfa} 876 int * p = &x; §\C{// must have address of x}§ 877 int & r = x; §\C{// must have address of x}§ 878 \end{cfa} 879 Therefore, it is superfluous to require explicitly taking the address of the initialization object, even though the type is incorrect. 880 Hence, \CFA allows ©r© to be assigned ©x© because it infers a reference for ©x©, by implicitly inserting a address-of operator, ©&©, and it is an error to put an ©&© because the types no longer match. 881 Unfortunately, C allows ©p© to be assigned with ©&x© or ©x©, by value, but most compilers warn about the latter assignment as being potentially incorrect. 882 (\CFA extends pointer initialization so a variable name is automatically referenced, eliminating the unsafe assignment.) 889 Therefore, for pointer/reference initialization, the initializing value must be an address not a value. 890 \begin{cfa} 891 int * p = &x; §\C{// assign address of x}§ 892 ®int * p = x;® §\C{// assign value of x}§ 893 int & r = x; §\C{// must have address of x}§ 894 \end{cfa} 895 Like the previous example with C pointer-arithmetic, it is unlikely assigning the value of ©x© into a pointer is meaningful (again, a warning is usually given). 896 Therefore, for safety, this context requires an address, so it is superfluous to require explicitly taking the address of the initialization object, even though the type is incorrect. 897 Note, this is strictly a convenience and safety feature for a programmer. 898 Hence, \CFA allows ©r© to be assigned ©x© because it infers a reference for ©x©, by implicitly inserting a address-of operator, ©&©, and it is an error to put an ©&© because the types no longer match due to the implicit dereference. 899 Unfortunately, C allows ©p© to be assigned with ©&x© (address) or ©x© (value), but most compilers warn about the latter assignment as being potentially incorrect. 883 900 Similarly, when a reference type is used for a parameter/return type, the call-site argument does not require a reference operator for the same reason. 884 901 \begin{cfa} 885 int & f( int & r ); §\C{// reference parameter and return}§886 z = f( x ) + f( y ); §\C{// reference operator added, temporaries needed for call results}§902 int & f( int & r ); §\C{// reference parameter and return}§ 903 z = f( x ) + f( y ); §\C{// reference operator added, temporaries needed for call results}§ 887 904 \end{cfa} 888 905 Within routine ©f©, it is possible to change the argument by changing the corresponding parameter, and parameter ©r© can be locally reassigned within ©f©. … … 892 909 z = temp1 + temp2; 893 910 \end{cfa} 894 This implicit referencingis crucial for reducing the syntactic burden for programmers when using references;911 This \Index{implicit referencing} is crucial for reducing the syntactic burden for programmers when using references; 895 912 otherwise references have the same syntactic burden as pointers in these contexts. 896 913 … … 899 916 void f( ®const® int & cr ); 900 917 void g( ®const® int * cp ); 901 f( 3 ); g( &3 );902 f( x + y ); g( &(x + y) );918 f( 3 ); g( ®&®3 ); 919 f( x + y ); g( ®&®(x + y) ); 903 920 \end{cfa} 904 921 Here, the compiler passes the address to the literal 3 or the temporary for the expression ©x + y©, knowing the argument cannot be changed through the parameter. 905 (The ©&© is necessary for the pointer-type parameter to make the types match, and is a common requirement for a C programmer.) 922 The ©&© before the constant/expression for the pointer-type parameter (©g©) is a \CFA extension necessary to type match and is a common requirement before a variable in C (\eg ©scanf©). 923 Importantly, ©&3© may not be equal to ©&3©, where the references occur across calls because the temporaries maybe different on each call. 924 906 925 \CFA \emph{extends} this semantics to a mutable pointer/reference parameter, and the compiler implicitly creates the necessary temporary (copying the argument), which is subsequently pointed-to by the reference parameter and can be changed.\footnote{ 907 926 If whole program analysis is possible, and shows the parameter is not assigned, \ie it is ©const©, the temporary is unnecessary.} … … 909 928 void f( int & r ); 910 929 void g( int * p ); 911 f( 3 ); g( &3 ); §\C{// compiler implicit generates temporaries}§912 f( x + y ); g( &(x + y) ); §\C{// compiler implicit generates temporaries}§930 f( 3 ); g( ®&®3 ); §\C{// compiler implicit generates temporaries}§ 931 f( x + y ); g( ®&®(x + y) ); §\C{// compiler implicit generates temporaries}§ 913 932 \end{cfa} 914 933 Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{ … … 917 936 918 937 %\CFA attempts to handle pointers and references in a uniform, symmetric manner. 919 However, C handles routine objects in an inconsistent way.920 A routine object is both a pointer and a reference ( particle and wave).938 Finally, C handles \Index{routine object}s in an inconsistent way. 939 A routine object is both a pointer and a reference (\Index{particle and wave}). 921 940 \begin{cfa} 922 941 void f( int i ); 923 void (*fp)( int ); 924 fp = f; §\C{// reference initialization}§ 925 fp = &f; §\C{// pointer initialization}§ 926 fp = *f; §\C{// reference initialization}§ 927 fp(3); §\C{// reference invocation}§ 928 (*fp)(3); §\C{// pointer invocation}§ 929 \end{cfa} 930 A routine object is best described by a ©const© reference: 931 \begin{cfa} 932 const void (&fr)( int ) = f; 933 fr = ... §\C{// error, cannot change code}§ 934 &fr = ...; §\C{// changing routine reference}§ 935 fr( 3 ); §\C{// reference call to f}§ 936 (*fr)(3); §\C{// error, incorrect type}§ 942 void (*fp)( int ); §\C{// routine pointer}§ 943 fp = f; §\C{// reference initialization}§ 944 fp = &f; §\C{// pointer initialization}§ 945 fp = *f; §\C{// reference initialization}§ 946 fp(3); §\C{// reference invocation}§ 947 (*fp)(3); §\C{// pointer invocation}§ 948 \end{cfa} 949 While C's treatment of routine objects has similarity to inferring a reference type in initialization contexts, the examples are assignment not initialization, and all possible forms of assignment are possible (©f©, ©&f©, ©*f©) without regard for type. 950 Instead, a routine object should be referenced by a ©const© reference: 951 \begin{cfa} 952 ®const® void (®&® fr)( int ) = f; §\C{// routine reference}§ 953 fr = ... §\C{// error, cannot change code}§ 954 &fr = ...; §\C{// changing routine reference}§ 955 fr( 3 ); §\C{// reference call to f}§ 956 (*fr)(3); §\C{// error, incorrect type}§ 937 957 \end{cfa} 938 958 because the value of the routine object is a routine literal, \ie the routine code is normally immutable during execution.\footnote{ … … 940 960 \CFA allows this additional use of references for routine objects in an attempt to give a more consistent meaning for them. 941 961 942 This situation is different from inferring with reference type being used ... 943 962 963 \subsection{Address-of Semantics} 964 965 In C, ©&E© is an rvalue for any expression ©E©. 966 \CFA extends the ©&© (address-of) operator as follows: 967 \begin{itemize} 968 \item 969 if ©R© is an \Index{rvalue} of type ©T &$_1$...&$_r$© where $r \ge 1$ references (©&© symbols) than ©&R© has type ©T ®*®&$_{\color{red}2}$...&$_{\color{red}r}$©, \ie ©T© pointer with $r-1$ references (©&© symbols). 970 971 \item 972 if ©L© is an \Index{lvalue} of type ©T &$_1$...&$_l$© where $l \ge 0$ references (©&© symbols) then ©&L© has type ©T ®*®&$_{\color{red}1}$...&$_{\color{red}l}$©, \ie ©T© pointer with $l$ references (©&© symbols). 973 \end{itemize} 974 The following example shows the first rule applied to different \Index{rvalue} contexts: 975 \begin{cfa} 976 int x, * px, ** ppx, *** pppx, **** ppppx; 977 int & rx = x, && rrx = rx, &&& rrrx = rrx ; 978 x = rrrx; // rrrx is an lvalue with type int &&& (equivalent to x) 979 px = &rrrx; // starting from rrrx, &rrrx is an rvalue with type int *&&& (&x) 980 ppx = &&rrrx; // starting from &rrrx, &&rrrx is an rvalue with type int **&& (&rx) 981 pppx = &&&rrrx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (&rrx) 982 ppppx = &&&&rrrx; // starting from &&&rrrx, &&&&rrrx is an rvalue with type int **** (&rrrx) 983 \end{cfa} 984 The following example shows the second rule applied to different \Index{lvalue} contexts: 985 \begin{cfa} 986 int x, * px, ** ppx, *** pppx; 987 int & rx = x, && rrx = rx, &&& rrrx = rrx ; 988 rrrx = 2; // rrrx is an lvalue with type int &&& (equivalent to x) 989 &rrrx = px; // starting from rrrx, &rrrx is an rvalue with type int *&&& (rx) 990 &&rrrx = ppx; // starting from &rrrx, &&rrrx is an rvalue with type int **&& (rrx) 991 &&&rrrx = pppx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (rrrx) 992 \end{cfa} 993 994 995 \subsection{Conversions} 996 997 C provides a basic implicit conversion to simplify variable usage: 998 \begin{enumerate} 999 \setcounter{enumi}{-1} 1000 \item 1001 lvalue to rvalue conversion: ©cv T© converts to ©T©, which allows implicit variable dereferencing. 1002 \begin{cfa} 1003 int x; 1004 x + 1; // lvalue variable (int) converts to rvalue for expression 1005 \end{cfa} 1006 An rvalue has no type qualifiers (©cv©), so the lvalue qualifiers are dropped. 1007 \end{enumerate} 1008 \CFA provides three new implicit conversion for reference types to simplify reference usage. 1009 \begin{enumerate} 1010 \item 1011 reference to rvalue conversion: ©cv T &© converts to ©T©, which allows implicit reference dereferencing. 1012 \begin{cfa} 1013 int x, &r = x, f( int p ); 1014 x = ®r® + f( ®r® ); // lvalue reference converts to rvalue 1015 \end{cfa} 1016 An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped. 1017 1018 \item 1019 lvalue to reference conversion: \lstinline[deletekeywords={lvalue}]@lvalue-type cv1 T@ converts to ©cv2 T &©, which allows implicitly converting variables to references. 1020 \begin{cfa} 1021 int x, &r = ®x®, f( int & p ); // lvalue variable (int) convert to reference (int &) 1022 f( ®x® ); // lvalue variable (int) convert to reference (int &) 1023 \end{cfa} 1024 Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost. 1025 Conversion can expand a type, where ©cv1© $>$ ©cv2©, \eg passing a ©const volatile int© to an ©int &©, which has high cost (\Index{warning}); 1026 furthermore, if ©cv1© has ©const© but not ©cv2©, a temporary variable is created to preserve the immutable lvalue. 1027 1028 \item 1029 rvalue to reference conversion: ©T© converts to ©cv T &©, which allows binding references to temporaries. 1030 \begin{cfa} 1031 int x, & f( int & p ); 1032 f( ®x + 3® ); // rvalue parameter (int) implicitly converts to lvalue temporary reference (int &) 1033 ®&f®(...) = &x; // rvalue result (int &) implicitly converts to lvalue temporary reference (int &) 1034 \end{cfa} 1035 In both case, modifications to the temporary are inaccessible (\Index{warning}). 1036 Conversion expands the temporary-type with ©cv©, which is low cost since the temporary is inaccessible. 1037 \end{enumerate} 944 1038 945 1039 946 1040 \begin{comment} 947 \section{References}948 949 By introducing references in parameter types, users are given an easy way to pass a value by reference, without the need for NULL pointer checks.950 In structures, a reference can replace a pointer to an object that should always have a valid value.951 When a structure contains a reference, all of its constructors must initialize the reference and all instances of this structure must initialize it upon definition.952 953 The syntax for using references in \CFA is the same as \CC with the exception of reference initialization.954 Use ©&© to specify a reference, and access references just like regular objects, not like pointers (use dot notation to access fields).955 When initializing a reference, \CFA uses a different syntax which differentiates reference initialization from assignment to a reference.956 The ©&© is used on both sides of the expression to clarify that the address of the reference is being set to the address of the variable to which it refers.957 958 959 1041 From: Richard Bilson <rcbilson@gmail.com> 960 1042 Date: Wed, 13 Jul 2016 01:58:58 +0000 … … 1118 1200 \section{Routine Definition} 1119 1201 1120 \CFA also supports a new syntax for routine definition, as well as ISO Cand K\&R routine syntax.1202 \CFA also supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax. 1121 1203 The point of the new syntax is to allow returning multiple values from a routine~\cite{Galletly96,CLU}, \eg: 1122 1204 \begin{cfa} … … 1138 1220 in both cases the type is assumed to be void as opposed to old style C defaults of int return type and unknown parameter types, respectively, as in: 1139 1221 \begin{cfa} 1140 [§\,§] g(); §\C{// no input or output parameters}§1141 [ void ] g( void ); §\C{// no input or output parameters}§1222 [§\,§] g(); §\C{// no input or output parameters}§ 1223 [ void ] g( void ); §\C{// no input or output parameters}§ 1142 1224 \end{cfa} 1143 1225 … … 1157 1239 \begin{cfa} 1158 1240 typedef int foo; 1159 int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§1241 int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§ 1160 1242 \end{cfa} 1161 1243 The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to foo. … … 1165 1247 C-style declarations can be used to declare parameters for \CFA style routine definitions, \eg: 1166 1248 \begin{cfa} 1167 [ int ] f( * int, int * ); §\C{// returns an integer, accepts 2 pointers to integers}§1168 [ * int, int * ] f( int ); §\C{// returns 2 pointers to integers, accepts an integer}§1249 [ int ] f( * int, int * ); §\C{// returns an integer, accepts 2 pointers to integers}§ 1250 [ * int, int * ] f( int ); §\C{// returns 2 pointers to integers, accepts an integer}§ 1169 1251 \end{cfa} 1170 1252 The reason for allowing both declaration styles in the new context is for backwards compatibility with existing preprocessor macros that generate C-style declaration-syntax, as in: 1171 1253 \begin{cfa} 1172 1254 #define ptoa( n, d ) int (*n)[ d ] 1173 int f( ptoa( p, 5 ) ) ... §\C{// expands to int f( int (*p)[ 5 ] )}§1174 [ int ] f( ptoa( p, 5 ) ) ... §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§1255 int f( ptoa( p, 5 ) ) ... §\C{// expands to int f( int (*p)[ 5 ] )}§ 1256 [ int ] f( ptoa( p, 5 ) ) ... §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§ 1175 1257 \end{cfa} 1176 1258 Again, programmers are highly encouraged to use one declaration form or the other, rather than mixing the forms. … … 1194 1276 int z; 1195 1277 ... x = 0; ... y = z; ... 1196 ®return;® 1278 ®return;® §\C{// implicitly return x, y}§ 1197 1279 } 1198 1280 \end{cfa} … … 1204 1286 [ int x, int y ] f() { 1205 1287 ... 1206 } 1288 } §\C{// implicitly return x, y}§ 1207 1289 \end{cfa} 1208 1290 In this case, the current values of ©x© and ©y© are returned to the calling routine just as if a ©return© had been encountered. 1291 1292 Named return values may be used in conjunction with named parameter values; 1293 specifically, a return and parameter can have the same name. 1294 \begin{cfa} 1295 [ int x, int y ] f( int, x, int y ) { 1296 ... 1297 } §\C{// implicitly return x, y}§ 1298 \end{cfa} 1299 This notation allows the compiler to eliminate temporary variables in nested routine calls. 1300 \begin{cfa} 1301 [ int x, int y ] f( int, x, int y ); §\C{// prototype declaration}§ 1302 int a, b; 1303 [a, b] = f( f( f( a, b ) ) ); 1304 \end{cfa} 1305 While the compiler normally ignores parameters names in prototype declarations, here they are used to eliminate temporary return-values by inferring that the results of each call are the inputs of the next call, and ultimately, the left-hand side of the assignment. 1306 Hence, even without the body of routine ©f© (separate compilation), it is possible to perform a global optimization across routine calls. 1307 The compiler warns about naming inconsistencies between routine prototype and definition in this case, and behaviour is \Index{undefined} if the programmer is inconsistent. 1209 1308 1210 1309 … … 1214 1313 as well, parameter names are optional, \eg: 1215 1314 \begin{cfa} 1216 [ int x ] f (); §\C{// returning int with no parameters}§1217 [ * int ] g (int y); §\C{// returning pointer to int with int parameter}§1218 [ ] h ( int,char);§\C{// returning no result with int and char parameters}§1219 [ * int, int ] j (int);§\C{// returning pointer to int and int, with int parameter}§1315 [ int x ] f (); §\C{// returning int with no parameters}§ 1316 [ * int ] g (int y); §\C{// returning pointer to int with int parameter}§ 1317 [ ] h ( int, char ); §\C{// returning no result with int and char parameters}§ 1318 [ * int, int ] j ( int ); §\C{// returning pointer to int and int, with int parameter}§ 1220 1319 \end{cfa} 1221 1320 This syntax allows a prototype declaration to be created by cutting and pasting source text from the routine definition header (or vice versa). … … 1225 1324 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1226 1325 \begin{cfa} 1227 [ int ] f( int), g;1326 [ int ] f( int ), g; 1228 1327 \end{cfa} 1229 1328 & 1230 1329 \begin{cfa} 1231 int f( int), g(int);1330 int f( int ), g( int ); 1232 1331 \end{cfa} 1233 1332 \end{tabular} … … 1235 1334 Declaration qualifiers can only appear at the start of a \CFA routine declaration,\footref{StorageClassSpecifier} \eg: 1236 1335 \begin{cfa} 1237 extern [ int ] f ( int);1238 static [ int ] g ( int);1336 extern [ int ] f ( int ); 1337 static [ int ] g ( int ); 1239 1338 \end{cfa} 1240 1339 … … 1244 1343 The syntax for pointers to \CFA routines specifies the pointer name on the right, \eg: 1245 1344 \begin{cfa} 1246 * [ int x ] () fp; §\C{// pointer to routine returning int with no parameters}§1247 * [ * int ] (int y) gp; §\C{// pointer to routine returning pointer to int with int parameter}§1248 * [ ] (int,char) hp; §\C{// pointer to routine returning no result with int and char parameters}§1249 * [ * int,int ] ( int) jp;§\C{// pointer to routine returning pointer to int and int, with int parameter}§1345 * [ int x ] () fp; §\C{// pointer to routine returning int with no parameters}§ 1346 * [ * int ] (int y) gp; §\C{// pointer to routine returning pointer to int with int parameter}§ 1347 * [ ] (int,char) hp; §\C{// pointer to routine returning no result with int and char parameters}§ 1348 * [ * int,int ] ( int ) jp; §\C{// pointer to routine returning pointer to int and int, with int parameter}§ 1250 1349 \end{cfa} 1251 1350 While parameter names are optional, \emph{a routine name cannot be specified}; 1252 1351 for example, the following is incorrect: 1253 1352 \begin{cfa} 1254 * [ int x ] f () fp; §\C{// routine name "f" is not allowed}§1353 * [ int x ] f () fp; §\C{// routine name "f" is not allowed}§ 1255 1354 \end{cfa} 1256 1355 … … 1258 1357 \section{Named and Default Arguments} 1259 1358 1260 Named and defaultarguments~\cite{Hardgrave76}\footnote{1359 Named\index{named arguments}\index{arguments!named} and default\index{default arguments}\index{arguments!default} arguments~\cite{Hardgrave76}\footnote{ 1261 1360 Francez~\cite{Francez77} proposed a further extension to the named-parameter passing style, which specifies what type of communication (by value, by reference, by name) the argument is passed to the routine.} 1262 1361 are two mechanisms to simplify routine call. … … 1439 1538 int ; §\C{// disallowed, unnamed field}§ 1440 1539 int *; §\C{// disallowed, unnamed field}§ 1441 int (*)( int); §\C{// disallowed, unnamed field}§1540 int (*)( int ); §\C{// disallowed, unnamed field}§ 1442 1541 }; 1443 1542 \end{cfa} … … 1562 1661 } 1563 1662 int main() { 1564 * [int]( int) fp = foo(); §\C{// int (*fp)(int)}§1663 * [int]( int ) fp = foo(); §\C{// int (*fp)( int )}§ 1565 1664 sout | fp( 3 ) | endl; 1566 1665 } … … 2683 2782 2684 2783 2685 \s ubsection{Constructors and Destructors}2784 \section{Constructors and Destructors} 2686 2785 2687 2786 \CFA supports C initialization of structures, but it also adds constructors for more advanced initialization. … … 3014 3113 3015 3114 3115 \begin{comment} 3016 3116 \section{Generics} 3017 3117 … … 3220 3320 } 3221 3321 \end{cfa} 3322 \end{comment} 3222 3323 3223 3324 … … 3279 3380 Complex *p3 = new(0.5, 1.0); // allocate + 2 param constructor 3280 3381 } 3281 3282 3382 \end{cfa} 3283 3383 … … 3291 3391 3292 3392 3393 \begin{comment} 3293 3394 \subsection{Unsafe C Constructs} 3294 3395 … … 3301 3402 The exact set of unsafe C constructs that will be disallowed in \CFA has not yet been decided, but is sure to include pointer arithmetic, pointer casting, etc. 3302 3403 Once the full set is decided, the rules will be listed here. 3404 \end{comment} 3303 3405 3304 3406 3305 3407 \section{Concurrency} 3306 3307 Today's processors for nearly all use cases, ranging from embedded systems to large cloud computing servers, are composed of multiple cores, often heterogeneous.3308 As machines grow in complexity, it becomes more difficult for a program to make the most use of the hardware available.3309 \CFA includes built-in concurrency features to enable high performance and improve programmer productivity on these multi-/many-core machines.3310 3408 3311 3409 Concurrency support in \CFA is implemented on top of a highly efficient runtime system of light-weight, M:N, user level threads. … … 3314 3412 This enables a very familiar interface to all programmers, even those with no parallel programming experience. 3315 3413 It also allows the compiler to do static type checking of all communication, a very important safety feature. 3316 This controlled communication with type safety has some similarities with channels in \Index*{Go}, and can actually implement 3317 channels exactly, as well as create additional communication patterns that channels cannot. 3414 This controlled communication with type safety has some similarities with channels in \Index*{Go}, and can actually implement channels exactly, as well as create additional communication patterns that channels cannot. 3318 3415 Mutex objects, monitors, are used to contain mutual exclusion within an object and synchronization across concurrent threads. 3319 3416 3320 Three new keywords are added to support these features: 3321 3322 monitor creates a structure with implicit locking when accessing fields 3323 3324 mutex implies use of a monitor requiring the implicit locking 3325 3326 task creates a type with implicit locking, separate stack, and a thread 3417 \begin{figure} 3418 \begin{cfa} 3419 #include <fstream> 3420 #include <coroutine> 3421 3422 coroutine Fibonacci { 3423 int fn; §\C{// used for communication}§ 3424 }; 3425 void ?{}( Fibonacci * this ) { 3426 this->fn = 0; 3427 } 3428 void main( Fibonacci * this ) { 3429 int fn1, fn2; §\C{// retained between resumes}§ 3430 this->fn = 0; §\C{// case 0}§ 3431 fn1 = this->fn; 3432 suspend(); §\C{// return to last resume}§ 3433 3434 this->fn = 1; §\C{// case 1}§ 3435 fn2 = fn1; 3436 fn1 = this->fn; 3437 suspend(); §\C{// return to last resume}§ 3438 3439 for ( ;; ) { §\C{// general case}§ 3440 this->fn = fn1 + fn2; 3441 fn2 = fn1; 3442 fn1 = this->fn; 3443 suspend(); §\C{// return to last resume}§ 3444 } // for 3445 } 3446 int next( Fibonacci * this ) { 3447 resume( this ); §\C{// transfer to last suspend}§ 3448 return this->fn; 3449 } 3450 int main() { 3451 Fibonacci f1, f2; 3452 for ( int i = 1; i <= 10; i += 1 ) { 3453 sout | next( &f1 ) | ' ' | next( &f2 ) | endl; 3454 } // for 3455 } 3456 \end{cfa} 3457 \caption{Fibonacci Coroutine} 3458 \label{f:FibonacciCoroutine} 3459 \end{figure} 3460 3461 3462 \subsection{Coroutine} 3463 3464 \Index{Coroutines} are the precursor to tasks. 3465 \VRef[Figure]{f:FibonacciCoroutine} shows a coroutine that computes the \Index*{Fibonacci} numbers. 3327 3466 3328 3467 … … 3339 3478 \end{cfa} 3340 3479 3480 \begin{figure} 3481 \begin{cfa} 3482 #include <fstream> 3483 #include <kernel> 3484 #include <monitor> 3485 #include <thread> 3486 3487 monitor global_t { 3488 int value; 3489 }; 3490 3491 void ?{}(global_t * this) { 3492 this->value = 0; 3493 } 3494 3495 static global_t global; 3496 3497 void increment3( global_t * mutex this ) { 3498 this->value += 1; 3499 } 3500 void increment2( global_t * mutex this ) { 3501 increment3( this ); 3502 } 3503 void increment( global_t * mutex this ) { 3504 increment2( this ); 3505 } 3506 3507 thread MyThread {}; 3508 3509 void main( MyThread* this ) { 3510 for(int i = 0; i < 1_000_000; i++) { 3511 increment( &global ); 3512 } 3513 } 3514 int main(int argc, char* argv[]) { 3515 processor p; 3516 { 3517 MyThread f[4]; 3518 } 3519 sout | global.value | endl; 3520 } 3521 \end{cfa} 3522 \caption{Atomic-Counter Monitor} 3523 \caption{f:AtomicCounterMonitor} 3524 \end{figure} 3525 3526 \begin{comment} 3341 3527 Since a monitor structure includes an implicit locking mechanism, it does not make sense to copy a monitor; 3342 3528 it is always passed by reference. … … 3385 3571 } 3386 3572 \end{cfa} 3573 \end{comment} 3387 3574 3388 3575 … … 3392 3579 A task provides mutual exclusion like a monitor, and also has its own execution state and a thread of control. 3393 3580 Similar to a monitor, a task is defined like a structure: 3581 3582 \begin{figure} 3583 \begin{cfa} 3584 #include <fstream> 3585 #include <kernel> 3586 #include <stdlib> 3587 #include <thread> 3588 3589 thread First { signal_once * lock; }; 3590 thread Second { signal_once * lock; }; 3591 3592 void ?{}( First * this, signal_once* lock ) { this->lock = lock; } 3593 void ?{}( Second * this, signal_once* lock ) { this->lock = lock; } 3594 3595 void main( First * this ) { 3596 for ( int i = 0; i < 10; i += 1 ) { 3597 sout | "First : Suspend No." | i + 1 | endl; 3598 yield(); 3599 } 3600 signal( this->lock ); 3601 } 3602 3603 void main( Second * this ) { 3604 wait( this->lock ); 3605 for ( int i = 0; i < 10; i += 1 ) { 3606 sout | "Second : Suspend No." | i + 1 | endl; 3607 yield(); 3608 } 3609 } 3610 3611 int main( void ) { 3612 signal_once lock; 3613 sout | "User main begin" | endl; 3614 { 3615 processor p; 3616 { 3617 First f = { &lock }; 3618 Second s = { &lock }; 3619 } 3620 } 3621 sout | "User main end" | endl; 3622 } 3623 \end{cfa} 3624 \caption{Simple Tasks} 3625 \label{f:SimpleTasks} 3626 \end{figure} 3627 3628 3629 \begin{comment} 3394 3630 \begin{cfa} 3395 3631 type Adder = task { … … 3445 3681 \end{cfa} 3446 3682 3447 3448 3683 \subsection{Cooperative Scheduling} 3449 3684 … … 3558 3793 } 3559 3794 \end{cfa} 3560 3561 3795 \end{comment} 3796 3797 3798 \begin{comment} 3562 3799 \section{Modules and Packages } 3563 3800 3564 \begin{comment}3565 3801 High-level encapsulation is useful for organizing code into reusable units, and accelerating compilation speed. 3566 3802 \CFA provides a convenient mechanism for creating, building and sharing groups of functionality that enhances productivity and improves compile time. … … 4226 4462 4227 4463 4464 \begin{comment} 4228 4465 \subsection[Comparing Key Features of CFA]{Comparing Key Features of \CFA} 4229 4466 … … 4603 4840 4604 4841 4605 \begin{comment}4606 4842 \subsubsection{Modules / Packages} 4607 4843 … … 4683 4919 } 4684 4920 \end{cfa} 4685 \end{comment}4686 4921 4687 4922 … … 4844 5079 4845 5080 \subsection{Summary of Language Comparison} 4846 4847 4848 \subsubsection[C++]{\CC} 5081 \end{comment} 5082 5083 5084 \subsection[C++]{\CC} 4849 5085 4850 5086 \Index*[C++]{\CC{}} is a general-purpose programming language. … … 4867 5103 4868 5104 4869 \subs ubsection{Go}5105 \subsection{Go} 4870 5106 4871 5107 \Index*{Go}, also commonly referred to as golang, is a programming language developed at Google in 2007 [.]. … … 4883 5119 4884 5120 4885 \subs ubsection{Rust}5121 \subsection{Rust} 4886 5122 4887 5123 \Index*{Rust} is a general-purpose, multi-paradigm, compiled programming language developed by Mozilla Research. … … 4897 5133 4898 5134 4899 \subs ubsection{D}5135 \subsection{D} 4900 5136 4901 5137 The \Index*{D} programming language is an object-oriented, imperative, multi-paradigm system programming … … 5009 5245 \item[Rationale:] keywords added to implement new semantics of \CFA. 5010 5246 \item[Effect on original feature:] change to semantics of well-defined feature. \\ 5011 Any ISO Cprograms using these keywords as identifiers are invalid \CFA programs.5247 Any \Celeven programs using these keywords as identifiers are invalid \CFA programs. 5012 5248 \item[Difficulty of converting:] keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism (see~\VRef{s:BackquoteIdentifiers}). 5013 5249 \item[How widely used:] clashes among new \CFA keywords and existing identifiers are rare. … … 5229 5465 hence, names in these include files are not mangled\index{mangling!name} (see~\VRef{s:Interoperability}). 5230 5466 All other C header files must be explicitly wrapped in ©extern "C"© to prevent name mangling. 5467 For \Index*[C++]{\CC{}}, the name-mangling issue is handled implicitly because most C header-files are augmented with checks for preprocessor variable ©__cplusplus©, which adds appropriate ©extern "C"© qualifiers. 5231 5468 5232 5469 … … 5311 5548 } 5312 5549 5313 // §\CFA§ safe initialization/copy 5550 // §\CFA§ safe initialization/copy, i.e., implicit size specification 5314 5551 forall( dtype T | sized(T) ) T * memset( T * dest, char c );§\indexc{memset}§ 5315 5552 forall( dtype T | sized(T) ) T * memcpy( T * dest, const T * src );§\indexc{memcpy}§ … … 5421 5658 \leavevmode 5422 5659 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 5423 forall( otype T | { int ?<?( T, T ); } ) 5424 T min( T t1, T t2 );§\indexc{min}§ 5425 5426 forall( otype T | { int ?>?( T, T ); } ) 5427 T max( T t1, T t2 );§\indexc{max}§ 5428 5429 forall( otype T | { T min( T, T ); T max( T, T ); } ) 5430 T clamp( T value, T min_val, T max_val );§\indexc{clamp}§ 5431 5432 forall( otype T ) 5433 void swap( T * t1, T * t2 );§\indexc{swap}§ 5660 forall( otype T | { int ?<?( T, T ); } ) T min( T t1, T t2 );§\indexc{min}§ 5661 forall( otype T | { int ?>?( T, T ); } ) T max( T t1, T t2 );§\indexc{max}§ 5662 forall( otype T | { T min( T, T ); T max( T, T ); } ) T clamp( T value, T min_val, T max_val );§\indexc{clamp}§ 5663 forall( otype T ) void swap( T * t1, T * t2 );§\indexc{swap}§ 5434 5664 \end{cfa} 5435 5665 -
doc/working/exception/design.txt
re4d829b r579263a 1 1 Design of Exceptions and EHM in Cforall: 2 2 3 Currently this is a combination of ideas and big questions that still have to 4 be addressed. It also includes some other error handling options, how they 5 interact and compare to exceptions. 3 4 Exception Instances: 5 Currently, exceptions are integers (like errno). 6 7 They are planned to be the new "tagged structures", which allows them to 8 exist in a simple hierarchy which shared functionality throughout. However 9 the tagged structures are not yet implemented so that will wait. 10 11 A single built in exception is at the top of the hierarchy and all other 12 exceptions are its children. When you match against an exception, you match 13 for an exception and its children, so the top of the hierarchy is used as a 14 catch-all option. 15 16 The shared functionality across exceptions has not been finalized, but will 17 probably include things like human readable descriptions and default handlers. 6 18 7 19 8 What is an Exception: 20 Throwing: 21 There are currently two kinds of throws, "throw" for termination and 22 "throwResume" for resumption. Both keywords can be used to create a throw 23 statement. The kind of throw decides what handlers may catch the exception 24 and weither control flow can return to the throw site. 9 25 10 In other words what do we throw? What is matched against, how does it carry 11 data with it? A very important question that has not been answered. 26 Syntax 27 "throw" exception ";" 28 "throwResume" exception ";" 12 29 13 Option 1: Strutures 30 Non-local throws are allowed for resumption only. A target is an object with 31 a stack, with which it may propagate and handle the exception. 14 32 15 Considering the current state of Cforall the most natural form of the 16 exception would likely be a struture, implementing a trait repersenting the 17 minimum features of an exception. This has many advantages, including arbitray 18 fields, some polymorphism and it matches exceptations of many current systems. 33 Syntax 34 "throwResume" exception "_At" target ";" 19 35 20 The main issue with this is matching, without OOP inheritance there is no 21 exception hierarchy. Meaning all handling has to happen on the exact exception 22 without the ease of grouping parents. There are several ways to attempt to 23 recover this. 24 25 The first is with conditional matching (a check after the type has been 26 matched) which allows for matching particular values of a known type. However 27 this does not dynamically expand and requires an extra step (as opposed to 28 mearly allowing one). I would not recomend this as the primary method. 29 30 Second is to try and use type casts/conversions to create an implicate 31 hierachy, so that a catch clause catches anything of the given type or 32 anything that converts to the given type. 33 34 Plan9 (from what I know of it) would be a powerful tool here. Even with it, 35 creating a hierarchy of types at runtime might be too expencive. Esecially 36 since they are less likely to be tree like at that point. 37 38 Option 2: Tags 39 40 The other option is to introduce a new construct into the language. A tag 41 repersents a type of exception, it is not a structure or variable (or even 42 a normal type). It may be usable in some of those contexts. 43 44 Tags can declare an existing tag as its parent. Tags can be caught by handlers 45 that catch their parents. (There is a single base_exception that all other 46 exceptions are children of eventually.) This allows for grouping of exceptions 47 that repersent similar errors. 48 49 Tags should also have some assotiated data, where and on what did the error 50 occur. Keeping with the otherness of exception tags and allowing them to be 51 expanded, using a parameter list. Each exception can have a list of paramters 52 given to it on a throw. Each tag would have a declared list of parameters 53 (which could be treated more like a set of fields as well). Child tags must 54 use their parent's list as a prefix to their own, so that the parameters can 55 be accessed when the child tag is matched against the parent. 56 57 Option N: ... 58 59 This list is not complete. 36 Termination throws unwind the stack until a handler is reached, control moves 37 onwards from the end of the handler. Resumption throws do not unwind, if a 38 handler is found and control will return to the throw after the exception is 39 handled. 60 40 61 41 62 Seperating Termination and Resumption: 42 Catching: 43 The catch and handle of an exception is preformed with a try statement, which 44 also can have finally clauses to exceute on exit from the scope. 63 45 64 Differentating the types of exceptions based on exception would be hard with 65 exceptions as structures. It is possible with exceptions as tags by having 66 two base exceptions, one for each type of throw. However recompining them 67 to dual types would be harder. 46 Syntax 47 "try" 48 try-block 49 ( ("catch" | "catchResume") 50 "(" exception_type [identifier] [";" conditional_expression] ")" 51 catch-block 52 )* 53 ("finally" 54 finally-block 55 )? 68 56 69 Reguardless, using different keywords would also be useful for clarity, even 70 if it does not add functality. Using the C++ like keywords would be a good 71 base. Resumption exceptions could use a different set (ex. raise->handle) or 72 use resume as a qualifier on the existing statements. 57 Either at least 1 handler clause or the finally clasue must be given on each 58 try block. Each handler clause handles 1 of the two types of throws. Each 59 handler also specifies a type of exception it handles, and will handle all 60 children exceptions as well. In addition, a conditional expression which, if 61 included, must be true for the handler to catch the exception. 62 63 The two types of handlers may be intermixed. Multiple handlers catching the 64 same type may also be used, to allow for fallbacks on false conditionals. 73 65 74 66 75 Conditional Matching:67 Implementation Overview: 76 68 77 A possible useful feature, it allows for arbitrary checks on a catch block 78 instead of merely matching a type. However there are few use cases that 79 cannot be avoided with proper use of a type hierarchy, and this shrinks even 80 further with a good use of re-throws.69 The implementation has two main parts. The first is just a collection of the 70 support definitions we need, the data types and functions used within the 71 exception handling code. Second is a translation from Cforall code to C code 72 that uses those definitions to throw, catch and handle exceptions. 81 73 82 Also it assumes one sweep, that might also be a problem. But might also give 83 it an advantage over re-throws. 74 Termination handlers call a specially annotated function, passing it inner 75 functions that act as the varius sub-blocks. Termination throws use the 76 unwind library that checks the underlying code for those annotations. Each 77 time one is found some magic is used to check for a matching handler, if one 78 is found control goes to the special function which excecutes the handler and 79 returns. 80 81 Resumption handlers maintain a linked list of stack allocated nodes that have 82 the handler functions attached. Throwing a resumption exception traverses this 83 list, and calls each handler, the handlers handle the exception if they can 84 and return if they did or not. 85 86 Finally clauses just use stack cleanup to force a nested function, which has 87 the code from the finally clause, to execute when we leave that section. 84 88 85 89 86 Alternative s: Implicate Handlers &Return Unions90 Alternative Error Handling: Return Unions 87 91 88 Both act as a kind of local version of an exception. Implicate handlers act as 89 resumption exceptions and return unions like termination exceptions. By local 90 I mean they work well at one or two levels of calls, but do not cover N levels 91 as cleanly. 92 Return unions (Maybe and Result), are types that can encode a success or 93 other result in a single value. Maybe stores a value or nothing, Result stores 94 a value or an error. 92 95 93 Implicate handles require a growing number of function pointers (which should 94 not be used very often) to be passed to functions, creating and additional 95 preformance cost. Return unions have to be checked and handled at every level, 96 which has some preformance cost, but also can significantly clutter code. 97 Proper tools can help with the latter. 96 For errors that are usually handled quite close to where they occur, these 97 can replace exceptions. 98 98 99 However, they may work better at that local level as they do not require stack 100 walking or unwinding. In addition they are closer to regular control flow and 101 are easier to staticly check. So even if they can't replace exceptions 102 (directly) they may still be worth using together. 103 104 For instance, consider the Python iterator interface. It uses a single 105 function, __next__, to access the next value and to signal the end of the 106 sequence. If a value is returned, it is the next value, if the StopIteration 107 exception is thrown the sequence has finished. 108 109 However almost every use of an iterator will add a try-except block around the 110 call site (possibly through for or next) to catch and handle the exception 111 immediately, ignoring the advantages of more distant exception handling. 112 113 In this case it may be cleaner to use a Maybe for both cases (as in Rust) 114 which gives similar results without having to jump to the exception handler. 115 This will likely handle the error case more efficiently and the success case a 116 bit less so. 117 118 It also mixes the error and regular control flow, which can hurt readablity, 119 but very little if the handling is simple, for instance providing a default 120 value. Similarly, if the error (or alternate outcome) is common enough 121 encoding it in the function signature may be good commuication. 99 They tend to be faster and require similar or less amounts of code to handle. 100 However they can slow down the normal path with some extra conditionals and 101 can mix the normal and exceptional control flow path. If handling the error 102 is simple, and happens relatively frequently, this might be prefered but in 103 other cases it just hurts speed and readability. 122 104 123 105 In short, these errors seem to be more effective when errors are likely and … … 125 107 be handled locally, might be better off using these instead of exceptions. 126 108 127 Also the implicate handlers and return unions could use exceptions as well. 128 For instance, a useful default might handler might be to throw an exception, 129 seaching up the stack for a solution if one is not locally provided. 130 131 Or here is a possible helper for unpacking a Result value: 109 Also the return unions could use exceptions as well. Getting the improper 110 side of a return union might throw an exception. Or we can provide helpers 111 for results withe exceptions as in: 132 112 forall(otype T, otype E | exception(E)) 133 113 T get_or_throw (Result(T, E) * this) { 134 if ( is_success(this)) {135 return get_ success(this);114 if (has_value(this)) { 115 return get_value(this); 136 116 } else { 137 throw get_ failure(this);117 throw get_error(this); 138 118 } 139 119 } 140 So they can feed off of each other. -
src/CodeGen/CodeGenerator.cc
re4d829b r579263a 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed May 10 14:45:00 201713 // Update Count : 48 412 // Last Modified On : Thu Jun 8 16:00:00 2017 13 // Update Count : 485 14 14 // 15 15 … … 112 112 113 113 CodeGenerator::CodeGenerator( std::ostream & os, bool pretty, bool genC, bool lineMarks ) : indent( *this), cur_indent( 0 ), insideFunction( false ), output( os ), printLabels( *this ), pretty( pretty ), genC( genC ), lineMarks( lineMarks ) {} 114 115 CodeGenerator::CodeGenerator( std::ostream & os, std::string init, int indentation, bool infunp )116 : indent( *this), cur_indent( indentation ), insideFunction( infunp ), output( os ), printLabels( *this ) {117 //output << std::string( init );118 }119 120 CodeGenerator::CodeGenerator( std::ostream & os, char * init, int indentation, bool infunp )121 : indent( *this ), cur_indent( indentation ), insideFunction( infunp ), output( os ), printLabels( *this ) {122 //output << std::string( init );123 }124 114 125 115 string CodeGenerator::mangleName( DeclarationWithType * decl ) { … … 932 922 } 933 923 924 void CodeGenerator::visit( ThrowStmt * throwStmt ) { 925 assertf( ! genC, "Throw statements should not reach code generation." ); 926 927 output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ? 928 "throw" : "throwResume"); 929 if (throwStmt->get_expr()) { 930 output << " "; 931 throwStmt->get_expr()->accept( *this ); 932 } 933 if (throwStmt->get_target()) { 934 output << " _At "; 935 throwStmt->get_target()->accept( *this ); 936 } 937 output << ";"; 938 } 939 934 940 void CodeGenerator::visit( WhileStmt * whileStmt ) { 935 941 if ( whileStmt->get_isDoWhile() ) { -
src/CodeGen/CodeGenerator.h
re4d829b r579263a 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed May 10 10:57:00 201713 // Update Count : 5 112 // Last Modified On : Thu Jun 8 15:48:00 2017 13 // Update Count : 52 14 14 // 15 15 … … 92 92 virtual void visit( BranchStmt * ); 93 93 virtual void visit( ReturnStmt * ); 94 virtual void visit( ThrowStmt * ); 94 95 virtual void visit( WhileStmt * ); 95 96 virtual void visit( ForStmt * ); -
src/CodeGen/FixNames.cc
re4d829b r579263a 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Mar 16 07:50:30201713 // Update Count : 1 612 // Last Modified On : Wed Jun 21 14:22:59 2017 13 // Update Count : 19 14 14 // 15 15 … … 114 114 throw SemanticError("Main expected to have 0, 2 or 3 arguments\n", functionDecl); 115 115 } 116 functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new ConstantExpr( Constant ( new BasicType( Type::Qualifiers(), BasicType::SignedInt ), "0") ) ) );116 functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new ConstantExpr( Constant::from_int( 0 ) ) ) ); 117 117 CodeGen::FixMain::registerMain( functionDecl ); 118 118 } -
src/Common/PassVisitor.h
re4d829b r579263a 12 12 #include "SynTree/Expression.h" 13 13 #include "SynTree/Constant.h" 14 #include "SynTree/TypeSubstitution.h" 14 15 15 16 #include "PassVisitor.proto.h" … … 18 19 // Templated visitor type 19 20 // To use declare a PassVisitor< YOUR VISITOR TYPE > 20 // The visitor type should specify the previsit/postvisit for types that are desired. 21 // The visitor type should specify the previsit/postvisit/premutate/postmutate for types that are desired. 22 // Note: previsit/postvisit/premutate/postmutate must be **public** members 23 // 24 // Several additional features are available through inheritance 25 // | WithTypeSubstitution - provides polymorphic TypeSubstitution * env for the current expression 26 // | WithStmtsToAdd - provides the ability to insert statements before or after the current statement by adding new statements into 27 // stmtsToAddBefore or stmtsToAddAfter respectively. 28 // | WithShortCircuiting - provides the ability to skip visiting child nodes; set visit_children to false in pre{visit,mutate} to skip visiting children 29 // | WithGuards - provides the ability to save/restore data like a LIFO stack; to save, call GuardValue with the variable to save, the variable 30 // will automatically be restored to its previous value after the corresponding postvisit/postmutate teminates. 21 31 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 22 32 template< typename pass_type > 23 33 class PassVisitor final : public Visitor, public Mutator { 24 34 public: 25 PassVisitor() = default;26 35 27 36 template< typename... Args > 28 37 PassVisitor(Args &&... args) 29 38 : pass( std::forward<Args>( args )... ) 30 {} 39 { 40 typedef PassVisitor<pass_type> this_t; 41 this_t * const * visitor = visitor_impl(pass, 0); 42 if(visitor) { 43 *const_cast<this_t **>( visitor ) = this; 44 } 45 } 31 46 32 47 virtual ~PassVisitor() = default; … … 54 69 virtual void visit( BranchStmt *branchStmt ) override final; 55 70 virtual void visit( ReturnStmt *returnStmt ) override final; 71 virtual void visit( ThrowStmt *throwStmt ) override final; 56 72 virtual void visit( TryStmt *tryStmt ) override final; 57 73 virtual void visit( CatchStmt *catchStmt ) override final; … … 85 101 virtual void visit( ConstructorExpr * ctorExpr ) override final; 86 102 virtual void visit( CompoundLiteralExpr *compLitExpr ) override final; 87 virtual void visit( UntypedValofExpr *valofExpr ) override final;88 103 virtual void visit( RangeExpr *rangeExpr ) override final; 89 104 virtual void visit( UntypedTupleExpr *tupleExpr ) override final; 90 105 virtual void visit( TupleExpr *tupleExpr ) override final; 91 106 virtual void visit( TupleIndexExpr *tupleExpr ) override final; 92 virtual void visit( MemberTupleExpr *tupleExpr ) override final;93 107 virtual void visit( TupleAssignExpr *assignExpr ) override final; 94 108 virtual void visit( StmtExpr * stmtExpr ) override final; … … 140 154 virtual Statement* mutate( BranchStmt *branchStmt ) override final; 141 155 virtual Statement* mutate( ReturnStmt *returnStmt ) override final; 156 virtual Statement* mutate( ThrowStmt *throwStmt ) override final; 142 157 virtual Statement* mutate( TryStmt *returnStmt ) override final; 143 158 virtual Statement* mutate( CatchStmt *catchStmt ) override final; … … 171 186 virtual Expression* mutate( ConstructorExpr *ctorExpr ) override final; 172 187 virtual Expression* mutate( CompoundLiteralExpr *compLitExpr ) override final; 173 virtual Expression* mutate( UntypedValofExpr *valofExpr ) override final;174 188 virtual Expression* mutate( RangeExpr *rangeExpr ) override final; 175 189 virtual Expression* mutate( UntypedTupleExpr *tupleExpr ) override final; 176 190 virtual Expression* mutate( TupleExpr *tupleExpr ) override final; 177 191 virtual Expression* mutate( TupleIndexExpr *tupleExpr ) override final; 178 virtual Expression* mutate( MemberTupleExpr *tupleExpr ) override final;179 192 virtual Expression* mutate( TupleAssignExpr *assignExpr ) override final; 180 193 virtual Expression* mutate( StmtExpr * stmtExpr ) override final; … … 207 220 208 221 private: 222 template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor ); 223 template<typename pass_t> friend void mutateAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor ); 224 209 225 template<typename node_type> void call_previsit ( node_type * node ) { previsit_impl ( pass, node, 0 ); } 210 226 template<typename node_type> void call_postvisit( node_type * node ) { postvisit_impl( pass, node, 0 ); } … … 218 234 void set_env( TypeSubstitution * env ) { set_env_impl( pass, env, 0); } 219 235 220 void visitStatementList( std::list< Statement* > &statements ); 236 template< typename func_t > 237 void handleStatementList( std::list< Statement * > & statements, func_t func ); 238 void visitStatementList ( std::list< Statement* > &statements ); 221 239 void mutateStatementList( std::list< Statement* > &statements ); 222 240 223 Statement * visitStatement( Statement * stmt ); 241 template< typename func_t > 242 Statement * handleStatement( Statement * stmt, func_t func ); 243 Statement * visitStatement ( Statement * stmt ); 224 244 Statement * mutateStatement( Statement * stmt ); 225 245 226 void visitExpression( Expression * expr ); 246 template< typename func_t > 247 Expression * handleExpression( Expression * expr, func_t func ); 248 Expression * visitExpression ( Expression * expr ); 227 249 Expression * mutateExpression( Expression * expr ); 228 250 … … 231 253 std::list< Statement* > * get_beforeStmts() { return stmtsToAddBefore_impl( pass, 0); } 232 254 std::list< Statement* > * get_afterStmts () { return stmtsToAddAfter_impl ( pass, 0); } 233 bool visit_children() { bool* skip = skip_children_impl(pass, 0); return ! (skip && *skip); } 255 std::list< Declaration* > * get_beforeDecls() { return declsToAddBefore_impl( pass, 0); } 256 std::list< Declaration* > * get_afterDecls () { return declsToAddAfter_impl ( pass, 0); } 257 258 void set_visit_children( bool& ref ) { bool_ref * ptr = visit_children_impl(pass, 0); if(ptr) ptr->set( ref ); } 259 260 guard_value_impl init_guard() { 261 guard_value_impl guard; 262 auto at_cleanup = at_cleanup_impl(pass, 0); 263 if( at_cleanup ) { 264 *at_cleanup = [&guard]( cleanup_func_t && func, void* val ) { 265 guard.push( std::move( func ), val ); 266 }; 267 } 268 return guard; 269 } 270 }; 271 272 template<typename pass_type, typename T> 273 void GuardValue( pass_type * pass, T& val ) { 274 pass->at_cleanup( [ val ]( void * newVal ) { 275 * static_cast< T * >( newVal ) = val; 276 }, static_cast< void * >( & val ) ); 277 } 278 279 class WithTypeSubstitution { 280 protected: 281 WithTypeSubstitution() = default; 282 ~WithTypeSubstitution() = default; 283 284 public: 285 TypeSubstitution * env = nullptr; 286 }; 287 288 class WithStmtsToAdd { 289 protected: 290 WithStmtsToAdd() = default; 291 ~WithStmtsToAdd() = default; 292 293 public: 294 std::list< Statement* > stmtsToAddBefore; 295 std::list< Statement* > stmtsToAddAfter; 296 }; 297 298 class WithDeclsToAdd { 299 protected: 300 WithDeclsToAdd() = default; 301 ~WithDeclsToAdd() = default; 302 303 public: 304 std::list< Declaration* > declsToAddBefore; 305 std::list< Declaration* > declsToAddAfter; 306 }; 307 308 class WithShortCircuiting { 309 protected: 310 WithShortCircuiting() = default; 311 ~WithShortCircuiting() = default; 312 313 public: 314 bool_ref visit_children; 315 }; 316 317 class WithGuards { 318 protected: 319 WithGuards() = default; 320 ~WithGuards() = default; 321 322 public: 323 at_cleanup_t at_cleanup; 324 325 template< typename T > 326 void GuardValue( T& val ) { 327 at_cleanup( [ val ]( void * newVal ) { 328 * static_cast< T * >( newVal ) = val; 329 }, static_cast< void * >( & val ) ); 330 } 331 332 template< typename T > 333 void GuardScope( T& val ) { 334 val.beginScope(); 335 at_cleanup( []( void * val ) { 336 static_cast< T * >( val )->endScope(); 337 }, static_cast< void * >( & val ) ); 338 } 339 340 template< typename Func > 341 void GuardAction( Func func ) { 342 at_cleanup( [func](__attribute__((unused)) void *) { func(); }, nullptr ); 343 } 344 }; 345 346 template<typename pass_type> 347 class WithVisitorRef { 348 protected: 349 WithVisitorRef() {} 350 ~WithVisitorRef() {} 351 352 public: 353 PassVisitor<pass_type> * const visitor = nullptr; 234 354 }; 235 355 -
src/Common/PassVisitor.impl.h
re4d829b r579263a 1 1 #pragma once 2 2 3 #define VISIT_START( node ) \ 4 call_previsit( node ); \ 5 if( visit_children() ) { \ 6 7 #define VISIT_END( node ) \ 8 } \ 9 return call_postvisit( node ); \ 10 11 #define MUTATE_START( node ) \ 12 call_premutate( node ); \ 13 if( visit_children() ) { \ 3 #define VISIT_START( node ) \ 4 __attribute__((unused)) \ 5 const auto & guard = init_guard(); \ 6 bool visit_children = true; \ 7 set_visit_children( visit_children ); \ 8 call_previsit( node ); \ 9 if( visit_children ) { \ 10 11 #define VISIT_END( node ) \ 12 } \ 13 call_postvisit( node ); \ 14 15 #define MUTATE_START( node ) \ 16 __attribute__((unused)) \ 17 const auto & guard = init_guard(); \ 18 bool visit_children = true; \ 19 set_visit_children( visit_children ); \ 20 call_premutate( node ); \ 21 if( visit_children ) { \ 14 22 15 23 #define MUTATE_END( type, node ) \ … … 18 26 19 27 20 #define VISIT_BODY( node ) \21 VISIT_START( node ); \22 Visitor::visit( node ); \23 VISIT_END( node ); \28 #define VISIT_BODY( node ) \ 29 VISIT_START( node ); \ 30 Visitor::visit( node ); \ 31 VISIT_END( node ); \ 24 32 25 33 … … 36 44 } 37 45 38 typedef std::list< Statement * > StmtList_t; 39 40 template< typename pass_type > 41 void PassVisitor< pass_type >::visitStatementList( std::list< Statement * > & statements ) { 46 typedef std::list< Statement * > StmtList_t; 47 typedef std::list< Declaration * > DeclList_t; 48 49 template<typename iterator_t> 50 static inline void splice( iterator_t it, DeclList_t * decls ) { 51 std::transform( 52 decls->begin(), 53 decls->end(), 54 it, 55 [](Declaration * decl) -> auto { 56 return new DeclStmt( noLabels, decl ); 57 } 58 ); 59 decls->clear(); 60 } 61 62 template< typename pass_type > 63 static inline void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_type >& visitor ) { 64 65 DeclList_t* beforeDecls = visitor.get_beforeDecls(); 66 DeclList_t* afterDecls = visitor.get_afterDecls(); 67 68 for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) { 69 // splice in new declarations after previous decl 70 if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); } 71 72 if ( i == decls.end() ) break; 73 74 // run mutator on declaration 75 maybeAccept( *i, visitor ); 76 77 // splice in new declarations before current decl 78 if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); } 79 } 80 } 81 82 template< typename pass_type > 83 static inline void mutateAll( std::list< Declaration* > &decls, PassVisitor< pass_type >& mutator ) { 84 85 DeclList_t* beforeDecls = mutator.get_beforeDecls(); 86 DeclList_t* afterDecls = mutator.get_afterDecls(); 87 88 for ( std::list< Declaration* >::iterator i = decls.begin(); ; ++i ) { 89 // splice in new declarations after previous decl 90 if ( !empty( afterDecls ) ) { decls.splice( i, *afterDecls ); } 91 92 if ( i == decls.end() ) break; 93 94 // run mutator on declaration 95 *i = maybeMutate( *i, mutator ); 96 97 // splice in new declarations before current decl 98 if ( !empty( beforeDecls ) ) { decls.splice( i, *beforeDecls ); } 99 } 100 } 101 102 template< typename pass_type > 103 template< typename func_t > 104 void PassVisitor< pass_type >::handleStatementList( std::list< Statement * > & statements, func_t func ) { 42 105 SemanticError errors; 106 107 // don't want statements from outer CompoundStmts to be added to this CompoundStmt 108 ValueGuardPtr< StmtList_t > oldBeforeStmts( get_beforeStmts() ); 109 ValueGuardPtr< StmtList_t > oldAfterStmts ( get_afterStmts () ); 110 ValueGuardPtr< DeclList_t > oldBeforeDecls( get_beforeDecls() ); 111 ValueGuardPtr< DeclList_t > oldAfterDecls ( get_afterDecls () ); 43 112 44 113 StmtList_t* beforeStmts = get_beforeStmts(); 45 114 StmtList_t* afterStmts = get_afterStmts(); 115 DeclList_t* beforeDecls = get_beforeDecls(); 116 DeclList_t* afterDecls = get_afterDecls(); 46 117 47 118 for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) { 119 120 if ( !empty( afterDecls ) ) { splice( std::inserter( statements, i ), afterDecls ); } 48 121 if ( !empty( afterStmts ) ) { statements.splice( i, *afterStmts ); } 122 49 123 try { 50 (*i)->accept( *this ); 124 func( *i ); 125 assert(( empty( beforeStmts ) && empty( afterStmts )) 126 || ( empty( beforeDecls ) && empty( afterDecls )) ); 127 51 128 } catch ( SemanticError &e ) { 52 129 errors.append( e ); 53 130 } 131 132 if ( !empty( beforeDecls ) ) { splice( std::inserter( statements, i ), beforeDecls ); } 54 133 if ( !empty( beforeStmts ) ) { statements.splice( i, *beforeStmts ); } 55 134 } 56 135 136 if ( !empty( afterDecls ) ) { splice( std::back_inserter( statements ), afterDecls); } 57 137 if ( !empty( afterStmts ) ) { statements.splice( statements.end(), *afterStmts ); } 58 138 if ( !errors.isEmpty() ) { throw errors; } … … 60 140 61 141 template< typename pass_type > 142 void PassVisitor< pass_type >::visitStatementList( std::list< Statement * > & statements ) { 143 handleStatementList( statements, [this]( Statement * stmt) { 144 stmt->accept( *this ); 145 }); 146 } 147 148 template< typename pass_type > 62 149 void PassVisitor< pass_type >::mutateStatementList( std::list< Statement * > & statements ) { 63 SemanticError errors; 150 handleStatementList( statements, [this]( Statement *& stmt) { 151 stmt = stmt->acceptMutator( *this ); 152 }); 153 } 154 155 156 template< typename pass_type > 157 template< typename func_t > 158 Statement * PassVisitor< pass_type >::handleStatement( Statement * stmt, func_t func ) { 159 // don't want statements from outer CompoundStmts to be added to this CompoundStmt 160 ValueGuardPtr< TypeSubstitution * > oldEnv ( get_env_ptr () ); 161 ValueGuardPtr< DeclList_t > oldBeforeDecls( get_beforeDecls() ); 162 ValueGuardPtr< DeclList_t > oldAfterDecls ( get_afterDecls () ); 163 ValueGuardPtr< StmtList_t > oldBeforeStmts( get_beforeStmts() ); 164 ValueGuardPtr< StmtList_t > oldAfterStmts ( get_afterStmts () ); 165 166 Statement *newStmt = func( stmt ); 64 167 65 168 StmtList_t* beforeStmts = get_beforeStmts(); 66 169 StmtList_t* afterStmts = get_afterStmts(); 67 68 for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) { 69 if ( !empty( afterStmts ) ) { statements.splice( i, *afterStmts ); } 70 try { 71 *i = (*i)->acceptMutator( *this ); 72 } catch ( SemanticError &e ) { 73 errors.append( e ); 74 } 75 if ( !empty( beforeStmts ) ) { statements.splice( i, *beforeStmts ); } 76 } 77 78 if ( !empty( afterStmts ) ) { statements.splice( statements.end(), *afterStmts ); } 79 if ( !errors.isEmpty() ) { throw errors; } 80 } 81 82 template< typename pass_type > 83 Statement * PassVisitor< pass_type >::visitStatement( Statement * stmt ) { 84 // don't want statements from outer CompoundStmts to be added to this CompoundStmt 85 ValueGuardPtr< TypeSubstitution * > oldEnv ( get_env_ptr() ); 86 ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() ); 87 ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () ); 88 89 maybeAccept( stmt, *this ); 90 91 StmtList_t* beforeStmts = get_beforeStmts(); 92 StmtList_t* afterStmts = get_afterStmts(); 93 94 if( empty(beforeStmts) && empty(afterStmts) ) { return stmt; } 170 DeclList_t* beforeDecls = get_beforeDecls(); 171 DeclList_t* afterDecls = get_afterDecls(); 172 173 if( empty(beforeStmts) && empty(afterStmts) && empty(beforeDecls) && empty(afterDecls) ) { return newStmt; } 174 assert(( empty( beforeStmts ) && empty( afterStmts )) 175 || ( empty( beforeDecls ) && empty( afterDecls )) ); 95 176 96 177 CompoundStmt *compound = new CompoundStmt( noLabels ); 178 if( !empty(beforeDecls) ) { splice( std::back_inserter( compound->get_kids() ), beforeDecls ); } 97 179 if( !empty(beforeStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *beforeStmts ); } 98 compound->get_kids().push_back( stmt ); 180 compound->get_kids().push_back( newStmt ); 181 if( !empty(afterDecls) ) { splice( std::back_inserter( compound->get_kids() ), afterDecls ); } 99 182 if( !empty(afterStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *afterStmts ); } 100 183 return compound; … … 102 185 103 186 template< typename pass_type > 187 Statement * PassVisitor< pass_type >::visitStatement( Statement * stmt ) { 188 return handleStatement( stmt, [this]( Statement * stmt ) { 189 maybeAccept( stmt, *this ); 190 return stmt; 191 }); 192 } 193 194 template< typename pass_type > 104 195 Statement * PassVisitor< pass_type >::mutateStatement( Statement * stmt ) { 105 // don't want statements from outer CompoundStmts to be added to this CompoundStmt 106 ValueGuardPtr< TypeSubstitution * > oldEnv ( get_env_ptr() ); 107 ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() ); 108 ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () ); 109 110 Statement *newStmt = maybeMutate( stmt, *this ); 111 112 StmtList_t* beforeStmts = get_beforeStmts(); 113 StmtList_t* afterStmts = get_afterStmts(); 114 115 if( empty(beforeStmts) && empty(afterStmts) ) { return newStmt; } 116 117 CompoundStmt *compound = new CompoundStmt( noLabels ); 118 if( !empty(beforeStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *beforeStmts ); } 119 compound->get_kids().push_back( newStmt ); 120 if( !empty(afterStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *afterStmts ); } 121 return compound; 122 } 123 124 125 126 template< typename pass_type > 127 void PassVisitor< pass_type >::visitExpression( Expression * expr ) { 128 if( !expr ) return; 196 return handleStatement( stmt, [this]( Statement * stmt ) { 197 return maybeMutate( stmt, *this ); 198 }); 199 } 200 201 template< typename pass_type > 202 template< typename func_t > 203 Expression * PassVisitor< pass_type >::handleExpression( Expression * expr, func_t func ) { 204 if( !expr ) return nullptr; 129 205 130 206 auto env_ptr = get_env_ptr(); … … 132 208 *env_ptr = expr->get_env(); 133 209 } 134 // xxx - should env be cloned (or moved) onto the result of the mutate? 135 expr->accept( *this ); 210 211 // should env be cloned (or moved) onto the result of the mutate? 212 return func( expr ); 213 } 214 215 template< typename pass_type > 216 Expression * PassVisitor< pass_type >::visitExpression( Expression * expr ) { 217 return handleExpression(expr, [this]( Expression * expr ) { 218 expr->accept( *this ); 219 return expr; 220 }); 136 221 } 137 222 138 223 template< typename pass_type > 139 224 Expression * PassVisitor< pass_type >::mutateExpression( Expression * expr ) { 140 if( !expr ) return nullptr; 141 142 auto env_ptr = get_env_ptr(); 143 if ( env_ptr && expr->get_env() ) { 144 *env_ptr = expr->get_env(); 145 } 146 // xxx - should env be cloned (or moved) onto the result of the mutate? 147 return expr->acceptMutator( *this ); 148 } 149 225 return handleExpression(expr, [this]( Expression * expr ) { 226 return expr->acceptMutator( *this ); 227 }); 228 } 150 229 151 230 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------ … … 153 232 template< typename pass_type > 154 233 void PassVisitor< pass_type >::visit( ObjectDecl * node ) { 155 VISIT_BODY( node ); 234 VISIT_BODY( node ); 156 235 } 157 236 158 237 template< typename pass_type > 159 238 void PassVisitor< pass_type >::visit( FunctionDecl * node ) { 160 VISIT_BODY( node ); 239 VISIT_BODY( node ); 161 240 } 162 241 163 242 template< typename pass_type > 164 243 void PassVisitor< pass_type >::visit( StructDecl * node ) { 165 VISIT_BODY( node ); 244 VISIT_BODY( node ); 166 245 } 167 246 168 247 template< typename pass_type > 169 248 void PassVisitor< pass_type >::visit( UnionDecl * node ) { 170 VISIT_BODY( node ); 249 VISIT_BODY( node ); 171 250 } 172 251 173 252 template< typename pass_type > 174 253 void PassVisitor< pass_type >::visit( EnumDecl * node ) { 175 VISIT_BODY( node ); 254 VISIT_BODY( node ); 176 255 } 177 256 178 257 template< typename pass_type > 179 258 void PassVisitor< pass_type >::visit( TraitDecl * node ) { 180 VISIT_BODY( node ); 259 VISIT_BODY( node ); 181 260 } 182 261 183 262 template< typename pass_type > 184 263 void PassVisitor< pass_type >::visit( TypeDecl * node ) { 185 VISIT_BODY( node ); 264 VISIT_BODY( node ); 186 265 } 187 266 188 267 template< typename pass_type > 189 268 void PassVisitor< pass_type >::visit( TypedefDecl * node ) { 190 VISIT_BODY( node ); 269 VISIT_BODY( node ); 191 270 } 192 271 193 272 template< typename pass_type > 194 273 void PassVisitor< pass_type >::visit( AsmDecl * node ) { 195 VISIT_BODY( node ); 274 VISIT_BODY( node ); 196 275 } 197 276 … … 225 304 void PassVisitor< pass_type >::visit( ExprStmt * node ) { 226 305 VISIT_START( node ); 227 call_beginScope();228 306 229 307 visitExpression( node->get_expr() ); 230 308 231 call_endScope();232 309 VISIT_END( node ); 233 310 } … … 242 319 } 243 320 321 //-------------------------------------------------------------------------- 322 // AsmStmt 244 323 template< typename pass_type > 245 324 void PassVisitor< pass_type >::visit( AsmStmt * node ) { 246 VISIT_BODY( node ); 325 VISIT_BODY( node ); 326 } 327 328 template< typename pass_type > 329 Statement * PassVisitor< pass_type >::mutate( AsmStmt * node ) { 330 MUTATE_BODY( Statement, node ); 247 331 } 248 332 … … 251 335 template< typename pass_type > 252 336 void PassVisitor< pass_type >::visit( IfStmt * node ) { 253 VISIT_START( node ); 337 VISIT_START( node ); 254 338 255 339 visitExpression( node->get_condition() ); … … 262 346 template< typename pass_type > 263 347 Statement * PassVisitor< pass_type >::mutate( IfStmt * node ) { 264 MUTATE_START( node ); 348 MUTATE_START( node ); 265 349 266 350 node->set_condition( mutateExpression( node->get_condition() ) ); … … 275 359 template< typename pass_type > 276 360 void PassVisitor< pass_type >::visit( WhileStmt * node ) { 277 VISIT_START( node ); 361 VISIT_START( node ); 278 362 279 363 visitExpression( node->get_condition() ); … … 285 369 template< typename pass_type > 286 370 Statement * PassVisitor< pass_type >::mutate( WhileStmt * node ) { 287 MUTATE_START( node ); 371 MUTATE_START( node ); 288 372 289 373 node->set_condition( mutateExpression( node->get_condition() ) ); … … 294 378 295 379 //-------------------------------------------------------------------------- 296 // WhileStmt380 // ForStmt 297 381 template< typename pass_type > 298 382 void PassVisitor< pass_type >::visit( ForStmt * node ) { 299 VISIT_START( node ); 383 VISIT_START( node ); 300 384 301 385 acceptAll( node->get_initialization(), *this ); … … 309 393 template< typename pass_type > 310 394 Statement * PassVisitor< pass_type >::mutate( ForStmt * node ) { 311 MUTATE_START( node ); 395 MUTATE_START( node ); 312 396 313 397 mutateAll( node->get_initialization(), *this ); … … 323 407 template< typename pass_type > 324 408 void PassVisitor< pass_type >::visit( SwitchStmt * node ) { 325 VISIT_START( node ); 409 VISIT_START( node ); 326 410 327 411 visitExpression( node->get_condition() ); … … 333 417 template< typename pass_type > 334 418 Statement * PassVisitor< pass_type >::mutate( SwitchStmt * node ) { 335 MUTATE_START( node ); 336 419 MUTATE_START( node ); 420 337 421 node->set_condition( mutateExpression( node->get_condition() ) ); 338 422 mutateStatementList( node->get_statements() ); 339 423 340 424 MUTATE_END( Statement, node ); 341 425 } 342 426 343 427 //-------------------------------------------------------------------------- 344 // SwitchStmt428 // CaseStmt 345 429 template< typename pass_type > 346 430 void PassVisitor< pass_type >::visit( CaseStmt * node ) { 347 VISIT_START( node ); 348 431 VISIT_START( node ); 432 349 433 visitExpression( node->get_condition() ); 350 434 visitStatementList( node->get_statements() ); 351 435 352 436 VISIT_END( node ); 353 437 } … … 355 439 template< typename pass_type > 356 440 Statement * PassVisitor< pass_type >::mutate( CaseStmt * node ) { 357 MUTATE_START( node ); 358 441 MUTATE_START( node ); 442 359 443 node->set_condition( mutateExpression( node->get_condition() ) ); 360 444 mutateStatementList( node->get_statements() ); 361 445 362 446 MUTATE_END( Statement, node ); 363 447 } 364 448 449 //-------------------------------------------------------------------------- 450 // BranchStmt 365 451 template< typename pass_type > 366 452 void PassVisitor< pass_type >::visit( BranchStmt * node ) { 367 VISIT_BODY( node ); 453 VISIT_BODY( node ); 454 } 455 456 template< typename pass_type > 457 Statement * PassVisitor< pass_type >::mutate( BranchStmt * node ) { 458 MUTATE_BODY( Statement, node ); 368 459 } 369 460 … … 386 477 387 478 MUTATE_END( Statement, node ); 479 } 480 481 //-------------------------------------------------------------------------- 482 // ThrowStmt 483 484 template< typename pass_type > 485 void PassVisitor< pass_type >::visit( ThrowStmt * node ) { 486 VISIT_BODY( node ); 487 } 488 489 template< typename pass_type > 490 Statement * PassVisitor< pass_type >::mutate( ThrowStmt * node ) { 491 MUTATE_BODY( Statement, node ); 388 492 } 389 493 … … 396 500 maybeAccept( node->get_block(), *this ); 397 501 acceptAll( node->get_catchers(), *this ); 502 maybeAccept( node->get_finally(), *this ); 398 503 399 504 VISIT_END( node ); … … 406 511 node->set_block( maybeMutate( node->get_block(), *this ) ); 407 512 mutateAll( node->get_catchers(), *this ); 408 513 node->set_finally( maybeMutate( node->get_finally(), *this ) ); 514 409 515 MUTATE_END( Statement, node ); 410 516 } … … 416 522 VISIT_START( node ); 417 523 524 maybeAccept( node->get_decl(), *this ); 525 node->set_cond( visitExpression( node->get_cond() ) ); 418 526 node->set_body( visitStatement( node->get_body() ) ); 419 maybeAccept( node->get_decl(), *this );420 527 421 528 VISIT_END( node ); … … 425 532 Statement * PassVisitor< pass_type >::mutate( CatchStmt * node ) { 426 533 MUTATE_START( node ); 427 428 node->set_body( mutateStatement( node->get_body() ) ); 429 node->set_decl( maybeMutate( node->get_decl(), *this ) ); 430 534 535 node->set_decl( maybeMutate( node->get_decl(), *this ) ); 536 node->set_cond( mutateExpression( node->get_cond() ) ); 537 node->set_body( mutateStatement( node->get_body() ) ); 538 431 539 MUTATE_END( Statement, node ); 432 540 } … … 434 542 template< typename pass_type > 435 543 void PassVisitor< pass_type >::visit( FinallyStmt * node ) { 436 VISIT_BODY( node ); 544 VISIT_BODY( node ); 437 545 } 438 546 439 547 template< typename pass_type > 440 548 void PassVisitor< pass_type >::visit( NullStmt * node ) { 441 VISIT_BODY( node ); 549 VISIT_BODY( node ); 442 550 } 443 551 444 552 template< typename pass_type > 445 553 void PassVisitor< pass_type >::visit( DeclStmt * node ) { 446 VISIT_BODY( node ); 554 VISIT_BODY( node ); 447 555 } 448 556 449 557 template< typename pass_type > 450 558 void PassVisitor< pass_type >::visit( ImplicitCtorDtorStmt * node ) { 451 VISIT_BODY( node ); 559 VISIT_BODY( node ); 452 560 } 453 561 454 562 template< typename pass_type > 455 563 void PassVisitor< pass_type >::visit( ApplicationExpr * node ) { 456 VISIT_BODY( node ); 564 VISIT_BODY( node ); 457 565 } 458 566 … … 462 570 void PassVisitor< pass_type >::visit( UntypedExpr * node ) { 463 571 VISIT_START( node ); 572 573 // maybeAccept( node->get_env(), *this ); 574 maybeAccept( node->get_result(), *this ); 464 575 465 576 for ( auto expr : node->get_args() ) { … … 474 585 MUTATE_START( node ); 475 586 587 node->set_env( maybeMutate( node->get_env(), *this ) ); 588 node->set_result( maybeMutate( node->get_result(), *this ) ); 589 476 590 for ( auto& expr : node->get_args() ) { 477 591 expr = mutateExpression( expr ); … … 483 597 template< typename pass_type > 484 598 void PassVisitor< pass_type >::visit( NameExpr * node ) { 485 VISIT_BODY( node ); 599 VISIT_BODY( node ); 486 600 } 487 601 488 602 template< typename pass_type > 489 603 void PassVisitor< pass_type >::visit( CastExpr * node ) { 490 VISIT_BODY( node ); 604 VISIT_BODY( node ); 491 605 } 492 606 493 607 template< typename pass_type > 494 608 void PassVisitor< pass_type >::visit( AddressExpr * node ) { 495 VISIT_BODY( node ); 609 VISIT_BODY( node ); 496 610 } 497 611 498 612 template< typename pass_type > 499 613 void PassVisitor< pass_type >::visit( LabelAddressExpr * node ) { 500 VISIT_BODY( node ); 614 VISIT_BODY( node ); 501 615 } 502 616 503 617 template< typename pass_type > 504 618 void PassVisitor< pass_type >::visit( UntypedMemberExpr * node ) { 505 VISIT_BODY( node ); 619 VISIT_BODY( node ); 506 620 } 507 621 508 622 template< typename pass_type > 509 623 void PassVisitor< pass_type >::visit( MemberExpr * node ) { 510 VISIT_BODY( node ); 624 VISIT_BODY( node ); 511 625 } 512 626 513 627 template< typename pass_type > 514 628 void PassVisitor< pass_type >::visit( VariableExpr * node ) { 515 VISIT_BODY( node ); 629 VISIT_BODY( node ); 516 630 } 517 631 518 632 template< typename pass_type > 519 633 void PassVisitor< pass_type >::visit( ConstantExpr * node ) { 520 VISIT_BODY( node ); 634 VISIT_BODY( node ); 521 635 } 522 636 523 637 template< typename pass_type > 524 638 void PassVisitor< pass_type >::visit( SizeofExpr * node ) { 525 VISIT_BODY( node ); 639 VISIT_BODY( node ); 526 640 } 527 641 528 642 template< typename pass_type > 529 643 void PassVisitor< pass_type >::visit( AlignofExpr * node ) { 530 VISIT_BODY( node ); 644 VISIT_BODY( node ); 531 645 } 532 646 533 647 template< typename pass_type > 534 648 void PassVisitor< pass_type >::visit( UntypedOffsetofExpr * node ) { 535 VISIT_BODY( node ); 649 VISIT_BODY( node ); 536 650 } 537 651 538 652 template< typename pass_type > 539 653 void PassVisitor< pass_type >::visit( OffsetofExpr * node ) { 540 VISIT_BODY( node ); 654 VISIT_BODY( node ); 541 655 } 542 656 543 657 template< typename pass_type > 544 658 void PassVisitor< pass_type >::visit( OffsetPackExpr * node ) { 545 VISIT_BODY( node ); 659 VISIT_BODY( node ); 546 660 } 547 661 548 662 template< typename pass_type > 549 663 void PassVisitor< pass_type >::visit( AttrExpr * node ) { 550 VISIT_BODY( node ); 664 VISIT_BODY( node ); 551 665 } 552 666 553 667 template< typename pass_type > 554 668 void PassVisitor< pass_type >::visit( LogicalExpr * node ) { 555 VISIT_BODY( node ); 669 VISIT_BODY( node ); 556 670 } 557 671 558 672 template< typename pass_type > 559 673 void PassVisitor< pass_type >::visit( ConditionalExpr * node ) { 560 VISIT_BODY( node ); 674 VISIT_BODY( node ); 561 675 } 562 676 563 677 template< typename pass_type > 564 678 void PassVisitor< pass_type >::visit( CommaExpr * node ) { 565 VISIT_BODY( node ); 679 VISIT_BODY( node ); 566 680 } 567 681 568 682 template< typename pass_type > 569 683 void PassVisitor< pass_type >::visit( TypeExpr * node ) { 570 VISIT_BODY( node ); 684 VISIT_BODY( node ); 571 685 } 572 686 573 687 template< typename pass_type > 574 688 void PassVisitor< pass_type >::visit( AsmExpr * node ) { 575 VISIT_BODY( node ); 689 VISIT_BODY( node ); 576 690 } 577 691 578 692 template< typename pass_type > 579 693 void PassVisitor< pass_type >::visit( ImplicitCopyCtorExpr * node ) { 580 VISIT_BODY( node ); 694 VISIT_BODY( node ); 581 695 } 582 696 583 697 template< typename pass_type > 584 698 void PassVisitor< pass_type >::visit( ConstructorExpr * node ) { 585 VISIT_BODY( node ); 699 VISIT_BODY( node ); 586 700 } 587 701 588 702 template< typename pass_type > 589 703 void PassVisitor< pass_type >::visit( CompoundLiteralExpr * node ) { 590 VISIT_BODY( node ); 591 } 592 593 template< typename pass_type > 594 void PassVisitor< pass_type >::visit( UntypedValofExpr * node ) { 595 VISIT_BODY( node ); 704 VISIT_BODY( node ); 596 705 } 597 706 598 707 template< typename pass_type > 599 708 void PassVisitor< pass_type >::visit( RangeExpr * node ) { 600 VISIT_BODY( node ); 709 VISIT_BODY( node ); 601 710 } 602 711 603 712 template< typename pass_type > 604 713 void PassVisitor< pass_type >::visit( UntypedTupleExpr * node ) { 605 VISIT_BODY( node ); 714 VISIT_BODY( node ); 606 715 } 607 716 608 717 template< typename pass_type > 609 718 void PassVisitor< pass_type >::visit( TupleExpr * node ) { 610 VISIT_BODY( node ); 719 VISIT_BODY( node ); 611 720 } 612 721 613 722 template< typename pass_type > 614 723 void PassVisitor< pass_type >::visit( TupleIndexExpr * node ) { 615 VISIT_BODY( node ); 616 } 617 618 template< typename pass_type > 619 void PassVisitor< pass_type >::visit( MemberTupleExpr * node ) { 620 VISIT_BODY( node ); 724 VISIT_BODY( node ); 621 725 } 622 726 623 727 template< typename pass_type > 624 728 void PassVisitor< pass_type >::visit( TupleAssignExpr * node ) { 625 VISIT_BODY( node ); 729 VISIT_BODY( node ); 626 730 } 627 731 … … 645 749 Expression * PassVisitor< pass_type >::mutate( StmtExpr * node ) { 646 750 MUTATE_START( node ); 647 751 648 752 // don't want statements from outer CompoundStmts to be added to this StmtExpr 649 753 ValueGuardPtr< TypeSubstitution * > oldEnv ( get_env_ptr() ); … … 658 762 template< typename pass_type > 659 763 void PassVisitor< pass_type >::visit( UniqueExpr * node ) { 660 VISIT_BODY( node ); 764 VISIT_BODY( node ); 661 765 } 662 766 663 767 template< typename pass_type > 664 768 void PassVisitor< pass_type >::visit( VoidType * node ) { 665 VISIT_BODY( node ); 769 VISIT_BODY( node ); 666 770 } 667 771 668 772 template< typename pass_type > 669 773 void PassVisitor< pass_type >::visit( BasicType * node ) { 670 VISIT_BODY( node ); 774 VISIT_BODY( node ); 671 775 } 672 776 673 777 template< typename pass_type > 674 778 void PassVisitor< pass_type >::visit( PointerType * node ) { 675 VISIT_BODY( node ); 779 VISIT_BODY( node ); 676 780 } 677 781 678 782 template< typename pass_type > 679 783 void PassVisitor< pass_type >::visit( ArrayType * node ) { 680 VISIT_BODY( node ); 784 VISIT_BODY( node ); 681 785 } 682 786 683 787 template< typename pass_type > 684 788 void PassVisitor< pass_type >::visit( FunctionType * node ) { 685 VISIT_BODY( node ); 789 VISIT_BODY( node ); 686 790 } 687 791 688 792 template< typename pass_type > 689 793 void PassVisitor< pass_type >::visit( StructInstType * node ) { 690 VISIT_BODY( node ); 794 VISIT_BODY( node ); 691 795 } 692 796 693 797 template< typename pass_type > 694 798 void PassVisitor< pass_type >::visit( UnionInstType * node ) { 695 VISIT_BODY( node ); 799 VISIT_BODY( node ); 696 800 } 697 801 698 802 template< typename pass_type > 699 803 void PassVisitor< pass_type >::visit( EnumInstType * node ) { 700 VISIT_BODY( node ); 804 VISIT_BODY( node ); 701 805 } 702 806 703 807 template< typename pass_type > 704 808 void PassVisitor< pass_type >::visit( TraitInstType * node ) { 705 VISIT_BODY( node ); 809 VISIT_BODY( node ); 706 810 } 707 811 708 812 template< typename pass_type > 709 813 void PassVisitor< pass_type >::visit( TypeInstType * node ) { 710 VISIT_BODY( node ); 814 VISIT_BODY( node ); 711 815 } 712 816 713 817 template< typename pass_type > 714 818 void PassVisitor< pass_type >::visit( TupleType * node ) { 715 VISIT_BODY( node ); 819 VISIT_BODY( node ); 716 820 } 717 821 718 822 template< typename pass_type > 719 823 void PassVisitor< pass_type >::visit( TypeofType * node ) { 720 VISIT_BODY( node ); 824 VISIT_BODY( node ); 721 825 } 722 826 723 827 template< typename pass_type > 724 828 void PassVisitor< pass_type >::visit( AttrType * node ) { 725 VISIT_BODY( node ); 829 VISIT_BODY( node ); 726 830 } 727 831 728 832 template< typename pass_type > 729 833 void PassVisitor< pass_type >::visit( VarArgsType * node ) { 730 VISIT_BODY( node ); 834 VISIT_BODY( node ); 731 835 } 732 836 733 837 template< typename pass_type > 734 838 void PassVisitor< pass_type >::visit( ZeroType * node ) { 735 VISIT_BODY( node ); 839 VISIT_BODY( node ); 736 840 } 737 841 738 842 template< typename pass_type > 739 843 void PassVisitor< pass_type >::visit( OneType * node ) { 740 VISIT_BODY( node ); 844 VISIT_BODY( node ); 741 845 } 742 846 … … 763 867 template< typename pass_type > 764 868 void PassVisitor< pass_type >::visit( ListInit * node ) { 765 VISIT_BODY( node ); 869 VISIT_BODY( node ); 766 870 } 767 871 768 872 template< typename pass_type > 769 873 void PassVisitor< pass_type >::visit( ConstructorInit * node ) { 770 VISIT_BODY( node ); 874 VISIT_BODY( node ); 771 875 } 772 876 773 877 template< typename pass_type > 774 878 void PassVisitor< pass_type >::visit( Subrange * node ) { 775 VISIT_BODY( node ); 879 VISIT_BODY( node ); 776 880 } 777 881 778 882 template< typename pass_type > 779 883 void PassVisitor< pass_type >::visit( Constant * node ) { 780 VISIT_BODY( node ); 884 VISIT_BODY( node ); 781 885 } 782 886 … … 829 933 830 934 template< typename pass_type > 831 Statement * PassVisitor< pass_type >::mutate( AsmStmt * node ) {832 MUTATE_BODY( Statement, node );833 }834 835 template< typename pass_type >836 Statement * PassVisitor< pass_type >::mutate( BranchStmt * node ) {837 MUTATE_BODY( Statement, node );838 }839 840 template< typename pass_type >841 935 Statement * PassVisitor< pass_type >::mutate( FinallyStmt * node ) { 842 936 MUTATE_BODY( Statement, node ); … … 974 1068 975 1069 template< typename pass_type > 976 Expression * PassVisitor< pass_type >::mutate( UntypedValofExpr * node ) {977 MUTATE_BODY( Expression, node );978 }979 980 template< typename pass_type >981 1070 Expression * PassVisitor< pass_type >::mutate( RangeExpr * node ) { 982 1071 MUTATE_BODY( Expression, node ); … … 995 1084 template< typename pass_type > 996 1085 Expression * PassVisitor< pass_type >::mutate( TupleIndexExpr * node ) { 997 MUTATE_BODY( Expression, node );998 }999 1000 template< typename pass_type >1001 Expression * PassVisitor< pass_type >::mutate( MemberTupleExpr * node ) {1002 1086 MUTATE_BODY( Expression, node ); 1003 1087 } -
src/Common/PassVisitor.proto.h
re4d829b r579263a 1 1 #pragma once 2 3 template<typename pass_type> 4 class PassVisitor; 5 6 typedef std::function<void( void * )> cleanup_func_t; 7 8 class guard_value_impl { 9 public: 10 guard_value_impl() = default; 11 12 ~guard_value_impl() { 13 while( !cleanups.empty() ) { 14 auto& cleanup = cleanups.top(); 15 cleanup.func( cleanup.val ); 16 cleanups.pop(); 17 } 18 } 19 20 void push( cleanup_func_t && func, void* val ) { 21 cleanups.emplace( std::move(func), val ); 22 } 23 24 private: 25 struct cleanup_t { 26 cleanup_func_t func; 27 void * val; 28 29 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {} 30 }; 31 32 std::stack< cleanup_t > cleanups; 33 }; 34 35 typedef std::function< void( cleanup_func_t, void * ) > at_cleanup_t; 36 37 class bool_ref { 38 public: 39 bool_ref() = default; 40 ~bool_ref() = default; 41 42 operator bool() { return *m_ref; } 43 bool operator=( bool val ) { return *m_ref = val; } 44 45 private: 46 47 template<typename pass> 48 friend class PassVisitor; 49 50 void set( bool & val ) { m_ref = &val; }; 51 52 bool * m_ref; 53 }; 2 54 3 55 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 56 // Deep magic (a.k.a template meta programming) to make the templated visitor work 5 57 // Basically the goal is to make 2 previsit_impl 6 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 58 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 7 59 // 'pass.previsit( node )' that compiles will be used for that node for that type 8 60 // This requires that this option only compile for passes that actually define an appropriate visit. … … 18 70 // Visit 19 71 template<typename pass_type, typename node_type> 20 static inline auto previsit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.previsit( node ), void() ) {72 static inline auto previsit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.previsit( node ), void() ) { 21 73 pass.previsit( node ); 22 74 } … … 27 79 28 80 template<typename pass_type, typename node_type> 29 static inline auto postvisit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.postvisit( node ), void() ) {81 static inline auto postvisit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.postvisit( node ), void() ) { 30 82 pass.postvisit( node ); 31 83 } … … 36 88 // Mutate 37 89 template<typename pass_type, typename node_type> 38 static inline auto premutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.premutate( node ), void() ) {90 static inline auto premutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.premutate( node ), void() ) { 39 91 return pass.premutate( node ); 40 92 } … … 45 97 46 98 template<typename return_type, typename pass_type, typename node_type> 47 static inline auto postmutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.postmutate( node ) ) {99 static inline auto postmutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.postmutate( node ) ) { 48 100 return pass.postmutate( node ); 49 101 } … … 54 106 // Begin/End scope 55 107 template<typename pass_type> 56 static inline auto begin_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( pass.beginScope(), void() ) {108 static inline auto begin_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( pass.beginScope(), void() ) { 57 109 pass.beginScope(); 58 110 } … … 63 115 64 116 template<typename pass_type> 65 static inline auto end_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( pass.endScope(), void() ) {117 static inline auto end_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( pass.endScope(), void() ) { 66 118 pass.endScope(); 67 119 } … … 73 125 #define FIELD_PTR( type, name ) \ 74 126 template<typename pass_type> \ 75 static inline auto name##_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( &pass.name ) { return &pass.name; }\127 static inline auto name##_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( &pass.name ) { return &pass.name; } \ 76 128 \ 77 129 template<typename pass_type> \ … … 81 133 FIELD_PTR( std::list< Statement* >, stmtsToAddBefore ) 82 134 FIELD_PTR( std::list< Statement* >, stmtsToAddAfter ) 83 FIELD_PTR( bool, skip_children ) 135 FIELD_PTR( std::list< Declaration* >, declsToAddBefore ) 136 FIELD_PTR( std::list< Declaration* >, declsToAddAfter ) 137 FIELD_PTR( bool_ref, visit_children ) 138 FIELD_PTR( at_cleanup_t, at_cleanup ) 139 FIELD_PTR( PassVisitor<pass_type> * const, visitor ) -
src/GenPoly/Box.cc
re4d829b r579263a 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat May 13 09:26:38201713 // Update Count : 34 112 // Last Modified On : Wed Jun 21 15:49:59 2017 13 // Update Count : 346 14 14 // 15 15 … … 108 108 Type *replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone = true ); 109 109 /// wraps a function application returning a polymorphic type with a new temporary for the out-parameter return value 110 Expression *addDynRetParam( ApplicationExpr *appExpr, FunctionType *function,Type *polyType, std::list< Expression *>::iterator &arg );110 Expression *addDynRetParam( ApplicationExpr *appExpr, Type *polyType, std::list< Expression *>::iterator &arg ); 111 111 Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ); 112 112 void boxParam( Type *formal, Expression *&arg, const TyVarMap &exprTyVars ); … … 341 341 Statement *makeAlignTo( Expression *lhs, Expression *rhs ) { 342 342 // check that the lhs is zeroed out to the level of rhs 343 Expression *ifCond = makeOp( "?&?", lhs, makeOp( "?-?", rhs, new ConstantExpr( Constant ( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), "1") ) ) );343 Expression *ifCond = makeOp( "?&?", lhs, makeOp( "?-?", rhs, new ConstantExpr( Constant::from_ulong( 1 ) ) ) ); 344 344 // if not aligned, increment to alignment 345 345 Expression *ifExpr = makeOp( "?+=?", lhs->clone(), makeOp( "?-?", rhs->clone(), ifCond->clone() ) ); … … 384 384 385 385 // initialize size and alignment to 0 and 1 (will have at least one member to re-edit size) 386 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant ( sizeAlignType->clone(), "0") ) ) );387 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant ( sizeAlignType->clone(), "1") ) ) );386 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 0 ) ) ) ); 387 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) ); 388 388 unsigned long n_members = 0; 389 389 bool firstMember = true; … … 441 441 442 442 // calculate union layout in function body 443 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant ( sizeAlignType->clone(), "1") ) ) );444 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant ( sizeAlignType->clone(), "1") ) ) );443 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) ); 444 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) ); 445 445 for ( std::list< Declaration* >::const_iterator member = unionDecl->get_members().begin(); member != unionDecl->get_members().end(); ++member ) { 446 446 DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( *member ); … … 504 504 DeclarationWithType *Pass1::mutate( FunctionDecl *functionDecl ) { 505 505 if ( functionDecl->get_statements() ) { // empty routine body ? 506 // std::cerr << "mutating function: " << functionDecl->get_mangleName() << std::endl; 506 507 doBeginScope(); 507 508 scopeTyVars.beginScope(); … … 548 549 retval = oldRetval; 549 550 doEndScope(); 551 // std::cerr << "end function: " << functionDecl->get_mangleName() << std::endl; 550 552 } // if 551 553 return functionDecl; … … 726 728 } 727 729 728 Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, FunctionType *function,Type *dynType, std::list< Expression *>::iterator &arg ) {730 Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType, std::list< Expression *>::iterator &arg ) { 729 731 assert( env ); 730 732 Type *concrete = replaceWithConcrete( appExpr, dynType ); … … 1116 1118 1117 1119 Expression *Pass1::mutate( ApplicationExpr *appExpr ) { 1118 // std::cerr << "mutate appExpr: " ;1120 // std::cerr << "mutate appExpr: " << InitTweak::getFunctionName( appExpr ) << std::endl; 1119 1121 // for ( TyVarMap::iterator i = scopeTyVars.begin(); i != scopeTyVars.end(); ++i ) { 1120 1122 // std::cerr << i->first << " "; … … 1141 1143 ReferenceToType *dynRetType = isDynRet( function, exprTyVars ); 1142 1144 1145 // std::cerr << function << std::endl; 1146 // std::cerr << "scopeTyVars: "; 1147 // printTyVarMap( std::cerr, scopeTyVars ); 1148 // std::cerr << "exprTyVars: "; 1149 // printTyVarMap( std::cerr, exprTyVars ); 1150 // std::cerr << "env: " << *env << std::endl; 1151 // std::cerr << needsAdapter( function, scopeTyVars ) << ! needsAdapter( function, exprTyVars) << std::endl; 1152 1143 1153 // NOTE: addDynRetParam needs to know the actual (generated) return type so it can make a temp variable, so pass the result type from the appExpr 1144 1154 // passTypeVars needs to know the program-text return type (i.e. the distinction between _conc_T30 and T3(int)) 1145 1155 // concRetType may not be a good name in one or both of these places. A more appropriate name change is welcome. 1146 1156 if ( dynRetType ) { 1157 // std::cerr << "dynRetType: " << dynRetType << std::endl; 1147 1158 Type *concRetType = appExpr->get_result()->isVoid() ? nullptr : appExpr->get_result(); 1148 ret = addDynRetParam( appExpr, function,concRetType, arg ); // xxx - used to use dynRetType instead of concRetType1159 ret = addDynRetParam( appExpr, concRetType, arg ); // xxx - used to use dynRetType instead of concRetType 1149 1160 } else if ( needsAdapter( function, scopeTyVars ) && ! needsAdapter( function, exprTyVars) ) { // xxx - exprTyVars is used above...? 1150 1161 // xxx - the ! needsAdapter check may be incorrect. It seems there is some situation where an adapter is applied where it shouldn't be, and this fixes it for some cases. More investigation is needed. … … 1564 1575 /// Returns an index expression into the offset array for a type 1565 1576 Expression *makeOffsetIndex( Type *objectType, long i ) { 1566 std::stringstream offset_namer; 1567 offset_namer << i; 1568 ConstantExpr *fieldIndex = new ConstantExpr( Constant( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), offset_namer.str() ) ); 1577 ConstantExpr *fieldIndex = new ConstantExpr( Constant::from_ulong( i ) ); 1569 1578 UntypedExpr *fieldOffset = new UntypedExpr( new NameExpr( "?[?]" ) ); 1570 1579 fieldOffset->get_args().push_back( new NameExpr( offsetofName( mangleType( objectType ) ) ) ); … … 1779 1788 // all union members are at offset zero 1780 1789 delete offsetofExpr; 1781 return new ConstantExpr( Constant ( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), "0") );1790 return new ConstantExpr( Constant::from_ulong( 0 ) ); 1782 1791 } else return offsetofExpr; 1783 1792 } -
src/GenPoly/DeclMutator.cc
re4d829b r579263a 9 9 // Author : Aaron B. Moss 10 10 // Created On : Fri Nov 27 14:44:00 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Thu Aug 4 11:16:43 201613 // Update Count : 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Jun 22 13:49:00 2017 13 // Update Count : 4 14 14 // 15 15 … … 178 178 Statement* DeclMutator::mutate(CatchStmt *catchStmt) { 179 179 catchStmt->set_decl( maybeMutate( catchStmt->get_decl(), *this ) ); 180 catchStmt->set_cond( maybeMutate( catchStmt->get_cond(), *this ) ); 180 181 catchStmt->set_body( mutateStatement( catchStmt->get_body() ) ); 181 182 return catchStmt; -
src/GenPoly/InstantiateGeneric.cc
re4d829b r579263a 22 22 #include "InstantiateGeneric.h" 23 23 24 #include "DeclMutator.h"25 24 #include "GenPoly.h" 26 25 #include "ScopedSet.h" 27 26 #include "ScrubTyVars.h" 28 #include "PolyMutator.h" 27 28 #include "Common/PassVisitor.h" 29 #include "Common/ScopedMap.h" 30 #include "Common/UniqueName.h" 31 #include "Common/utility.h" 29 32 30 33 #include "ResolvExpr/typeops.h" … … 34 37 #include "SynTree/Type.h" 35 38 36 #include "Common/ScopedMap.h" 37 #include " Common/UniqueName.h"38 #include "Common/utility.h" 39 40 #include "InitTweak/InitTweak.h" 41 39 42 40 43 namespace GenPoly { … … 153 156 } 154 157 155 // collect the environments of each TypeInstType so that type variables can be replaced156 // xxx - possibly temporary solution. Access to type environments is required in GenericInstantiator, but it needs to be a DeclMutator which does not provide easy access to the type environments.157 class EnvFinder final : public GenPoly::PolyMutator {158 public:159 using GenPoly::PolyMutator::mutate;160 virtual Type * mutate( TypeInstType * inst ) override {161 if ( env ) envMap[inst] = env;162 return inst;163 }164 165 // don't want to associate an environment with TypeInstTypes that occur in function types - this may actually only apply to function types belonging to DeclarationWithTypes (or even just FunctionDecl)?166 virtual Type * mutate( FunctionType * ftype ) override {167 return ftype;168 }169 std::unordered_map< ReferenceToType *, TypeSubstitution * > envMap;170 };171 172 158 /// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately 173 class GenericInstantiator final : public DeclMutator{159 struct GenericInstantiator final : public WithTypeSubstitution, public WithDeclsToAdd, public WithVisitorRef<GenericInstantiator>, public WithGuards { 174 160 /// Map of (generic type, parameter list) pairs to concrete type instantiations 175 161 InstantiationMap< AggregateDecl, AggregateDecl > instantiations; … … 178 164 /// Namer for concrete types 179 165 UniqueName typeNamer; 180 /// Reference to mapping of environments 181 const std::unordered_map< ReferenceToType *, TypeSubstitution * > & envMap; 182 public: 183 GenericInstantiator( const std::unordered_map< ReferenceToType *, TypeSubstitution * > & envMap ) : DeclMutator(), instantiations(), dtypeStatics(), typeNamer("_conc_"), envMap( envMap ) {} 184 185 using DeclMutator::mutate; 186 virtual Type* mutate( StructInstType *inst ) override; 187 virtual Type* mutate( UnionInstType *inst ) override; 188 189 virtual void doBeginScope() override; 190 virtual void doEndScope() override; 166 /// Should not make use of type environment to replace types of function parameter and return values. 167 bool inFunctionType = false; 168 GenericInstantiator() : instantiations(), dtypeStatics(), typeNamer("_conc_") {} 169 170 Type* postmutate( StructInstType *inst ); 171 Type* postmutate( UnionInstType *inst ); 172 173 void premutate( FunctionType * ftype ) { 174 GuardValue( inFunctionType ); 175 inFunctionType = true; 176 } 177 178 void beginScope(); 179 void endScope(); 191 180 private: 192 181 /// Wrap instantiation lookup for structs … … 207 196 208 197 void instantiateGeneric( std::list< Declaration* > &translationUnit ) { 209 EnvFinder finder; 210 mutateAll( translationUnit, finder ); 211 GenericInstantiator instantiator( finder.envMap ); 212 instantiator.mutateDeclarationList( translationUnit ); 198 PassVisitor<GenericInstantiator> instantiator; 199 mutateAll( translationUnit, instantiator ); 213 200 } 214 201 … … 306 293 Type *GenericInstantiator::replaceWithConcrete( Type *type, bool doClone ) { 307 294 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) { 308 if ( envMap.count( typeInst ) ) { 309 TypeSubstitution * env = envMap.at( typeInst ); 295 if ( env && ! inFunctionType ) { 310 296 Type *concrete = env->lookup( typeInst->get_name() ); 311 297 if ( concrete ) { … … 331 317 332 318 333 Type* GenericInstantiator::mutate( StructInstType *inst ) { 334 // mutate subtypes 335 Type *mutated = Mutator::mutate( inst ); 336 inst = dynamic_cast< StructInstType* >( mutated ); 337 if ( ! inst ) return mutated; 338 319 Type* GenericInstantiator::postmutate( StructInstType *inst ) { 339 320 // exit early if no need for further mutation 340 321 if ( inst->get_parameters().empty() ) return inst; … … 368 349 substituteMembers( inst->get_baseStruct()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() ); 369 350 insert( inst, typeSubs, concDecl ); // must insert before recursion 370 concDecl->acceptMutator( * this); // recursively instantiate members371 DeclMutator::addDeclaration( concDecl ); // must occur before declaration is added so that member instantiations appear first351 concDecl->acceptMutator( *visitor ); // recursively instantiate members 352 declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first 372 353 } 373 354 StructInstType *newInst = new StructInstType( inst->get_qualifiers(), concDecl->get_name() ); … … 388 369 } 389 370 390 Type* GenericInstantiator::mutate( UnionInstType *inst ) { 391 // mutate subtypes 392 Type *mutated = Mutator::mutate( inst ); 393 inst = dynamic_cast< UnionInstType* >( mutated ); 394 if ( ! inst ) return mutated; 395 371 Type* GenericInstantiator::postmutate( UnionInstType *inst ) { 396 372 // exit early if no need for further mutation 397 373 if ( inst->get_parameters().empty() ) return inst; … … 423 399 substituteMembers( inst->get_baseUnion()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() ); 424 400 insert( inst, typeSubs, concDecl ); // must insert before recursion 425 concDecl->acceptMutator( * this); // recursively instantiate members426 DeclMutator::addDeclaration( concDecl ); // must occur before declaration is added so that member instantiations appear first401 concDecl->acceptMutator( *visitor ); // recursively instantiate members 402 declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first 427 403 } 428 404 UnionInstType *newInst = new UnionInstType( inst->get_qualifiers(), concDecl->get_name() ); … … 442 418 } 443 419 444 void GenericInstantiator::doBeginScope() { 445 DeclMutator::doBeginScope(); 420 void GenericInstantiator::beginScope() { 446 421 instantiations.beginScope(); 447 422 dtypeStatics.beginScope(); 448 423 } 449 424 450 void GenericInstantiator::doEndScope() { 451 DeclMutator::doEndScope(); 425 void GenericInstantiator::endScope() { 452 426 instantiations.endScope(); 453 427 dtypeStatics.endScope(); -
src/GenPoly/PolyMutator.cc
re4d829b r579263a 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Thu Aug 4 11:26:22 201613 // Update Count : 1 611 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Jun 22 13:47:00 2017 13 // Update Count : 17 14 14 // 15 15 … … 123 123 124 124 Statement * PolyMutator::mutate(TryStmt *tryStmt) { 125 tryStmt->set_block( 125 tryStmt->set_block( maybeMutate( tryStmt->get_block(), *this ) ); 126 126 mutateAll( tryStmt->get_catchers(), *this ); 127 tryStmt->set_finally( maybeMutate( tryStmt->get_finally(), *this ) ); 127 128 return tryStmt; 128 129 } 129 130 130 131 Statement * PolyMutator::mutate(CatchStmt *cathStmt) { 131 cathStmt->set_body( mutateStatement( cathStmt->get_body() ) ); 132 cathStmt->set_decl( maybeMutate( cathStmt->get_decl(), *this ) ); 132 cathStmt->set_body( mutateStatement( cathStmt->get_body() ) ); 133 cathStmt->set_cond( maybeMutate( cathStmt->get_cond(), *this ) ); 134 cathStmt->set_decl( maybeMutate( cathStmt->get_decl(), *this ) ); 133 135 return cathStmt; 134 136 } -
src/GenPoly/Specialize.cc
re4d829b r579263a 93 93 } 94 94 95 bool needsTupleSpecialization( Type *formalType, Type *actualType , TypeSubstitution *env) {95 bool needsTupleSpecialization( Type *formalType, Type *actualType ) { 96 96 // Needs tuple specialization if the structure of the formal type and actual type do not match. 97 97 // This is the case if the formal type has ttype polymorphism, or if the structure of tuple types … … 99 99 if ( FunctionType * fftype = getFunctionType( formalType ) ) { 100 100 if ( fftype->isTtype() ) return true; 101 // conversion of 0 (null) to function type does not require tuple specialization 102 if ( dynamic_cast< ZeroType * >( actualType ) ) return false; 101 103 FunctionType * aftype = getFunctionType( actualType ); 102 104 assertf( aftype, "formal type is a function type, but actual type is not." ); … … 112 114 113 115 bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) { 114 return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType , env);116 return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType ); 115 117 } 116 118 -
src/InitTweak/FixInit.cc
re4d829b r579263a 10 10 // Created On : Wed Jan 13 16:29:30 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 17 09:13:47201713 // Update Count : 7 112 // Last Modified On : Wed Jun 21 17:35:05 2017 13 // Update Count : 74 14 14 // 15 15 … … 56 56 typedef std::unordered_map< int, int > UnqCount; 57 57 58 class InsertImplicitCalls {58 class InsertImplicitCalls : public WithTypeSubstitution { 59 59 public: 60 60 /// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which … … 69 69 // collects environments for relevant nodes 70 70 EnvMap & envMap; 71 TypeSubstitution * env; //Magically populated by the PassVisitor72 71 }; 73 72 … … 192 191 }; 193 192 194 class FixInit {193 class FixInit : public WithStmtsToAdd { 195 194 public: 196 195 /// expand each object declaration to use its constructor after it is declared. … … 200 199 201 200 std::list< Declaration * > staticDtorDecls; 202 std::list< Statement * > stmtsToAddAfter; // found by PassVisitor203 201 }; 204 202 … … 726 724 // static bool __objName_uninitialized = true 727 725 BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool ); 728 SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant ( boolType->clone(), "1") ) );726 SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant::from_int( 1 ) ) ); 729 727 ObjectDecl * isUninitializedVar = new ObjectDecl( objDecl->get_mangleName() + "_uninitialized", Type::StorageClasses( Type::Static ), LinkageSpec::Cforall, 0, boolType, boolInitExpr ); 730 728 isUninitializedVar->fixUniqueId(); … … 733 731 UntypedExpr * setTrue = new UntypedExpr( new NameExpr( "?=?" ) ); 734 732 setTrue->get_args().push_back( new VariableExpr( isUninitializedVar ) ); 735 setTrue->get_args().push_back( new ConstantExpr( Constant ( boolType->clone(), "0") ) );733 setTrue->get_args().push_back( new ConstantExpr( Constant::from_int( 0 ) ) ); 736 734 737 735 // generate body of if … … 902 900 } 903 901 904 void InsertDtors::visit( ReturnStmt * returnStmt ) {902 void InsertDtors::visit( __attribute((unused)) ReturnStmt * returnStmt ) { 905 903 // return exits all scopes, so dump destructors for all scopes 906 904 for ( OrderedDecls & od : reverseDeclOrder ) { -
src/InitTweak/GenInit.cc
re4d829b r579263a 39 39 40 40 namespace InitTweak { 41 class ReturnFixer final : public GenPoly::PolyMutator { 42 public: 41 namespace { 42 const std::list<Label> noLabels; 43 const std::list<Expression *> noDesignators; 44 } 45 46 struct ReturnFixer : public WithStmtsToAdd, public WithGuards { 43 47 /// consistently allocates a temporary variable for the return value 44 48 /// of a function so that anything which the resolver decides can be constructed … … 46 50 static void makeReturnTemp( std::list< Declaration * > &translationUnit ); 47 51 48 typedef GenPoly::PolyMutator Parent; 49 using Parent::mutate; 50 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ) override; 51 virtual Statement * mutate( ReturnStmt * returnStmt ) override; 52 void premutate( FunctionDecl *functionDecl ); 53 void premutate( ReturnStmt * returnStmt ); 52 54 53 55 protected: … … 56 58 }; 57 59 58 class CtorDtor final : public GenPoly::PolyMutator { 59 public: 60 typedef GenPoly::PolyMutator Parent; 61 using Parent::mutate; 60 struct CtorDtor : public WithGuards, public WithShortCircuiting { 62 61 /// create constructor and destructor statements for object declarations. 63 62 /// the actual call statements will be added in after the resolver has run … … 66 65 static void generateCtorDtor( std::list< Declaration * > &translationUnit ); 67 66 68 virtual DeclarationWithType * mutate( ObjectDecl * ) override; 69 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ) override; 67 void previsit( ObjectDecl * ); 68 void previsit( FunctionDecl *functionDecl ); 69 70 70 // should not traverse into any of these declarations to find objects 71 71 // that need to be constructed or destructed 72 v irtual Declaration* mutate( StructDecl *aggregateDecl ) override;73 v irtual Declaration* mutate( UnionDecl *aggregateDecl ) override { return aggregateDecl; }74 v irtual Declaration* mutate( EnumDecl *aggregateDecl ) override { return aggregateDecl; }75 v irtual Declaration* mutate( TraitDecl *aggregateDecl ) override { return aggregateDecl; }76 v irtual TypeDecl* mutate( TypeDecl *typeDecl ) override { return typeDecl; }77 v irtual Declaration* mutate( TypedefDecl *typeDecl ) override { return typeDecl; }78 79 v irtual Type * mutate( FunctionType *funcType ) override { return funcType; }80 81 v irtual CompoundStmt * mutate( CompoundStmt * compoundStmt ) override;72 void previsit( StructDecl *aggregateDecl ); 73 void previsit( UnionDecl *aggregateDecl ) { visit_children = false; } 74 void previsit( EnumDecl *aggregateDecl ) { visit_children = false; } 75 void previsit( TraitDecl *aggregateDecl ) { visit_children = false; } 76 void previsit( TypeDecl *typeDecl ) { visit_children = false; } 77 void previsit( TypedefDecl *typeDecl ) { visit_children = false; } 78 79 void previsit( FunctionType *funcType ) { visit_children = false; } 80 81 void previsit( CompoundStmt * compoundStmt ); 82 82 83 83 private: … … 131 131 132 132 void ReturnFixer::makeReturnTemp( std::list< Declaration * > & translationUnit ) { 133 ReturnFixerfixer;133 PassVisitor<ReturnFixer> fixer; 134 134 mutateAll( translationUnit, fixer ); 135 135 } 136 136 137 Statement *ReturnFixer::mutate( ReturnStmt *returnStmt ) {137 void ReturnFixer::premutate( ReturnStmt *returnStmt ) { 138 138 std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals(); 139 139 assert( returnVals.size() == 0 || returnVals.size() == 1 ); … … 146 146 construct->get_args().push_back( new AddressExpr( new VariableExpr( returnVals.front() ) ) ); 147 147 construct->get_args().push_back( returnStmt->get_expr() ); 148 stmtsToAdd .push_back(new ExprStmt(noLabels, construct));148 stmtsToAddBefore.push_back(new ExprStmt(noLabels, construct)); 149 149 150 150 // return the retVal object 151 151 returnStmt->set_expr( new VariableExpr( returnVals.front() ) ); 152 152 } // if 153 return returnStmt; 154 } 155 156 DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) { 157 ValueGuard< FunctionType * > oldFtype( ftype ); 158 ValueGuard< std::string > oldFuncName( funcName ); 153 } 154 155 void ReturnFixer::premutate( FunctionDecl *functionDecl ) { 156 GuardValue( ftype ); 157 GuardValue( funcName ); 159 158 160 159 ftype = functionDecl->get_functionType(); 161 160 funcName = functionDecl->get_name(); 162 return Parent::mutate( functionDecl );163 161 } 164 162 … … 210 208 211 209 void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) { 212 CtorDtorctordtor;213 mutateAll( translationUnit, ctordtor );210 PassVisitor<CtorDtor> ctordtor; 211 acceptAll( translationUnit, ctordtor ); 214 212 } 215 213 … … 288 286 } 289 287 290 DeclarationWithType * CtorDtor::mutate( ObjectDecl * objDecl ) {288 void CtorDtor::previsit( ObjectDecl * objDecl ) { 291 289 handleDWT( objDecl ); 292 290 // hands off if @=, extern, builtin, etc. … … 300 298 objDecl->set_init( genCtorInit( objDecl ) ); 301 299 } 302 return Parent::mutate( objDecl ); 303 } 304 305 DeclarationWithType * CtorDtor::mutate( FunctionDecl *functionDecl ) { 306 ValueGuard< bool > oldInFunc = inFunction; 300 } 301 302 void CtorDtor::previsit( FunctionDecl *functionDecl ) { 303 GuardValue( inFunction ); 307 304 inFunction = true; 308 305 309 306 handleDWT( functionDecl ); 310 307 311 managedTypes.beginScope();308 GuardScope( managedTypes ); 312 309 // go through assertions and recursively add seen ctor/dtors 313 310 for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) { … … 316 313 } 317 314 } 318 // parameters should not be constructed and destructed, so don't mutate FunctionType 319 functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) ); 320 321 managedTypes.endScope(); 322 return functionDecl; 323 } 324 325 Declaration* CtorDtor::mutate( StructDecl *aggregateDecl ) { 315 316 PassVisitor<CtorDtor> newCtorDtor; 317 newCtorDtor.pass = *this; 318 maybeAccept( functionDecl->get_statements(), newCtorDtor ); 319 visit_children = false; // do not try and construct parameters or forall parameters - must happen after maybeAccept 320 } 321 322 void CtorDtor::previsit( StructDecl *aggregateDecl ) { 323 visit_children = false; // do not try to construct and destruct aggregate members 324 326 325 // don't construct members, but need to take note if there is a managed member, 327 326 // because that means that this type is also managed … … 335 334 } 336 335 } 337 return aggregateDecl; 338 } 339 340 CompoundStmt * CtorDtor::mutate( CompoundStmt * compoundStmt ) { 341 managedTypes.beginScope(); 342 CompoundStmt * stmt = Parent::mutate( compoundStmt ); 343 managedTypes.endScope(); 344 return stmt; 345 } 346 336 } 337 338 void CtorDtor::previsit( CompoundStmt * compoundStmt ) { 339 GuardScope( managedTypes ); 340 } 347 341 } // namespace InitTweak 348 342 -
src/InitTweak/InitTweak.cc
re4d829b r579263a 471 471 public: 472 472 ConstExprChecker() : isConstExpr( true ) {} 473 474 using Visitor::visit; 473 475 474 476 virtual void visit( __attribute((unused)) ApplicationExpr *applicationExpr ) { isConstExpr = false; } -
src/Parser/ExpressionNode.cc
re4d829b r579263a 10 10 // Created On : Sat May 16 13:17:07 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 17 21:31:01201713 // Update Count : 5 2712 // Last Modified On : Wed Jun 21 16:44:46 2017 13 // Update Count : 541 14 14 // 15 15 … … 62 62 bool dec = true, Unsigned = false; // decimal, unsigned constant 63 63 int size; // 0 => int, 1 => long, 2 => long long 64 unsigned long long v; // converted integral value64 unsigned long long int v; // converted integral value 65 65 size_t last = str.length() - 1; // last character of constant 66 66 … … 118 118 } // if 119 119 120 Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[Unsigned][size] ), str ) );120 Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[Unsigned][size] ), str, v ) ); 121 121 delete &str; // created by lex 122 122 return ret; … … 133 133 // floating-point constant has minimum of 2 characters: 1. or .1 134 134 size_t last = str.length() - 1; 135 double v; 136 137 sscanf( str.c_str(), "%lg", &v ); 135 138 136 139 if ( checkI( str[last] ) ) { // imaginary ? … … 150 153 } // if 151 154 152 Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[complx][size] ), str ) );155 Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[complx][size] ), str, v ) ); 153 156 delete &str; // created by lex 154 157 return ret; … … 156 159 157 160 Expression *build_constantChar( const std::string & str ) { 158 Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::Char ), str ) );161 Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::Char ), str, (unsigned long long int)(unsigned char)str[1] ) ); 159 162 delete &str; // created by lex 160 163 return ret; … … 164 167 // string should probably be a primitive type 165 168 ArrayType *at = new ArrayType( emptyQualifiers, new BasicType( Type::Qualifiers( Type::Const ), BasicType::Char ), 166 new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::UnsignedInt ), 167 toString( str.size()+1-2 ) ) ), // +1 for '\0' and -2 for '"' 169 new ConstantExpr( Constant::from_ulong( str.size() + 1 - 2 ) ), // +1 for '\0' and -2 for '"' 168 170 false, false ); 169 ConstantExpr * ret = new ConstantExpr( Constant( at, str ) ); 171 // constant 0 is ignored for pure string value 172 ConstantExpr * ret = new ConstantExpr( Constant( at, str, (unsigned long long int)0 ) ); 170 173 delete &str; // created by lex 171 174 return ret; … … 173 176 174 177 Expression *build_constantZeroOne( const std::string & str ) { 175 Expression * ret = new ConstantExpr( Constant( str == "0" ? (Type *)new ZeroType( emptyQualifiers ) : (Type*)new OneType( emptyQualifiers ), str ) ); 178 Expression * ret = new ConstantExpr( Constant( str == "0" ? (Type *)new ZeroType( emptyQualifiers ) : (Type*)new OneType( emptyQualifiers ), str, 179 str == "0" ? (unsigned long long int)0 : (unsigned long long int)1 ) ); 176 180 delete &str; // created by lex 177 181 return ret; … … 184 188 std::stringstream ss( str ); 185 189 ss >> a >> dot >> b; 186 UntypedMemberExpr * ret = new UntypedMemberExpr( 187 new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::SignedInt ), toString( b ) ) ), 188 new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::SignedInt ), toString( a ) ) ) ); 190 UntypedMemberExpr * ret = new UntypedMemberExpr( new ConstantExpr( Constant::from_int( b ) ), new ConstantExpr( Constant::from_int( a ) ) ); 189 191 delete &str; 190 192 return ret; … … 223 225 } // build_field_name_REALDECIMALconstant 224 226 225 NameExpr * build_varref( const string *name , bool labelp) {227 NameExpr * build_varref( const string *name ) { 226 228 NameExpr *expr = new NameExpr( *name, nullptr ); 227 229 delete name; … … 346 348 347 349 Expression *build_valexpr( StatementNode *s ) { 348 return new UntypedValofExpr( maybeMoveBuild< Statement >(s), nullptr);350 return new StmtExpr( dynamic_cast< CompoundStmt * >(maybeMoveBuild< Statement >(s) ) ); 349 351 } 350 352 Expression *build_typevalue( DeclarationNode *decl ) { -
src/Parser/ParseNode.h
re4d829b r579263a 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 13:28:16 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Mar 17 15:42:18201713 // Update Count : 77 711 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Jun 12 13:00:00 2017 13 // Update Count : 779 14 14 // 15 15 … … 166 166 Expression * build_field_name_REALDECIMALconstant( const std::string & str ); 167 167 168 NameExpr * build_varref( const std::string * name , bool labelp = false);168 NameExpr * build_varref( const std::string * name ); 169 169 Expression * build_typevalue( DeclarationNode * decl ); 170 170 … … 393 393 Statement * build_return( ExpressionNode * ctl ); 394 394 Statement * build_throw( ExpressionNode * ctl ); 395 Statement * build_resume( ExpressionNode * ctl ); 396 Statement * build_resume_at( ExpressionNode * ctl , ExpressionNode * target ); 395 397 Statement * build_try( StatementNode * try_stmt, StatementNode * catch_stmt, StatementNode * finally_stmt ); 396 Statement * build_catch( DeclarationNode * decl, StatementNode * stmt, bool catchAny = false);398 Statement * build_catch( CatchStmt::Kind kind, DeclarationNode *decl, ExpressionNode *cond, StatementNode *body ); 397 399 Statement * build_finally( StatementNode * stmt ); 398 400 Statement * build_compound( StatementNode * first ); … … 413 415 result->location = cur->location; 414 416 * out++ = result; 417 } else { 418 assertf(false, "buildList unknown type"); 415 419 } // if 416 420 } catch( SemanticError &e ) { -
src/Parser/StatementNode.cc
re4d829b r579263a 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 14:59:41 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Thu Feb 2 22:16:40 201713 // Update Count : 32 711 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Jun 12 13:03:00 2017 13 // Update Count : 329 14 14 // 15 15 … … 152 152 return new ReturnStmt( noLabels, exps.size() > 0 ? exps.back() : nullptr ); 153 153 } 154 154 155 Statement *build_throw( ExpressionNode *ctl ) { 155 156 std::list< Expression * > exps; 156 157 buildMoveList( ctl, exps ); 157 158 assertf( exps.size() < 2, "This means we are leaking memory"); 158 return new ReturnStmt( noLabels, !exps.empty() ? exps.back() : nullptr, true ); 159 return new ThrowStmt( noLabels, ThrowStmt::Terminate, !exps.empty() ? exps.back() : nullptr ); 160 } 161 162 Statement *build_resume( ExpressionNode *ctl ) { 163 std::list< Expression * > exps; 164 buildMoveList( ctl, exps ); 165 assertf( exps.size() < 2, "This means we are leaking memory"); 166 return new ThrowStmt( noLabels, ThrowStmt::Resume, !exps.empty() ? exps.back() : nullptr ); 167 } 168 169 Statement *build_resume_at( ExpressionNode *ctl, ExpressionNode *target ) { 170 (void)ctl; 171 (void)target; 172 assertf( false, "resume at (non-local throw) is not yet supported," ); 159 173 } 160 174 161 175 Statement *build_try( StatementNode *try_stmt, StatementNode *catch_stmt, StatementNode *finally_stmt ) { 162 std::list< Statement * > branches;163 buildMoveList< Statement, StatementNode >( catch_stmt, branches );176 std::list< CatchStmt * > branches; 177 buildMoveList< CatchStmt, StatementNode >( catch_stmt, branches ); 164 178 CompoundStmt *tryBlock = safe_dynamic_cast< CompoundStmt * >(maybeMoveBuild< Statement >(try_stmt)); 165 179 FinallyStmt *finallyBlock = dynamic_cast< FinallyStmt * >(maybeMoveBuild< Statement >(finally_stmt) ); 166 180 return new TryStmt( noLabels, tryBlock, branches, finallyBlock ); 167 181 } 168 Statement *build_catch( DeclarationNode *decl, StatementNode *stmt, bool catchAny ) {169 std::list< Statement * > branches; 170 buildMoveList< Statement, StatementNode >( stmt, branches );171 assert( branches.size() == 1 ); 172 return new CatchStmt( noLabels, maybeMoveBuild< Declaration >(decl), branches.front(), catchAny);182 Statement *build_catch( CatchStmt::Kind kind, DeclarationNode *decl, ExpressionNode *cond, StatementNode *body ) { 183 std::list< Statement * > branches; 184 buildMoveList< Statement, StatementNode >( body, branches ); 185 assert( branches.size() == 1 ); 186 return new CatchStmt( noLabels, kind, maybeMoveBuild< Declaration >(decl), maybeMoveBuild< Expression >(cond), branches.front() ); 173 187 } 174 188 Statement *build_finally( StatementNode *stmt ) { -
src/Parser/parser.yy
re4d829b r579263a 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu May 25 15:21:59201713 // Update Count : 2 39812 // Last Modified On : Mon Jun 12 12:59:00 2017 13 // Update Count : 2402 14 14 // 15 15 … … 193 193 %type<sn> case_value_list case_label case_label_list 194 194 %type<sn> switch_clause_list_opt switch_clause_list choose_clause_list_opt choose_clause_list 195 %type<sn> handler_listhandler_clause finally_clause195 %type<sn> /* handler_list */ handler_clause finally_clause 196 196 197 197 // declarations … … 547 547 { $$ = new ExpressionNode( build_attrtype( build_varref( $1 ), $3 ) ); } 548 548 // | ANDAND IDENTIFIER // GCC, address of label 549 // { $$ = new ExpressionNode( new OperatorNode( OperKinds::LabelAddress ), new ExpressionNode( build_varref( $2 , true) ); }549 // { $$ = new ExpressionNode( new OperatorNode( OperKinds::LabelAddress ), new ExpressionNode( build_varref( $2 ) ); } 550 550 ; 551 551 … … 931 931 { $$ = new StatementNode( build_throw( $2 ) ); } 932 932 | THROWRESUME assignment_expression_opt ';' // handles reresume 933 { $$ = new StatementNode( build_ throw( $2 ) ); }933 { $$ = new StatementNode( build_resume( $2 ) ); } 934 934 | THROWRESUME assignment_expression_opt AT assignment_expression ';' // handles reresume 935 { $$ = new StatementNode( build_ throw( $2) ); }935 { $$ = new StatementNode( build_resume_at( $2, $4 ) ); } 936 936 ; 937 937 938 938 exception_statement: 939 TRY compound_statement handler_ list939 TRY compound_statement handler_clause 940 940 { $$ = new StatementNode( build_try( $2, $3, 0 ) ); } 941 941 | TRY compound_statement finally_clause 942 942 { $$ = new StatementNode( build_try( $2, 0, $3 ) ); } 943 | TRY compound_statement handler_ listfinally_clause943 | TRY compound_statement handler_clause finally_clause 944 944 { $$ = new StatementNode( build_try( $2, $3, $4 ) ); } 945 945 ; 946 946 947 handler_list:948 handler_clause949 // ISO/IEC 9899:1999 Section 15.3(6 ) If present, a "..." handler shall be the last handler for its try block.950 | CATCH '(' ELLIPSIS ')' compound_statement951 { $$ = new StatementNode( build_catch( 0, $5, true ) ); }952 | handler_clause CATCH '(' ELLIPSIS ')' compound_statement953 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); }954 | CATCHRESUME '(' ELLIPSIS ')' compound_statement955 { $$ = new StatementNode( build_catch( 0, $5, true ) ); }956 | handler_clause CATCHRESUME '(' ELLIPSIS ')' compound_statement957 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); }958 ;947 //handler_list: 948 // handler_clause 949 // // ISO/IEC 9899:1999 Section 15.3(6 ) If present, a "..." handler shall be the last handler for its try block. 950 // | CATCH '(' ELLIPSIS ')' compound_statement 951 // { $$ = new StatementNode( build_catch( 0, $5, true ) ); } 952 // | handler_clause CATCH '(' ELLIPSIS ')' compound_statement 953 // { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); } 954 // | CATCHRESUME '(' ELLIPSIS ')' compound_statement 955 // { $$ = new StatementNode( build_catch( 0, $5, true ) ); } 956 // | handler_clause CATCHRESUME '(' ELLIPSIS ')' compound_statement 957 // { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); } 958 // ; 959 959 960 960 handler_clause: 961 961 CATCH '(' push push exception_declaration pop ')' compound_statement pop 962 { $$ = new StatementNode( build_catch( $5, $8 ) ); }962 { $$ = new StatementNode( build_catch( CatchStmt::Terminate, $5, nullptr, $8 ) ); } 963 963 | handler_clause CATCH '(' push push exception_declaration pop ')' compound_statement pop 964 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $6, $9 ) ) ); }964 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( CatchStmt::Terminate, $6, nullptr, $9 ) ) ); } 965 965 | CATCHRESUME '(' push push exception_declaration pop ')' compound_statement pop 966 { $$ = new StatementNode( build_catch( $5, $8 ) ); }966 { $$ = new StatementNode( build_catch( CatchStmt::Resume, $5, nullptr, $8 ) ); } 967 967 | handler_clause CATCHRESUME '(' push push exception_declaration pop ')' compound_statement pop 968 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $6, $9 ) ) ); }968 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( CatchStmt::Resume, $6, nullptr, $9 ) ) ); } 969 969 ; 970 970 -
src/Parser/parseutility.cc
re4d829b r579263a 10 10 // Created On : Sat May 16 15:30:39 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Aug 14 23:45:03 201613 // Update Count : 312 // Last Modified On : Wed Jun 21 15:33:41 2017 13 // Update Count : 5 14 14 // 15 15 … … 26 26 UntypedExpr *comparison = new UntypedExpr( new NameExpr( "?!=?" ) ); 27 27 comparison->get_args().push_back( orig ); 28 comparison->get_args().push_back( new ConstantExpr( Constant( new ZeroType( emptyQualifiers ), "0" ) ) );28 comparison->get_args().push_back( new ConstantExpr( Constant( new ZeroType( emptyQualifiers ), "0", (unsigned long long int)0 ) ) ); 29 29 return new CastExpr( comparison, new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ); 30 30 } -
src/ResolvExpr/AlternativeFinder.cc
re4d829b r579263a 97 97 /// Prunes a list of alternatives down to those that have the minimum conversion cost for a given return type; skips ambiguous interpretations 98 98 template< typename InputIterator, typename OutputIterator > 99 void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out , const SymTab::Indexer &indexer) {99 void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out ) { 100 100 // select the alternatives that have the minimum conversion cost for a particular set of result types 101 101 std::map< std::string, PruneStruct > selected; … … 183 183 ) 184 184 AltList::iterator oldBegin = alternatives.begin(); 185 pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ) , indexer);185 pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ) ); 186 186 if ( alternatives.begin() == oldBegin ) { 187 187 std::ostringstream stream; -
src/ResolvExpr/CommonType.cc
re4d829b r579263a 157 157 void CommonType::visit( PointerType *pointerType ) { 158 158 if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) { 159 if ( widenFirst && dynamic_cast< VoidType* >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base() , indexer) ) {159 if ( widenFirst && dynamic_cast< VoidType* >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) { 160 160 getCommonWithVoidPointer( otherPointer, pointerType ); 161 } else if ( widenSecond && dynamic_cast< VoidType* >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base() , indexer) ) {161 } else if ( widenSecond && dynamic_cast< VoidType* >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) { 162 162 getCommonWithVoidPointer( pointerType, otherPointer ); 163 163 } else if ( ( pointerType->get_base()->get_qualifiers() >= otherPointer->get_base()->get_qualifiers() || widenFirst ) -
src/ResolvExpr/PtrsCastable.cc
re4d829b r579263a 135 135 } 136 136 137 void PtrsCastable::visit(TraitInstType *inst) { 138 // I definitely don't think we should be doing anything here 139 } 137 void PtrsCastable::visit( __attribute__((unused)) TraitInstType *inst ) {} 140 138 141 139 void PtrsCastable::visit(TypeInstType *inst) { -
src/ResolvExpr/Unify.cc
re4d829b r579263a 114 114 } 115 115 116 bool isFtype( Type *type , const SymTab::Indexer &indexer) {116 bool isFtype( Type *type ) { 117 117 if ( dynamic_cast< FunctionType* >( type ) ) { 118 118 return true; … … 123 123 } 124 124 125 bool tyVarCompatible( const TypeDecl::Data & data, Type *type , const SymTab::Indexer &indexer) {125 bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) { 126 126 switch ( data.kind ) { 127 127 case TypeDecl::Any: … … 131 131 // type must also be complete 132 132 // xxx - should this also check that type is not a tuple type and that it's not a ttype? 133 return ! isFtype( type , indexer) && (! data.isComplete || type->isComplete() );133 return ! isFtype( type ) && (! data.isComplete || type->isComplete() ); 134 134 case TypeDecl::Ftype: 135 return isFtype( type , indexer);135 return isFtype( type ); 136 136 case TypeDecl::Ttype: 137 137 // ttype unifies with any tuple type … … 144 144 OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() ); 145 145 assert( tyvar != openVars.end() ); 146 if ( ! tyVarCompatible( tyvar->second, other , indexer) ) {146 if ( ! tyVarCompatible( tyvar->second, other ) ) { 147 147 return false; 148 148 } // if … … 388 388 } 389 389 390 void Unify::visit( VoidType *voidType) {390 void Unify::visit( __attribute__((unused)) VoidType *voidType) { 391 391 result = dynamic_cast< VoidType* >( type2 ); 392 392 } … … 683 683 684 684 template< typename Iterator1, typename Iterator2 > 685 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode,const SymTab::Indexer &indexer ) {685 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) { 686 686 auto get_type = [](Type * t) { return t; }; 687 687 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) { … … 733 733 flatten( flat2.get(), back_inserter( types2 ) ); 734 734 735 result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, widenMode,indexer );736 } // if 737 } 738 739 void Unify::visit( VarArgsType *varArgsType) {735 result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer ); 736 } // if 737 } 738 739 void Unify::visit( __attribute__((unused)) VarArgsType *varArgsType ) { 740 740 result = dynamic_cast< VarArgsType* >( type2 ); 741 741 } 742 742 743 void Unify::visit( ZeroType *zeroType) {743 void Unify::visit( __attribute__((unused)) ZeroType *zeroType ) { 744 744 result = dynamic_cast< ZeroType* >( type2 ); 745 745 } 746 746 747 void Unify::visit( OneType *oneType) {747 void Unify::visit( __attribute__((unused)) OneType *oneType ) { 748 748 result = dynamic_cast< OneType* >( type2 ); 749 749 } -
src/ResolvExpr/typeops.h
re4d829b r579263a 118 118 119 119 // in Unify.cc 120 bool isFtype( Type *type , const SymTab::Indexer &indexer);120 bool isFtype( Type *type ); 121 121 bool typesCompatible( Type *, Type *, const SymTab::Indexer &indexer, const TypeEnvironment &env ); 122 122 bool typesCompatibleIgnoreQualifiers( Type *, Type *, const SymTab::Indexer &indexer, const TypeEnvironment &env ); -
src/SymTab/Autogen.cc
re4d829b r579263a 262 262 // E ?=?(E volatile*, int), 263 263 // ?=?(E _Atomic volatile*, int); 264 void makeEnumFunctions( Enum Decl *enumDecl, EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) {264 void makeEnumFunctions( EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) { 265 265 266 266 // T ?=?(E *, E); … … 486 486 487 487 /// generates the body of a union assignment/copy constructor/field constructor 488 void makeUnionAssignBody( FunctionDecl * funcDecl , bool isDynamicLayout) {488 void makeUnionAssignBody( FunctionDecl * funcDecl ) { 489 489 FunctionType * ftype = funcDecl->get_functionType(); 490 490 assert( ftype->get_parameters().size() == 2 ); … … 506 506 // Make function polymorphic in same parameters as generic union, if applicable 507 507 const std::list< TypeDecl* > & typeParams = aggregateDecl->get_parameters(); // List of type variables to be placed on the generated functions 508 bool isDynamicLayout = hasDynamicLayout( aggregateDecl ); // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for struct) 509 508 510 509 // default ctor/dtor need only first parameter 511 510 // void ?{}(T *); void ^?{}(T *); … … 533 532 FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting ); 534 533 535 makeUnionAssignBody( assignDecl , isDynamicLayout);534 makeUnionAssignBody( assignDecl ); 536 535 537 536 // body of assignment and copy ctor is the same 538 makeUnionAssignBody( copyCtorDecl , isDynamicLayout);537 makeUnionAssignBody( copyCtorDecl ); 539 538 540 539 // create a constructor which takes the first member type as a parameter. … … 551 550 FunctionDecl * ctor = genFunc( "?{}", memCtorType, functionNesting ); 552 551 553 makeUnionAssignBody( ctor , isDynamicLayout);552 makeUnionAssignBody( ctor ); 554 553 memCtors.push_back( ctor ); 555 554 // only generate a ctor for the first field … … 578 577 EnumInstType *enumInst = new EnumInstType( Type::Qualifiers(), enumDecl->get_name() ); 579 578 // enumInst->set_baseEnum( enumDecl ); 580 makeEnumFunctions( enum Decl, enumInst, functionNesting, declsToAddAfter );579 makeEnumFunctions( enumInst, functionNesting, declsToAddAfter ); 581 580 } 582 581 } -
src/SymTab/Autogen.h
re4d829b r579263a 10 10 // Created On : Sun May 17 21:53:34 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 17 09:10:41201713 // Update Count : 912 // Last Modified On : Wed Jun 21 17:25:26 2017 13 // Update Count : 14 14 14 // 15 15 … … 43 43 template< typename OutputIterator > 44 44 Statement * genScalarCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast = false ) { 45 46 47 45 // want to be able to generate assignment, ctor, and dtor generically, 46 // so fname is either ?=?, ?{}, or ^?{} 47 UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) ); 48 48 49 // do something special for unnamed members 50 dstParam = new AddressExpr( dstParam ); 51 if ( addCast ) { 52 // cast to T* with qualifiers removed, so that qualified objects can be constructed 53 // and destructed with the same functions as non-qualified objects. 54 // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument 55 // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever 56 // remove lvalue as a qualifier, this can change to 57 // type->get_qualifiers() = Type::Qualifiers(); 58 assert( type ); 59 Type * castType = type->clone(); 60 // castType->get_qualifiers() -= Type::Qualifiers(true, true, true, false, true, false); 61 castType->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic ); 62 castType->set_lvalue( true ); // xxx - might not need this 63 dstParam = new CastExpr( dstParam, new PointerType( Type::Qualifiers(), castType ) ); 64 } 65 fExpr->get_args().push_back( dstParam ); 49 // do something special for unnamed members 50 dstParam = new AddressExpr( dstParam ); 51 if ( addCast ) { 52 // cast to T* with qualifiers removed, so that qualified objects can be constructed 53 // and destructed with the same functions as non-qualified objects. 54 // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument 55 // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever 56 // remove lvalue as a qualifier, this can change to 57 // type->get_qualifiers() = Type::Qualifiers(); 58 assert( type ); 59 Type * castType = type->clone(); 60 castType->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic ); 61 castType->set_lvalue( true ); // xxx - might not need this 62 dstParam = new CastExpr( dstParam, new PointerType( Type::Qualifiers(), castType ) ); 63 } 64 fExpr->get_args().push_back( dstParam ); 66 65 67 66 Statement * listInit = srcParam.buildListInit( fExpr ); 68 67 69 70 68 std::list< Expression * > args = *++srcParam; 69 fExpr->get_args().splice( fExpr->get_args().end(), args ); 71 70 72 71 *out++ = new ExprStmt( noLabels, fExpr ); 73 72 74 73 srcParam.clearArrayIndices(); 75 74 76 75 return listInit; 77 76 } 78 77 … … 88 87 Expression * begin, * end, * update, * cmp; 89 88 if ( forward ) { 90 // generate: for ( int i = 0; i < 0; ++i )91 begin = new ConstantExpr( Constant ( new ZeroType( emptyQualifiers ), "0") );89 // generate: for ( int i = 0; i < N; ++i ) 90 begin = new ConstantExpr( Constant::from_int( 0 ) ); 92 91 end = array->get_dimension()->clone(); 93 92 cmp = new NameExpr( "?<?" ); … … 97 96 begin = new UntypedExpr( new NameExpr( "?-?" ) ); 98 97 ((UntypedExpr*)begin)->get_args().push_back( array->get_dimension()->clone() ); 99 ((UntypedExpr*)begin)->get_args().push_back( new ConstantExpr( Constant ( new OneType( emptyQualifiers ), "1") ) );100 end = new ConstantExpr( Constant ( new ZeroType( emptyQualifiers ), "0") );98 ((UntypedExpr*)begin)->get_args().push_back( new ConstantExpr( Constant::from_int( 1 ) ) ); 99 end = new ConstantExpr( Constant::from_int( 0 ) ); 101 100 cmp = new NameExpr( "?>=?" ); 102 101 update = new NameExpr( "--?" ); -
src/SymTab/ImplementationType.cc
re4d829b r579263a 76 76 } 77 77 78 void ImplementationType::visit(FunctionType *functionType) { 79 /// FunctionType *newType = functionType->clone(); 80 /// for ( std::list< DeclarationWithType* >::iterator i = newType->get_parameters().begin(); i != newType->get_parameters().end(); ++i ) { 81 /// i->set_type( implementationType( i->get_type(), indexer ) ); 82 /// } 83 /// for ( std::list< DeclarationWithType* >::iterator i = newType->get_parameters().begin(); i != newType->get_parameters().end(); ++i ) { 84 /// i->set_type( implementationType( i->get_type(), indexer ) ); 85 /// } 86 } 87 78 void ImplementationType::visit( __attribute__((unused)) FunctionType *functionType ) {} 88 79 void ImplementationType::visit( __attribute__((unused)) StructInstType * aggregateUseType ) {} 89 80 void ImplementationType::visit( __attribute__((unused)) UnionInstType * aggregateUseType ) {} -
src/SymTab/Indexer.cc
re4d829b r579263a 495 495 } 496 496 497 void Indexer::visit( UntypedValofExpr *valofExpr ) {498 acceptNewScope( valofExpr->get_result(), *this );499 maybeAccept( valofExpr->get_body(), *this );500 }501 502 497 void Indexer::visit( RangeExpr *rangeExpr ) { 503 498 maybeAccept( rangeExpr->get_low(), *this ); … … 518 513 acceptNewScope( tupleExpr->get_result(), *this ); 519 514 maybeAccept( tupleExpr->get_tuple(), *this ); 520 }521 522 void Indexer::visit( MemberTupleExpr *tupleExpr ) {523 acceptNewScope( tupleExpr->get_result(), *this );524 maybeAccept( tupleExpr->get_member(), *this );525 maybeAccept( tupleExpr->get_aggregate(), *this );526 515 } 527 516 -
src/SymTab/Indexer.h
re4d829b r579263a 69 69 virtual void visit( ConstructorExpr * ctorExpr ); 70 70 virtual void visit( CompoundLiteralExpr *compLitExpr ); 71 virtual void visit( UntypedValofExpr *valofExpr );72 71 virtual void visit( RangeExpr *rangeExpr ); 73 72 virtual void visit( UntypedTupleExpr *tupleExpr ); 74 73 virtual void visit( TupleExpr *tupleExpr ); 75 74 virtual void visit( TupleIndexExpr *tupleExpr ); 76 virtual void visit( MemberTupleExpr *tupleExpr );77 75 virtual void visit( TupleAssignExpr *tupleExpr ); 78 76 virtual void visit( StmtExpr * stmtExpr ); -
src/SymTab/Mangler.cc
re4d829b r579263a 236 236 } 237 237 238 void Mangler::visit( ZeroType *zeroType ) {238 void Mangler::visit( __attribute__((unused)) ZeroType *zeroType ) { 239 239 mangleName << "Z"; 240 240 } 241 241 242 void Mangler::visit( OneType *oneType ) {242 void Mangler::visit( __attribute__((unused)) OneType *oneType ) { 243 243 mangleName << "O"; 244 244 } -
src/SymTab/Validate.cc
re4d829b r579263a 106 106 107 107 /// Fix return types so that every function returns exactly one value 108 class ReturnTypeFixer { 109 public: 108 struct ReturnTypeFixer { 110 109 static void fix( std::list< Declaration * > &translationUnit ); 111 110 … … 115 114 116 115 /// Replaces enum types by int, and function or array types in function parameter and return lists by appropriate pointers. 117 class EnumAndPointerDecayPass final : public Visitor { 118 typedef Visitor Parent; 119 virtual void visit( EnumDecl *aggregateDecl ); 120 virtual void visit( FunctionType *func ); 116 struct EnumAndPointerDecay { 117 void previsit( EnumDecl *aggregateDecl ); 118 void previsit( FunctionType *func ); 121 119 }; 122 120 … … 126 124 public: 127 125 LinkReferenceToTypes( bool doDebug, const Indexer *indexer ); 128 private:129 126 using Parent::visit; 130 127 void visit( EnumInstType *enumInst ) final; … … 136 133 void visit( UnionDecl *unionDecl ) final; 137 134 void visit( TypeInstType *typeInst ) final; 138 135 private: 139 136 const Indexer *indexer; 140 137 … … 147 144 }; 148 145 149 /// Replaces array and function types in forall lists by appropriate pointer type 150 class Pass3final : public Indexer {146 /// Replaces array and function types in forall lists by appropriate pointer type and assigns each Object and Function declaration a unique ID. 147 class ForallPointerDecay final : public Indexer { 151 148 typedef Indexer Parent; 152 149 public: 153 150 using Parent::visit; 154 Pass3( const Indexer *indexer );155 private: 151 ForallPointerDecay( const Indexer *indexer ); 152 156 153 virtual void visit( ObjectDecl *object ) override; 157 154 virtual void visit( FunctionDecl *func ) override; … … 160 157 }; 161 158 162 class ReturnChecker { 163 public: 159 struct ReturnChecker : public WithGuards { 164 160 /// Checks that return statements return nothing if their return type is void 165 161 /// and return something if the return type is non-void. 166 162 static void checkFunctionReturns( std::list< Declaration * > & translationUnit ); 167 private: 163 168 164 void previsit( FunctionDecl * functionDecl ); 169 void postvisit( FunctionDecl * functionDecl );170 165 void previsit( ReturnStmt * returnStmt ); 171 166 172 167 typedef std::list< DeclarationWithType * > ReturnVals; 173 168 ReturnVals returnVals; 174 std::stack< ReturnVals > returnValsStack;175 169 }; 176 170 … … 208 202 }; 209 203 210 class VerifyCtorDtorAssign { 211 public: 204 struct VerifyCtorDtorAssign { 212 205 /// ensure that constructors, destructors, and assignment have at least one 213 206 /// parameter, the first of which must be a pointer, and that ctor/dtors have no … … 219 212 220 213 /// ensure that generic types have the correct number of type arguments 221 class ValidateGenericParameters { 222 public: 214 struct ValidateGenericParameters { 223 215 void previsit( StructInstType * inst ); 224 216 void previsit( UnionInstType * inst ); 225 217 }; 226 218 227 class ArrayLength { 228 public: 219 struct ArrayLength { 229 220 /// for array types without an explicit length, compute the length and store it so that it 230 221 /// is known to the rest of the phases. For example, … … 239 230 }; 240 231 241 class CompoundLiteral final : public GenPoly::DeclMutator{232 struct CompoundLiteral final : public WithDeclsToAdd, public WithVisitorRef<CompoundLiteral> { 242 233 Type::StorageClasses storageClasses; 243 234 244 using GenPoly::DeclMutator::mutate; 245 DeclarationWithType * mutate( ObjectDecl *objectDecl ) final; 246 Expression *mutate( CompoundLiteralExpr *compLitExpr ) final; 235 void premutate( ObjectDecl *objectDecl ); 236 Expression * postmutate( CompoundLiteralExpr *compLitExpr ); 247 237 }; 248 238 249 239 void validate( std::list< Declaration * > &translationUnit, bool doDebug ) { 250 EnumAndPointerDecayPassepc;240 PassVisitor<EnumAndPointerDecay> epc; 251 241 LinkReferenceToTypes lrt( doDebug, 0 ); 252 Pass3 pass3( 0 );253 CompoundLiteralcompoundliteral;242 ForallPointerDecay fpd( 0 ); 243 PassVisitor<CompoundLiteral> compoundliteral; 254 244 PassVisitor<ValidateGenericParameters> genericParams; 255 245 … … 262 252 VerifyCtorDtorAssign::verify( translationUnit ); // must happen before autogen, because autogen examines existing ctor/dtors 263 253 Concurrency::applyKeywords( translationUnit ); 264 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay Pass254 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay 265 255 Concurrency::implementMutexFuncs( translationUnit ); 266 256 Concurrency::implementThreadStarter( translationUnit ); 267 257 ReturnChecker::checkFunctionReturns( translationUnit ); 268 compoundliteral.mutateDeclarationList( translationUnit);269 acceptAll( translationUnit, pass3);258 mutateAll( translationUnit, compoundliteral ); 259 acceptAll( translationUnit, fpd ); 270 260 ArrayLength::computeLength( translationUnit ); 271 261 } 272 262 273 263 void validateType( Type *type, const Indexer *indexer ) { 274 EnumAndPointerDecayPassepc;264 PassVisitor<EnumAndPointerDecay> epc; 275 265 LinkReferenceToTypes lrt( false, indexer ); 276 Pass3 pass3( indexer );266 ForallPointerDecay fpd( indexer ); 277 267 type->accept( epc ); 278 268 type->accept( lrt ); 279 type->accept( pass3);269 type->accept( fpd ); 280 270 } 281 271 … … 356 346 } 357 347 358 void EnumAndPointerDecay Pass::visit( EnumDecl *enumDecl ) {348 void EnumAndPointerDecay::previsit( EnumDecl *enumDecl ) { 359 349 // Set the type of each member of the enumeration to be EnumConstant 360 350 for ( std::list< Declaration * >::iterator i = enumDecl->get_members().begin(); i != enumDecl->get_members().end(); ++i ) { … … 363 353 obj->set_type( new EnumInstType( Type::Qualifiers( Type::Const ), enumDecl->get_name() ) ); 364 354 } // for 365 Parent::visit( enumDecl );366 355 } 367 356 … … 370 359 void fixFunctionList( DWTList & dwts, FunctionType * func ) { 371 360 // the only case in which "void" is valid is where it is the only one in the list; then it should be removed 372 // entirely other fix ups are handled by the FixFunction class361 // entirely. other fix ups are handled by the FixFunction class 373 362 typedef typename DWTList::iterator DWTIterator; 374 363 DWTIterator begin( dwts.begin() ), end( dwts.end() ); … … 389 378 for ( ; i != end; ++i ) { 390 379 FixFunction fixer; 391 *i = (*i 380 *i = (*i)->acceptMutator( fixer ); 392 381 if ( fixer.get_isVoid() ) { 393 382 throw SemanticError( "invalid type void in function type ", func ); … … 398 387 } 399 388 400 void EnumAndPointerDecay Pass::visit( FunctionType *func ) {389 void EnumAndPointerDecay::previsit( FunctionType *func ) { 401 390 // Fix up parameters and return types 402 391 fixFunctionList( func->get_parameters(), func ); 403 392 fixFunctionList( func->get_returnVals(), func ); 404 Visitor::visit( func );405 393 } 406 394 … … 549 537 } 550 538 551 Pass3::Pass3( const Indexer *other_indexer ) : Indexer( false ) {539 ForallPointerDecay::ForallPointerDecay( const Indexer *other_indexer ) : Indexer( false ) { 552 540 if ( other_indexer ) { 553 541 indexer = other_indexer; … … 587 575 } 588 576 589 void Pass3::visit( ObjectDecl *object ) {577 void ForallPointerDecay::visit( ObjectDecl *object ) { 590 578 forallFixer( object->get_type() ); 591 579 if ( PointerType *pointer = dynamic_cast< PointerType * >( object->get_type() ) ) { … … 596 584 } 597 585 598 void Pass3::visit( FunctionDecl *func ) {586 void ForallPointerDecay::visit( FunctionDecl *func ) {