Changes in / [6250a312:0f9bef3]
- Files:
-
- 4 added
- 23 deleted
- 44 edited
Legend:
- Unmodified
- Added
- Removed
-
Jenkins/FullBuild
r6250a312 r0f9bef3 9 9 10 10 try { 11 // Wrap build to add timestamp to command line12 wrap([$class: 'TimestamperBuildWrapper']) {11 //Prevent the build from exceeding 30 minutes 12 timeout(60) { 13 13 14 stage('Build') { 14 //Wrap build to add timestamp to command line 15 wrap([$class: 'TimestamperBuildWrapper']) { 15 16 16 results = [null, null]17 stage 'Build' 17 18 18 parallel ( 19 gcc_6_x64: { trigger_build( 'gcc-6', 'x64', true ) }, 20 gcc_6_x86: { trigger_build( 'gcc-6', 'x86', true ) }, 21 gcc_5_x64: { trigger_build( 'gcc-5', 'x64', false ) }, 22 gcc_5_x86: { trigger_build( 'gcc-5', 'x86', false ) }, 23 gcc_4_x64: { trigger_build( 'gcc-4.9', 'x64', false ) }, 24 gcc_4_x86: { trigger_build( 'gcc-4.9', 'x86', false ) }, 25 clang_x64: { trigger_build( 'clang', 'x64', false ) }, 26 clang_x86: { trigger_build( 'clang', 'x86', false ) }, 27 ) 19 results = [null, null] 20 21 parallel ( 22 gcc_6_x64: { trigger_build( 'gcc-6', 'x64', true ) }, 23 gcc_6_x86: { trigger_build( 'gcc-6', 'x86', true ) }, 24 gcc_5_x64: { trigger_build( 'gcc-5', 'x64', false ) }, 25 gcc_5_x86: { trigger_build( 'gcc-5', 'x86', false ) }, 26 gcc_4_x64: { trigger_build( 'gcc-4.9', 'x64', false ) }, 27 gcc_4_x86: { trigger_build( 'gcc-4.9', 'x86', false ) }, 28 clang_x64: { trigger_build( 'clang', 'x64', false ) }, 29 clang_x86: { trigger_build( 'clang', 'x86', false ) }, 30 ) 31 32 //Push latest changes to do-lang repo 33 push_build() 28 34 } 29 30 //Push latest changes to do-lang repo31 push_build()32 35 } 33 36 } … … 96 99 def push_build() { 97 100 //Don't use the build_stage function which outputs the compiler 98 stage ('Push') {101 stage 'Push' 99 102 100 103 status_prefix = 'Push' … … 119 122 //sh "GIT_SSH_COMMAND=\"ssh -v\" git push DoLang ${gitRefNewValue}:master" 120 123 echo('BUILD NOT PUSH SINCE DO-LANG SERVER WAS DOWN') 121 }122 124 } 123 125 -
Jenkinsfile
r6250a312 r0f9bef3 28 28 wrap([$class: 'TimestamperBuildWrapper']) { 29 29 30 notify_server() 31 32 prepare_build() 33 34 checkout() 35 36 build() 37 38 test() 39 40 benchmark() 41 42 clean() 43 44 build_doc() 45 46 publish() 47 48 notify_server() 30 //Prevent the build from exceeding 60 minutes 31 timeout(60) { 32 33 notify_server() 34 35 prepare_build() 36 37 checkout() 38 39 build() 40 41 test() 42 43 benchmark() 44 45 clean() 46 47 build_doc() 48 49 publish() 50 51 notify_server() 52 } 49 53 } 50 54 } … … 85 89 def collect_git_info() { 86 90 87 checkout scm88 89 91 //create the temporary output directory in case it doesn't already exist 90 92 def out_dir = pwd tmp: true … … 93 95 //parse git logs to find what changed 94 96 gitRefName = env.BRANCH_NAME 95 sh "git reflog > ${out_dir}/GIT_COMMIT" 97 dir("../${gitRefName}@script") { 98 sh "git reflog > ${out_dir}/GIT_COMMIT" 99 } 96 100 git_reflog = readFile("${out_dir}/GIT_COMMIT") 97 101 gitRefOldValue = (git_reflog =~ /moving from (.+) to (.+)/)[0][1] … … 166 170 } 167 171 168 def build_stage(String name , Closure block) {172 def build_stage(String name) { 169 173 stage_name = name 170 stage (name, block)174 stage name 171 175 } 172 176 … … 241 245 //Compilation script is done here but environnement set-up and error handling is done in main loop 242 246 def checkout() { 243 build_stage ('Checkout') {247 build_stage'Checkout' 244 248 //checkout the source code and clean the repo 245 249 checkout scm … … 250 254 //Reset the git repo so no local changes persist 251 255 sh 'git reset --hard' 252 }253 256 } 254 257 255 258 def build() { 256 build_stage ('Build') {259 build_stage'Build' 257 260 258 261 def install_dir = pwd tmp: true … … 266 269 //Compile the project 267 270 sh 'make -j 8 --no-print-directory V=0 install' 268 }269 271 } 270 272 271 273 def test() { 272 build_stage ('Test') {274 build_stage'Test' 273 275 274 276 //Run the tests from the tests directory 275 277 if ( do_alltests ) { 276 sh 'make -C src/tests all-tests debug=yes --no-print-directory'277 sh 'make -C src/tests all-tests debug=no --no-print-directory'278 sh 'make -C src/tests all-tests debug=yes' 279 sh 'make -C src/tests all-tests debug=no' 278 280 } 279 281 else { 280 sh 'make -C src/tests --no-print-directory' 281 } 282 } 282 sh 'make -C src/tests' 283 } 283 284 } 284 285 285 286 def benchmark() { 286 build_stage ('Benchmark') {287 build_stage'Benchmark' 287 288 288 289 if( !do_benchmark ) return … … 293 294 //Append bench results 294 295 sh 'make -C src/benchmark --no-print-directory csv-data >> bench.csv' 295 }296 296 } 297 297 298 298 def clean() { 299 build_stage ('Cleanup') {299 build_stage'Cleanup' 300 300 301 301 //do a maintainer-clean to make sure we need to remake from scratch 302 302 sh 'make maintainer-clean > /dev/null' 303 }304 303 } 305 304 306 305 def build_doc() { 307 build_stage ('Documentation') {306 build_stage'Documentation' 308 307 309 308 if( !do_doc ) return … … 316 315 make_doc() 317 316 } 318 }319 317 } 320 318 321 319 def publish() { 322 build_stage ('Publish') {320 build_stage'Publish' 323 321 324 322 if( !do_publish ) return … … 326 324 //Then publish the results 327 325 sh 'curl --silent --data @bench.csv http://plg2:8082/jenkins/publish > /dev/null || true' 328 }329 326 } 330 327 … … 374 371 """ 375 372 376 def email_to = "pabuhr@uwaterloo.ca, rschlunt@uwaterloo.ca, a3moss@uwaterloo.ca, tdelisle@uwaterloo.ca, brice.dobry@huawei.com , ajbeach@edu.uwaterloo.ca"373 def email_to = "pabuhr@uwaterloo.ca, rschlunt@uwaterloo.ca, a3moss@uwaterloo.ca, tdelisle@uwaterloo.ca, brice.dobry@huawei.com" 377 374 378 375 //send email notification -
doc/rob_thesis/cfa-format.tex
r6250a312 r0f9bef3 1 %\usepackage{xcolor}2 %\usepackage{listings}1 \usepackage{xcolor} 2 \usepackage{listings} 3 3 % \usepackage{booktabs} 4 4 % \usepackage{array} … … 103 103 104 104 \renewcommand{\ttdefault}{pcr} 105 106 \newcommand{\basicstylesmall}{\scriptsize\ttfamily\color{basicCol}}107 105 108 106 \lstdefinestyle{defaultStyle}{ … … 133 131 style=defaultStyle 134 132 } 135 \lstMakeShortInline[basewidth=0.5em,breaklines=true,b reakatwhitespace,basicstyle=\normalsize\ttfamily\color{basicCol}]@ % single-character for \lstinline133 \lstMakeShortInline[basewidth=0.5em,breaklines=true,basicstyle=\normalsize\ttfamily\color{basicCol}]@ % single-character for \lstinline 136 134 137 135 \lstnewenvironment{cfacode}[1][]{ … … 197 195 \newcommand{\one}{\lstinline{one_t}\xspace} 198 196 \newcommand{\ateq}{\lstinline{\@=}\xspace} 199 200 \newenvironment{newtext}{\color{red}}{\ignorespacesafterend}201 197 202 198 % \lstset{ % -
doc/rob_thesis/conclusions.tex
r6250a312 r0f9bef3 6 6 On the surface, the work may appear as a rehash of similar mechanisms in \CC. 7 7 However, every added feature is different than its \CC counterpart, often with extended functionality, better integration with C and its programmers, and always supports separate compilation. 8 All of these new features are being used extensively by the \CFA development-team to build the \CFA runtime system. 9 In particular, the concurrency system is built on top of RAII, library functions @new@ and @delete@ are used to manage dynamically allocated objects, and tuples are used to provide uniform interfaces to C library routines such as @div@ and @remquo@. 8 All of these new features are being used by the \CFA development-team to build the \CFA runtime system. 10 9 11 10 \section{Constructors and Destructors} … … 246 245 That is, structure fields can be accessed and modified by any block of code without restriction, so while it is possible to ensure that an object is initially set to a valid state, it is not possible to ensure that it remains in a consistent state throughout its lifetime. 247 246 A popular technique for ensuring consistency in object-oriented programming languages is to provide access modifiers such as @private@, which provides compile-time checks that only privileged code accesses private data. 248 This approach could be added to \CFA, but it requires an idiomatic way of specifying what code is privileged and what data is protected.247 This approach could be added to \CFA, but it requires an idiomatic way of specifying what code is privileged. 249 248 One possibility is to tie access control into an eventual module system. 250 251 \begin{sloppypar}252 The current implementation of implicit subobject-construction is currently an all-or-nothing check.253 That is, if a subobject is conditionally constructed, \eg within an if-statement, no implicit constructors for that object are added.254 \begin{cfacode}255 struct A { ... };256 void ?{}(A * a) { ... }257 258 struct B {259 A a;260 };261 void ?{}(B * b) {262 if (...) {263 (&b->a){}; // explicitly constructed264 } // does not construct in else case265 }266 \end{cfacode}267 This behaviour is unsafe and breaks the guarantee that constructors fully initialize objects.268 This situation should be properly handled, either by examining all paths and inserting implicit constructor calls only in the paths missing construction, or by emitting an error or warning.269 \end{sloppypar}270 249 271 250 \subsection{Tuples} … … 273 252 This feature ties nicely into named tuples, as seen in D and Swift. 274 253 275 Currently, tuple flattening and structuring conversions are 0-cost conversions in the resolution algorithm.254 Currently, tuple flattening and structuring conversions are 0-cost. 276 255 This makes tuples conceptually very simple to work with, but easily causes unnecessary ambiguity in situations where the type system should be able to differentiate between alternatives. 277 256 Adding an appropriate cost function to tuple conversions will allow tuples to interact with the rest of the programming language more cohesively. -
doc/rob_thesis/ctordtor.tex
r6250a312 r0f9bef3 6 6 % doesn't seem possible to do this without allowing ttype on generic structs? 7 7 8 Since \CFA is a true systems language, it does not require a garbage collector. 9 As well, \CFA is not an object-oriented programming language, \ie, structures cannot have methods. 10 While structures can have function pointer members, this is different from methods, since methods have implicit access to structure members and methods cannot be reassigned. 8 Since \CFA is a true systems language, it does not provide a garbage collector. 9 As well, \CFA is not an object-oriented programming language, \ie, structures cannot have routine members. 11 10 Nevertheless, one important goal is to reduce programming complexity and increase safety. 12 11 To that end, \CFA provides support for implicit pre/post-execution of routines for objects, via constructors and destructors. … … 33 32 The key difference between assignment and initialization being that assignment occurs on a live object (\ie, an object that contains data). 34 33 It is important to note that this means @x@ could have been used uninitialized prior to being assigned, while @y@ could not be used uninitialized. 35 Use of uninitialized variables yields undefined behaviour \cite[p.~558]{C11}, which is a common source of errors in C programs.34 Use of uninitialized variables yields undefined behaviour, which is a common source of errors in C programs. 36 35 37 36 Initialization of a declaration is strictly optional, permitting uninitialized variables to exist. … … 71 70 int x2 = opaque_get(x, 2); 72 71 \end{cfacode} 73 This pattern is cumbersome to use since every access becomes a function call , requiring awkward syntax and a performance cost.72 This pattern is cumbersome to use since every access becomes a function call. 74 73 While useful in some situations, this compromise is too restrictive. 75 74 Furthermore, even with this idiom it is easy to make mistakes, such as forgetting to destroy an object or destroying it multiple times. 76 75 77 76 A constructor provides a way of ensuring that the necessary aspects of object initialization is performed, from setting up invariants to providing compile- and run-time checks for appropriate initialization parameters. 78 This goal is achieved through a \emph{guarantee} that a constructor is called \emph{implicitly} after every object is allocated from a type with associated constructors, as part of an object's \emph{definition}.79 Since a constructor is called on every object of a managed type, it is \emph{impossible}to forget to initialize such objects, as long as all constructors perform some sensible form of initialization.77 This goal is achieved through a guarantee that a constructor is called implicitly after every object is allocated from a type with associated constructors, as part of an object's definition. 78 Since a constructor is called on every object of a managed type, it is impossible to forget to initialize such objects, as long as all constructors perform some sensible form of initialization. 80 79 81 80 In \CFA, a constructor is a function with the name @?{}@. … … 115 114 In other words, a default constructor is a constructor that takes a single argument: the @this@ parameter. 116 115 117 In \CFA, a destructor is a function much like a constructor, except that its name is \lstinline!^?{}! \footnote{Originally, the name @~?{}@ was chosen for destructors, to provide familiarity to \CC programmers. Unforunately, this name causes parsing conflicts with the bitwise-not operator when used with operator syntax (see section \ref{sub:syntax}.)}and it takes only one argument.116 In \CFA, a destructor is a function much like a constructor, except that its name is \lstinline!^?{}! and it takes only one argument. 118 117 A destructor for the @Array@ type can be defined as: 119 118 \begin{cfacode} … … 136 135 On line 2, @z@ is initialized with the value of @x@, while on line 3, @y@ is assigned the value of @x@. 137 136 The key distinction between initialization and assignment is that a value to be initialized does not hold any meaningful values, whereas an object to be assigned might. 138 In particular, these cases cannot be handled the same way because in the former case @z@ has no array, while @y@ does. 139 A \emph{copy constructor} is used to perform initialization using another object of the same type. 137 In particular, these cases cannot be handled the same way because in the former case @z@ does not currently own an array, while @y@ does. 140 138 141 139 \begin{cfacode}[emph={other}, emphstyle=\color{red}] … … 153 151 } 154 152 \end{cfacode} 155 The two functions above handle the cases of initialization and assignment.156 The first function is called a copy constructor, because it constructs its argument by copying the values from another object of the same type.153 The two functions above handle these cases. 154 The first function is called a \emph{copy constructor}, because it constructs its argument by copying the values from another object of the same type. 157 155 The second function is the standard copy-assignment operator. 158 \CFA does not currently have the concept of reference types, so the most appropriate type for the source object in copy constructors and assignment operators is a value type.159 Appropriate care is taken in the implementation to avoid recursive calls to the copy constructor.160 156 The four functions (default constructor, destructor, copy constructor, and assignment operator) are special in that they safely control the state of most objects. 161 157 … … 220 216 A * y = malloc(); // copy construct: ?{}(&y, malloc()) 221 217 218 ?{}(&x); // explicit construct x, second construction 219 ?{}(y, x); // explit construct y from x, second construction 222 220 ^?{}(&x); // explicit destroy x, in different order 223 ?{}(&x); // explicit construct x, second construction224 221 ^?{}(y); // explicit destroy y 225 ?{}(y, x); // explit construct y from x, second construction226 222 227 223 // implicit ^?{}(&y); … … 283 279 \end{cfacode} 284 280 In this example, @malloc@ dynamically allocates storage and initializes it using a constructor, all before assigning it into the variable @x@. 285 Intuitively, the expression-resolver determines that @malloc@ returns some type @T *@, as does the constructor expression since it returns the type of its argument.286 This type flows outwards to the declaration site where the expected type is known to be @X *@, thus the first argument to the constructor must be @X *@, narrowing the search space.287 288 281 If this extension is not present, constructing dynamically allocated objects is much more cumbersome, requiring separate initialization of the pointer and initialization of the pointed-to memory. 289 282 \begin{cfacode} … … 307 300 It should be noted that this technique is not exclusive to @malloc@, and allows a user to write a custom allocator that can be idiomatically used in much the same way as a constructed @malloc@ call. 308 301 309 While it is possible to use operator syntax with destructors, destructors invalidate their argument, thus operator syntax with destructors is void-typed expression.302 It should be noted that while it is possible to use operator syntax with destructors, destructors invalidate their argument, thus operator syntax with destructors is a statement and does not produce a value. 310 303 311 304 \subsection{Function Generation} … … 315 308 If the translator can expect these functions to exist, then it can unconditionally attempt to resolve them. 316 309 Moreover, the existence of a standard interface allows polymorphic code to interoperate with new types seamlessly. 317 While automatic generation of assignment functions is present in previous versions of \CFA, the the implementation has been largely rewritten to accomodate constructors and destructors.318 310 319 311 To mimic the behaviour of standard C, the default constructor and destructor for all of the basic types and for all pointer types are defined to do nothing, while the copy constructor and assignment operator perform a bitwise copy of the source parameter (as in \CC). 320 This default is intended to maintain backwards compatibility and performance, by not imposing unexpected operations for a C programmer, as a zero-default behaviour would.321 However, it is possible for a user to define such constructors so that variables are safely zeroed by default, if desired.322 %%%%%%%%%%%%%%%%%%%%%%%%%% line width %%%%%%%%%%%%%%%%%%%%%%%%%%323 \begin{cfacode}324 void ?{}(int * i) { *i = 0; }325 forall(dtype T) void ?{}(T ** p) { *p = 0; } // any pointer type326 void f() {327 int x; // initialized to 0328 int * p; // initialized to 0329 }330 \end{cfacode}331 %%%%%%%%%%%%%%%%%%%%%%%%%% line width %%%%%%%%%%%%%%%%%%%%%%%%%%332 312 333 313 There are several options for user-defined types: structures, unions, and enumerations. 334 314 To aid in ease of use, the standard set of four functions is automatically generated for a user-defined type after its definition is completed. 335 315 By auto-generating these functions, it is ensured that legacy C code continues to work correctly in every context where \CFA expects these functions to exist, since they are generated for every complete type. 336 As well, these functions are always generated, since they may be needed by polymorphic functions.337 With that said, the generated functions are not called implicitly unless they are non-trivial, and are never exported, making it simple for the optimizer to strip them away when they are not used.338 316 339 317 The generated functions for enumerations are the simplest. … … 360 338 } 361 339 \end{cfacode} 362 In the future, \CFA will introduce strongly-typed enumerations, like those in \CC , wherein enumerations create a new type distinct from @int@ so that integral values require an explicit cast to be stored in an enumeration variable.340 In the future, \CFA will introduce strongly-typed enumerations, like those in \CC. 363 341 The existing generated routines are sufficient to express this restriction, since they are currently set up to take in values of that enumeration type. 364 342 Changes related to this feature only need to affect the expression resolution phase, where more strict rules will be applied to prevent implicit conversions from integral types to enumeration types, but should continue to permit conversions from enumeration types to @int@. … … 514 492 In addition to freedom, \ateq provides a simple path for migrating legacy C code to \CFA, in that objects can be moved from C-style initialization to \CFA gradually and individually. 515 493 It is worth noting that the use of unmanaged objects can be tricky to get right, since there is no guarantee that the proper invariants are established on an unmanaged object. 516 It is recommended that most objects be managed by sensible constructors and destructors, except where absolutely necessary , such as memory-mapped devices, trigger devices, I/O controllers, etc.494 It is recommended that most objects be managed by sensible constructors and destructors, except where absolutely necessary. 517 495 518 496 When a user declares any constructor or destructor, the corresponding intrinsic/generated function and all field constructors for that type are hidden, so that they are not found during expression resolution until the user-defined function goes out of scope. … … 567 545 \end{cfacode} 568 546 However, if the translator sees a sub-object used within the body of a constructor, but does not see a constructor call that uses the sub-object as the target of a constructor, then the translator assumes the object is to be implicitly constructed (copy constructed in a copy constructor and default constructed in any other constructor). 569 To override this rule, \ateq can be used to force the translator to trust the programmer's discretion.570 This form of \ateq is not yet implemented.571 547 \begin{cfacode} 572 548 void ?{}(A * a) { … … 580 556 } 581 557 582 void ?{}(A * a, int x) {583 // object forwarded to another constructor,584 // does not implicitly construct any members585 (&a){};586 }587 588 558 void ^?{}(A * a) { 589 559 ^(&a->x){}; // explicit destructor call 590 560 } // z, y, w implicitly destructed, in this order 591 561 \end{cfacode} 592 If at any point, the @this@ parameter is passed directly as the target of another constructor, then it is assumed the other constructor handles the initialization of all of the object's members and no implicit constructor calls are added to the current constructor. 562 If at any point, the @this@ parameter is passed directly as the target of another constructor, then it is assumed that constructor handles the initialization of all of the object's members and no implicit constructor calls are added. 563 To override this rule, \ateq can be used to force the translator to trust the programmer's discretion. 564 This form of \ateq is not yet implemented. 593 565 594 566 Despite great effort, some forms of C syntax do not work well with constructors in \CFA. … … 647 619 The body of @A@ has been omitted, since only the constructor interfaces are important. 648 620 649 It should be noted that unmanaged objects , i.e. objects that have only trivial constructors,can still make use of designations and nested initializers in \CFA.621 It should be noted that unmanaged objects can still make use of designations and nested initializers in \CFA. 650 622 It is simple to overcome this limitation for managed objects by making use of compound literals, so that the arguments to the constructor call are explicitly typed. 651 %%%%%%%%%%%%%%%%%%%%%%%%%% line width %%%%%%%%%%%%%%%%%%%%%%%%%%652 \begin{cfacode}653 struct B { int x; };654 struct C { int y; };655 struct A { B b; C c; };656 void ?{}(A *, B);657 void ?{}(A *, C);658 659 A a = {660 (C){ 10 } // disambiguate with compound literal661 };662 \end{cfacode}663 %%%%%%%%%%%%%%%%%%%%%%%%%% line width %%%%%%%%%%%%%%%%%%%%%%%%%%664 623 665 624 \subsection{Implicit Destructors} … … 785 744 \end{cfacode} 786 745 787 While \CFA supports the GCC computed-goto extension, the behaviour of managed objects in combination with computed-goto is undefined.788 \begin{cfacode}789 void f(int val) {790 void * l = val == 0 ? &&L1 : &&L2;791 {792 A x;793 L1: ;794 goto *l; // branches differently depending on argument795 }796 L2: ;797 }798 \end{cfacode}799 Likewise, destructors are not executed at scope-exit due to a computed-goto in \CC, as of g++ version 6.2.800 801 746 \subsection{Implicit Copy Construction} 802 747 \label{s:implicit_copy_construction} … … 805 750 Exempt from these rules are intrinsic and built-in functions. 806 751 It should be noted that unmanaged objects are subject to copy constructor calls when passed as arguments to a function or when returned from a function, since they are not the \emph{target} of the copy constructor call. 807 That is, since the parameter is not marked as an unmanaged object using \ateq, it is copy constructed if it is returned by value or passed as an argument to another function, so to guarantee consistent behaviour, unmanaged objects must be copy constructed when passed as arguments.752 That is, since the parameter is not marked as an unmanaged object using \ateq, it is be copy constructed if it is returned by value or passed as an argument to another function, so to guarantee consistent behaviour, unmanaged objects must be copy constructed when passed as arguments. 808 753 These semantics are important to bear in mind when using unmanaged objects, and could produce unexpected results when mixed with objects that are explicitly constructed. 809 754 \begin{cfacode} 810 struct A { ... };755 struct A; 811 756 void ?{}(A *); 812 757 void ?{}(A *, A); … … 865 810 It should be noted that reference types will allow specifying that a value does not need to be copied, however reference types do not provide a means of preventing implicit copy construction from uses of the reference, so the problem is still present when passing or returning the reference by value. 866 811 867 Adding implicit copy construction imposes the additional runtime cost of the copy constructor for every argument and return value in a function call.868 This cost is necessary to maintain appropriate value semantics when calling a function.869 In the future, return-value-optimization (RVO) can be implemented for \CFA to elide unnecessary copy construction and destruction of temporary objects.870 This cost is not present for types with trivial copy constructors and destructors.871 872 812 A known issue with this implementation is that the argument and return value temporaries are not guaranteed to have the same address for their entire lifetimes. 873 813 In the previous example, since @_retval_f@ is allocated and constructed in @f@, then returned by value, the internal data is bitwise copied into the caller's stack frame. … … 968 908 \subsection{Array Initialization} 969 909 Arrays are a special case in the C type-system. 970 Type checking largely ignores size information for C arrays, making it impossible to write a standalone \CFA function that constructs or destructs an array,while maintaining the standard interface for constructors and destructors.910 C arrays do not carry around their size, making it impossible to write a standalone \CFA function that constructs or destructs an array while maintaining the standard interface for constructors and destructors. 971 911 Instead, \CFA defines the initialization and destruction of an array recursively. 972 912 That is, when an array is defined, each of its elements is constructed in order from element 0 up to element $n-1$. … … 1207 1147 \end{cfacode} 1208 1148 1209 This implementation comes at the runtime cost of an additional branch for every @static@ local variable, each time the function is called.1210 Since initializers are not required to be compile-time constant expressions, they can involve global variables, function arguments, function calls, etc.1211 As a direct consequence, @static@ local variables cannot be initialized with an attribute-constructor routines like global variables can.1212 However, in the case where the variable is unmanaged and has a compile-time constant initializer, a C-compliant initializer is generated and the additional cost is not present.1213 \CC shares the same semantics for its @static@ local variables.1214 1215 1149 \subsection{Polymorphism} 1216 1150 As mentioned in section \ref{sub:polymorphism}, \CFA currently has 3 type-classes that are used to designate polymorphic data types: @otype@, @dtype@, and @ftype@. … … 1238 1172 These additions allow @f@'s body to create and destroy objects of type @T@, and pass objects of type @T@ as arguments to other functions, following the normal \CFA rules. 1239 1173 A point of note here is that objects can be missing default constructors (and eventually other functions through deleted functions), so it is important for \CFA programmers to think carefully about the operations needed by their function, as to not over-constrain the acceptable parameter types and prevent potential reuse. 1240 1241 These additional assertion parameters impose a runtime cost on all managed temporary objects created in polymorphic code, even those with trivial constructors and destructors.1242 This cost is necessary because polymorphic code does not know the actual type at compile-time, due to separate compilation.1243 Since trivial constructors and destructors either do not perform operations or are simply bit-wise copy operations, the imposed cost is essentially the cost of the function calls.1244 1245 \section{Summary}1246 1247 When creating a new object of a managed type, it is guaranteed that a constructor is be called to initialize the object at its definition point, and is destructed when the object's lifetime ends.1248 Destructors are called in the reverse order of construction.1249 1250 Every argument passed to a function is copy constructed into a temporary object that is passed by value to the functions and destructed at the end of the statement.1251 Function return values are copy constructed inside the function at the return statement, passed by value to the call-site, and destructed at the call-site at the end of the statement.1252 1253 Every complete object type has a default constructor, copy constructor, assignment operator, and destructor.1254 To accomplish this, these functions are generated as appropriate for new types.1255 User-defined functions shadow built-in and automatically generated functions, so it is possible to specialize the behaviour of a type.1256 Furthermore, default constructors and aggregate field constructors are hidden when \emph{any} constructor is defined.1257 1258 Objects dynamically allocated with @malloc@, \ateq objects, and objects with only trivial constructors and destructors are unmanaged.1259 Unmanaged objects are never the target of an implicit constructor or destructor call. -
doc/rob_thesis/intro.tex
r6250a312 r0f9bef3 19 19 Unfortunately, \CC is actively diverging from C, so incremental additions require significant effort and training, coupled with multiple legacy design-choices that cannot be updated. 20 20 21 The current implementation of \CFA is a source-to-source translator from \CFA to GNU C \cite{GCCExtensions}. 22 23 The remainder of this section describes some of the important features that currently exist in \CFA, to give the reader the necessary context in which the new features presented in this thesis must dovetail. 21 The remainder of this section describes some of the important new features that currently exist in \CFA, to give the reader the necessary context in which the new features presented in this thesis must dovetail. 24 22 25 23 \subsection{C Background} 26 24 \label{sub:c_background} 27 In the context of this work, the term \emph{object} refers to a region of data storage in the execution environment, the contents of which can represent values \cite[p.~6]{C11}.28 29 25 One of the lesser-known features of standard C is \emph{designations}. 30 26 Designations are similar to named parameters in languages such as Python and Scala, except that they only apply to aggregate initializers. 31 Note that in \CFA, designations use a colon separator, rather than an equals sign as in C, because this syntax is one of the few places that conflicts with the new language features.32 27 \begin{cfacode} 33 28 struct A { … … 48 43 Later initializers override earlier initializers, so a sub-object for which there is more than one initializer is only initialized by its last initializer. 49 44 These semantics can be seen in the initialization of @a0@, where @x@ is designated twice, and thus initialized to @8@. 45 Note that in \CFA, designations use a colon separator, rather than an equals sign as in C, because this syntax is one of the few places that conflicts with the new language features. 50 46 51 47 C also provides \emph{compound literal} expressions, which provide a first-class mechanism for creating unnamed objects. … … 61 57 Compound literals create an unnamed object, and result in an lvalue, so it is legal to assign a value into a compound literal or to take its address \cite[p.~86]{C11}. 62 58 Syntactically, compound literals look like a cast operator followed by a brace-enclosed initializer, but semantically are different from a C cast, which only applies basic conversions and coercions and is never an lvalue. 63 64 The \CFA translator makes use of several GNU C extensions, including \emph{nested functions} and \emph{attributes}.65 Nested functions make it possible to access data that is lexically in scope in the nested function's body.66 \begin{cfacode}67 int f() {68 int x = 0;69 void g() {70 x++;71 }72 g(); // changes x73 }74 \end{cfacode}75 Nested functions come with the usual C caveat that they should not leak into the containing environment, since they are only valid as long as the containing function's stack frame is active.76 77 Attributes make it possible to inform the compiler of certain properties of the code.78 For example, a function can be marked as deprecated, so that legacy APIs can be identified and slowly removed, or as \emph{hot}, so that the compiler knows the function is called frequently and should be aggresively optimized.79 \begin{cfacode}80 __attribute__((deprecated("foo is deprecated, use bar instead")))81 void foo();82 __attribute__((hot)) void bar(); // heavily optimized83 84 foo(); // warning85 bar();86 \end{cfacode}87 59 88 60 \subsection{Overloading} … … 92 64 C provides a small amount of built-in overloading, \eg + is overloaded for the basic types. 93 65 Like in \CC, \CFA allows user-defined overloading based both on the number of parameters and on the types of parameters. 94 \begin{cfacode}95 void f(void); // (1)96 void f(int); // (2)97 void f(char); // (3)98 99 f('A'); // selects (3)100 \end{cfacode}66 \begin{cfacode} 67 void f(void); // (1) 68 void f(int); // (2) 69 void f(char); // (3) 70 71 f('A'); // selects (3) 72 \end{cfacode} 101 73 In this case, there are three @f@ procedures, where @f@ takes either 0 or 1 arguments, and if an argument is provided then it may be of type @int@ or of type @char@. 102 74 Exactly which procedure is executed depends on the number and types of arguments passed. 103 75 If there is no exact match available, \CFA attempts to find a suitable match by examining the C built-in conversion heuristics. 104 The \CFA expression resolution algorithm uses a cost function to determine the interpretation that uses the fewest conversions and polymorphic type bindings. 105 \begin{cfacode} 106 void g(long long); 107 108 g(12345); 109 \end{cfacode} 76 \begin{cfacode} 77 void g(long long); 78 79 g(12345); 80 \end{cfacode} 110 81 In the above example, there is only one instance of @g@, which expects a single parameter of type @long long@. 111 82 Here, the argument provided has type @int@, but since all possible values of type @int@ can be represented by a value of type @long long@, there is a safe conversion from @int@ to @long long@, and so \CFA calls the provided @g@ routine. 112 83 113 Overloading solves the problem present in C where there can only be one function with a given name, requiring multiple names for functions that perform the same operation but take in different types.114 This can be seen in the example of the absolute value functions C:115 \begin{cfacode}116 // stdlib.h117 int abs(int);118 long int labs(long int);119 long long int llabs(long long int);120 \end{cfacode}121 In \CFA, the functions @labs@ and @llabs@ are replaced by appropriate overloads of @abs@.122 123 84 In addition to this form of overloading, \CFA also allows overloading based on the number and types of \emph{return} values. 124 85 This extension is a feature that is not available in \CC, but is available in other programming languages such as Ada \cite{Ada95}. 125 \begin{cfacode}126 int g(); // (1)127 double g(); // (2)128 129 int x = g(); // selects (1)130 \end{cfacode}86 \begin{cfacode} 87 int g(); // (1) 88 double g(); // (2) 89 90 int x = g(); // selects (1) 91 \end{cfacode} 131 92 Here, the only difference between the signatures of the different versions of @g@ is in the return values. 132 93 The result context is used to select an appropriate routine definition. 133 94 In this case, the result of @g@ is assigned into a variable of type @int@, so \CFA prefers the routine that returns a single @int@, because it is an exact match. 134 135 Return-type overloading solves similar problems to parameter-list overloading, in that multiple functions that perform similar operations can have the same, but produce different values.136 One use case for this feature is to provide two versions of the @bsearch@ routine:137 \begin{cfacode}138 forall(otype T | { int ?<?( T, T ); })139 T * bsearch(T key, const T * arr, size_t dimension) {140 int comp(const void * t1, const void * t2) {141 return *(T *)t1 < *(T *)t2 ? -1 : *(T *)t2 < *(T *)t1 ? 1 : 0;142 }143 return (T *)bsearch(&key, arr, dimension, sizeof(T), comp);144 }145 forall(otype T | { int ?<?( T, T ); })146 unsigned int bsearch(T key, const T * arr, size_t dimension) {147 T *result = bsearch(key, arr, dimension);148 // pointer subtraction includes sizeof(T)149 return result ? result - arr : dimension;150 }151 double key = 5.0;152 double vals[10] = { /* 10 floating-point values */ };153 154 double * val = bsearch( 5.0, vals, 10 ); // selection based on return type155 int posn = bsearch( 5.0, vals, 10 );156 \end{cfacode}157 The first version provides a thin wrapper around the C @bsearch@ routine, converting untyped @void *@ to the polymorphic type @T *@, allowing the \CFA compiler to catch errors when the type of @key@, @arr@, and the target at the call-site do not agree.158 The second version provides an alternate return of the index in the array of the selected element, rather than its address.159 95 160 96 There are times when a function should logically return multiple values. … … 209 145 210 146 An extra quirk introduced by multiple return values is in the resolution of function calls. 211 \begin{cfacode}212 int f(); // (1)213 [int, int] f(); // (2)214 215 void g(int, int);216 217 int x, y;218 [x, y] = f(); // selects (2)219 g(f()); // selects (2)220 \end{cfacode}147 \begin{cfacode} 148 int f(); // (1) 149 [int, int] f(); // (2) 150 151 void g(int, int); 152 153 int x, y; 154 [x, y] = f(); // selects (2) 155 g(f()); // selects (2) 156 \end{cfacode} 221 157 In this example, the only possible call to @f@ that can produce the two @int@s required for assigning into the variables @x@ and @y@ is the second option. 222 158 A similar reasoning holds calling the function @g@. 223 224 This duality between aggregation and aliasing can be seen in the C standard library in the @div@ and @remquo@ functions, which return the quotient and remainder for a division of integer and floating-point values, respectively.225 \begin{cfacode}226 typedef struct { int quo, rem; } div_t; // from stdlib.h227 div_t div( int num, int den );228 double remquo( double num, double den, int * quo );229 div_t qr = div( 13, 5 ); // return quotient/remainder aggregate230 int q;231 double r = remquo( 13.5, 5.2, &q ); // return remainder, alias quotient232 \end{cfacode}233 @div@ aggregates the quotient/remainder in a structure, while @remquo@ aliases a parameter to an argument.234 Alternatively, a programming language can directly support returning multiple values, \eg in \CFA:235 \begin{lstlisting}236 [int, int] div(int num, int den); // return two integers237 [double, double] div( double num, double den ); // return two doubles238 int q, r; // overloaded variable names239 double q, r;240 [q, r] = div(13, 5); // select appropriate div and q, r241 [q, r] = div(13.5, 5.2);242 \end{lstlisting}243 159 244 160 In \CFA, overloading also applies to operator names, known as \emph{operator overloading}. 245 161 Similar to function overloading, a single operator is given multiple meanings by defining new versions of the operator with different signatures. 246 162 In \CC, this can be done as follows 247 \begin{cppcode}248 struct A { int i; };249 Aoperator+(A x, A y);250 bool operator<(A x, A y);251 \end{cppcode}163 \begin{cppcode} 164 struct A { int i; }; 165 int operator+(A x, A y); 166 bool operator<(A x, A y); 167 \end{cppcode} 252 168 253 169 In \CFA, the same example can be written as follows. 254 \begin{cfacode}255 struct A { int i; };256 A?+?(A x, A y); // '?'s represent operands257 int?<?(A x, A y);258 \end{cfacode}170 \begin{cfacode} 171 struct A { int i; }; 172 int ?+?(A x, A y); // '?'s represent operands 173 bool ?<?(A x, A y); 174 \end{cfacode} 259 175 Notably, the only difference is syntax. 260 176 Most of the operators supported by \CC for operator overloading are also supported in \CFA. … … 263 179 Finally, \CFA also permits overloading variable identifiers. 264 180 This feature is not available in \CC. 265 \begin{cfacode}266 struct Rational { int numer, denom; };267 int x = 3; // (1)268 double x = 1.27; // (2)269 Rational x = { 4, 11 }; // (3)270 271 void g(double);272 273 x += 1; // chooses (1)274 g(x); // chooses (2)275 Rational y = x; // chooses (3)276 \end{cfacode}181 \begin{cfacode} 182 struct Rational { int numer, denom; }; 183 int x = 3; // (1) 184 double x = 1.27; // (2) 185 Rational x = { 4, 11 }; // (3) 186 187 void g(double); 188 189 x += 1; // chooses (1) 190 g(x); // chooses (2) 191 Rational y = x; // chooses (3) 192 \end{cfacode} 277 193 In this example, there are three definitions of the variable @x@. 278 194 Based on the context, \CFA attempts to choose the variable whose type best matches the expression context. … … 292 208 Due to these rewrite rules, the values @0@ and @1@ have the types \zero and \one in \CFA, which allow for overloading various operations that connect to @0@ and @1@ \footnote{In the original design of \CFA, @0@ and @1@ were overloadable names \cite[p.~7]{cforall}.}. 293 209 The types \zero and \one have special built-in implicit conversions to the various integral types, and a conversion to pointer types for @0@, which allows standard C code involving @0@ and @1@ to work as normal. 294 \begin{cfacode}295 // lvalue is similar to returning a reference in C++296 lvalue Rational ?+=?(Rational *a, Rational b);297 Rational ?=?(Rational * dst, zero_t) {298 return *dst = (Rational){ 0, 1 };299 }300 301 Rational sum(Rational *arr, int n) {302 Rational r;303 r = 0; // use rational-zero_t assignment304 for (; n > 0; n--) {305 r += arr[n-1];306 }307 return r;308 }309 \end{cfacode}210 \begin{cfacode} 211 // lvalue is similar to returning a reference in C++ 212 lvalue Rational ?+=?(Rational *a, Rational b); 213 Rational ?=?(Rational * dst, zero_t) { 214 return *dst = (Rational){ 0, 1 }; 215 } 216 217 Rational sum(Rational *arr, int n) { 218 Rational r; 219 r = 0; // use rational-zero_t assignment 220 for (; n > 0; n--) { 221 r += arr[n-1]; 222 } 223 return r; 224 } 225 \end{cfacode} 310 226 This function takes an array of @Rational@ objects and produces the @Rational@ representing the sum of the array. 311 227 Note the use of an overloaded assignment operator to set an object of type @Rational@ to an appropriate @0@ value. … … 316 232 In particular, \CFA supports the notion of parametric polymorphism. 317 233 Parametric polymorphism allows a function to be written generically, for all values of all types, without regard to the specifics of a particular type. 318 For example, in \CC, the simple identity function for all types can be written as :319 \begin{cppcode}320 template<typename T>321 T identity(T x) { return x; }322 \end{cppcode}323 \CC uses the template mechanism to support parametric polymorphism. In \CFA, an equivalent function can be written as :324 \begin{cfacode}325 forall(otype T)326 T identity(T x) { return x; }327 \end{cfacode}234 For example, in \CC, the simple identity function for all types can be written as 235 \begin{cppcode} 236 template<typename T> 237 T identity(T x) { return x; } 238 \end{cppcode} 239 \CC uses the template mechanism to support parametric polymorphism. In \CFA, an equivalent function can be written as 240 \begin{cfacode} 241 forall(otype T) 242 T identity(T x) { return x; } 243 \end{cfacode} 328 244 Once again, the only visible difference in this example is syntactic. 329 245 Fundamental differences can be seen by examining more interesting examples. 330 In \CC, a generic sum function is written as follows :331 \begin{cppcode}332 template<typename T>333 T sum(T *arr, int n) {334 T t; // default construct => 0335 for (; n > 0; n--) t += arr[n-1];336 return t;337 }338 \end{cppcode}246 In \CC, a generic sum function is written as follows 247 \begin{cppcode} 248 template<typename T> 249 T sum(T *arr, int n) { 250 T t; // default construct => 0 251 for (; n > 0; n--) t += arr[n-1]; 252 return t; 253 } 254 \end{cppcode} 339 255 Here, the code assumes the existence of a default constructor, assignment operator, and an addition operator over the provided type @T@. 340 256 If any of these required operators are not available, the \CC compiler produces an error message stating which operators could not be found. 341 257 342 A similar sum function can be written in \CFA as follows :343 \begin{cfacode}344 forall(otype T | **R**{ T ?=?(T *, zero_t); T ?+=?(T *, T); }**R**)345 T sum(T *arr, int n) {346 T t = 0;347 for (; n > 0; n--) t = t += arr[n-1];348 return t;349 }350 \end{cfacode}258 A similar sum function can be written in \CFA as follows 259 \begin{cfacode} 260 forall(otype T | **R**{ T ?=?(T *, zero_t); T ?+=?(T *, T); }**R**) 261 T sum(T *arr, int n) { 262 T t = 0; 263 for (; n > 0; n--) t = t += arr[n-1]; 264 return t; 265 } 266 \end{cfacode} 351 267 The first thing to note here is that immediately following the declaration of @otype T@ is a list of \emph{type assertions} that specify restrictions on acceptable choices of @T@. 352 268 In particular, the assertions above specify that there must be an assignment from \zero to @T@ and an addition assignment operator from @T@ to @T@. 353 269 The existence of an assignment operator from @T@ to @T@ and the ability to create an object of type @T@ are assumed implicitly by declaring @T@ with the @otype@ type-class. 354 270 In addition to @otype@, there are currently two other type-classes. 355 356 @dtype@, short for \emph{data type}, serves as the top type for object types; any object type, complete or incomplete, can be bound to a @dtype@ type variable.357 To contrast, @otype@, short for \emph{object type}, is a @dtype@ with known size, alignment, and an assignment operator, and thus bind only to complete object types.358 With this extra information, complete objects can be used in polymorphic code in the same way they are used in monomorphic code, providing familiarity and ease of use.359 The third type-class is @ftype@, short for \emph{function type}, matching only function types.360 271 The three type parameter kinds are summarized in \autoref{table:types} 361 272 … … 364 275 \begin{tabular}{|c||c|c|c||c|c|c|} 365 276 \hline 366 name & object type & incomplete type & function type & can assign & can create & has size \\ \hline277 name & object type & incomplete type & function type & can assign value & can create & has size \\ \hline 367 278 @otype@ & X & & & X & X & X \\ \hline 368 279 @dtype@ & X & X & & & & \\ \hline … … 377 288 In contrast, the explicit nature of assertions allows \CFA's polymorphic functions to be separately compiled, as the function prototype states all necessary requirements separate from the implementation. 378 289 For example, the prototype for the previous sum function is 379 \begin{cfacode}380 forall(otype T | **R**{ T ?=?(T *, zero_t); T ?+=?(T *, T); }**R**)381 T sum(T *arr, int n);382 \end{cfacode}290 \begin{cfacode} 291 forall(otype T | **R**{ T ?=?(T *, zero_t); T ?+=?(T *, T); }**R**) 292 T sum(T *arr, int n); 293 \end{cfacode} 383 294 With this prototype, a caller in another translation unit knows all of the constraints on @T@, and thus knows all of the operations that need to be made available to @sum@. 384 295 385 296 In \CFA, a set of assertions can be factored into a \emph{trait}. 386 297 \begin{cfacode} 387 trait Addable(otype T) {388 T ?+?(T, T);389 T ++?(T);390 T ?++(T);391 }392 forall(otype T | Addable(T)) void f(T);393 forall(otype T | Addable(T) | { T --?(T); }) T g(T);394 forall(otype T, U | Addable(T) | { T ?/?(T, U); }) U h(T, U);298 trait Addable(otype T) { 299 T ?+?(T, T); 300 T ++?(T); 301 T ?++(T); 302 } 303 forall(otype T | Addable(T)) void f(T); 304 forall(otype T | Addable(T) | { T --?(T); }) T g(T); 305 forall(otype T, U | Addable(T) | { T ?/?(T, U); }) U h(T, U); 395 306 \end{cfacode} 396 307 This capability allows specifying the same set of assertions in multiple locations, without the repetition and likelihood of mistakes that come with manually writing them out for each function declaration. 397 308 398 An interesting application of return-type resolution and polymorphism is a polymorphicversion of @malloc@.309 An interesting application of return-type resolution and polymorphism is a type-safe version of @malloc@. 399 310 \begin{cfacode} 400 311 forall(dtype T | sized(T)) … … 410 321 The built-in trait @sized@ ensures that size and alignment information for @T@ is available in the body of @malloc@ through @sizeof@ and @_Alignof@ expressions respectively. 411 322 In calls to @malloc@, the type @T@ is bound based on call-site information, allowing \CFA code to allocate memory without the potential for errors introduced by manually specifying the size of the allocated block. 412 413 \subsection{Planned Features}414 415 One of the planned features \CFA is \emph{reference types}.416 At a high level, the current proposal is to add references as a way to cleanup pointer syntax.417 With references, it will be possible to store any address, as with a pointer, with the key difference being that references are automatically dereferenced.418 \begin{cfacode}419 int x = 0;420 int * p = &x; // needs &421 int & ref = x; // no &422 423 printf("%d %d\n", *p, ref); // pointer needs *, ref does not424 \end{cfacode}425 426 It is possible to add new functions or shadow existing functions for the duration of a scope, using normal C scoping rules.427 One application of this feature is to reverse the order of @qsort@.428 \begin{cfacode}429 forall(otype T | { int ?<?( T, T ); })430 void qsort(const T * arr, size_t size) {431 int comp(const void * t1, const void * t2) {432 return *(T *)t1 < *(T *)t2 ? -1 : *(T *)t2 < *(T *)t1 ? 1 : 0;433 }434 qsort(arr, dimension, sizeof(T), comp);435 436 }437 double vals[10] = { ... };438 qsort(vals, 10); // ascending order439 {440 int ?<?(double x, double y) { // locally override behaviour441 return x > y;442 }443 qsort(vals, 10); // descending sort444 }445 \end{cfacode}446 Currently, there is no way to \emph{remove} a function from consideration from the duration of a scope.447 For example, it may be desirable to eliminate assignment from a scope, to reduce accidental mutation.448 To address this desire, \emph{deleted functions} are a planned feature for \CFA.449 \begin{cfacode}450 forall(otype T) void f(T *);451 452 int x = 0;453 f(&x); // might modify x454 {455 int ?=?(int *, int) = delete;456 f(&x); // error, no assignment for int457 }458 \end{cfacode}459 Now, if the deleted function is chosen as the best match, the expression resolver emits an error.460 323 461 324 \section{Invariants} … … 587 450 \end{javacode} 588 451 In Java 7, a new \emph{try-with-resources} construct was added to alleviate most of the pain of working with resources, but ultimately it still places the burden squarely on the user rather than on the library designer. 589 Furthermore, for complete safety this pattern requires nested objects to be declared separately, otherwise resources that can throw an exception on close can leak nested resources \ footnote{Since close is only guaranteed to be called on objects declared in the try-list and not objects passed as constructor parameters, the @B@ object may not be closed in @new A(new B())@ if @A@'s close raises an exception.} \cite{TryWithResources}.452 Furthermore, for complete safety this pattern requires nested objects to be declared separately, otherwise resources that can throw an exception on close can leak nested resources \cite{TryWithResources}. 590 453 \begin{javacode} 591 454 public void write(String filename, String msg) throws Exception { … … 658 521 % these are declared in the struct, so they're closer to C++ than to CFA, at least syntactically. Also do not allow for default constructors 659 522 % D has a GC, which already makes the situation quite different from C/C++ 660 The programming language Dalso manages resources with constructors and destructors \cite{D}.661 In D, @struct@s are stack allocat ableand managed via scoping like in \CC, whereas @class@es are managed automatically by the garbage collector.523 The programming language, D, also manages resources with constructors and destructors \cite{D}. 524 In D, @struct@s are stack allocated and managed via scoping like in \CC, whereas @class@es are managed automatically by the garbage collector. 662 525 Like Java, using the garbage collector means that destructors are called indeterminately, requiring the use of finally statements to ensure dynamically allocated resources that are not managed by the garbage collector, such as open files, are cleaned up. 663 526 Since D supports RAII, it is possible to use the same techniques as in \CC to ensure that resources are released in a timely manner. … … 892 755 893 756 Type-safe variadic functions are added to \CFA and discussed in Chapter 4. 894 895 \section{Contributions}896 \label{s:contributions}897 898 No prior work on constructors or destructors had been done for \CFA.899 I did both the design and implementation work.900 While the overall design is based on constructors and destructors in object-oriented C++, it had to be re-engineered into non-object-oriented \CFA.901 I also had to make changes to the \CFA expression-resolver to integrate constructors and destructors into the type system.902 903 Prior work on the design of tuples for \CFA was done by Till, and some initial implementation work by Esteves.904 I largely took the Till design but added tuple indexing, which exists in a number of programming languages with tuples, simplified the implicit tuple conversions, and integrated with the \CFA polymorphism and assertion satisfaction model.905 I did a new implementation of tuples, and extensively906 augmented initial work by Bilson to incorporate tuples into the \CFA expression-resolver and type-unifier.907 908 No prior work on variadic functions had been done for \CFA.909 I did both the design and implementation work.910 While the overall design is based on variadic templates in C++, my design is novel in the way it is incorporated into the \CFA polymorphism model, and is engineered into \CFA so it dovetails with tuples. -
doc/rob_thesis/thesis-frontpgs.tex
r6250a312 r0f9bef3 86 86 %\newpage 87 87 88 % A C K N O W L E D G E M E N T S89 % -------------------------------88 % % A C K N O W L E D G E M E N T S 89 % % ------------------------------- 90 90 91 \begin{center}\textbf{Acknowledgements}\end{center}91 % \begin{center}\textbf{Acknowledgements}\end{center} 92 92 93 I would like to thank my supervisor, Professor Peter Buhr, for all of his help, including reading the many drafts of this thesis and providing guidance throughout my degree. 94 This work would not have been as enjoyable, nor would it have been as strong without Peter's knowledge, help, and encouragement. 95 96 I would like to thank my readers, Professors Gregor Richards and Patrick Lam for all of their helpful feedback. 97 98 Thanks to Aaron Moss and Thierry Delisle for many helpful discussions, both work-related and not, and for all of the work they have put into the \CFA project. 99 This thesis would not have been the same without their efforts. 100 101 I thank Glen Ditchfield and Richard Bilson, for all of their help with both the design and implementation of \CFA. 102 103 I thank my partner, Erin Blackmere, for all of her love and support. 104 Without her, I would not be who I am today. 105 106 Thanks to my parents, Bob and Jackie Schluntz, for their love and support throughout my life, and for always encouraging me to be my best. 107 108 Thanks to my best friends, Travis Bartlett, Abraham Dubrisingh, and Kevin Wu, whose companionship is always appreciated. 109 The time we've spent together over the past 4 years has always kept me entertained. 110 An extra shout-out to Kaleb Alway, Max Bardakov, Ten Bradley, and Ed Lee, with whom I've shared many a great meal; thank you for being my friend. 111 112 Finally, I would like to acknowledge financial support in the form of a David R. Cheriton Graduate Scholarship and a corporate partnership with Huawei Ltd. 113 114 \cleardoublepage 115 %\newpage 93 % % I would like to thank all the little people who made this possible. 94 % TODO 95 % \cleardoublepage 96 % %\newpage 116 97 117 98 % % D E D I C A T I O N -
doc/rob_thesis/thesis.tex
r6250a312 r0f9bef3 118 118 \usepackage[pdftex]{graphicx} % For including graphics N.B. pdftex graphics driver 119 119 120 \usepackage{xcolor}121 \usepackage{listings}122 123 120 \input{cfa-format.tex} 124 121 … … 141 138 pdftitle={Resource Management and Tuples in \CFA}, % title: CHANGE THIS TEXT! 142 139 pdfauthor={Rob Schluntz}, % author: CHANGE THIS TEXT! and uncomment this line 143 pdfsubject={Programming Languages}, % subject: CHANGE THIS TEXT! and uncomment this line140 % pdfsubject={Subject}, % subject: CHANGE THIS TEXT! and uncomment this line 144 141 % pdfkeywords={keyword1} {key2} {key3}, % list of keywords, and uncomment this line if desired 145 142 pdfnewwindow=true, % links in new window -
doc/rob_thesis/tuples.tex
r6250a312 r0f9bef3 161 161 \end{cfacode} 162 162 163 \begin{sloppypar}164 163 In addition to variables of tuple type, it is also possible to have pointers to tuples, and arrays of tuples. 165 Tuple types can be composed of any types, except for array types, since array assignment is disallowed, which makes tuple assignment difficult when a tuple contains an array.164 Tuple types can be composed of any types, except for array types, since arrays do not carry their size around, which makes tuple assignment difficult when a tuple contains an array. 166 165 \begin{cfacode} 167 166 [double, int] di; … … 170 169 \end{cfacode} 171 170 This examples declares a variable of type @[double, int]@, a variable of type pointer to @[double, int]@, and an array of ten @[double, int]@. 172 \end{sloppypar}173 171 174 172 \subsection{Tuple Indexing} … … 214 212 The flexible structure of tuples permits a simple and expressive function-call syntax to work seamlessly with both single- and multiple-return-value functions, and with any number of arguments of arbitrarily complex structure. 215 213 216 In \KWC \cite{Buhr94a,Till89}, there were 4 tuple coercions: opening, closing, flattening, and structuring.214 In \KWC \cite{Buhr94a,Till89}, a precursor to \CFA, there were 4 tuple coercions: opening, closing, flattening, and structuring. 217 215 Opening coerces a tuple value into a tuple of values, while closing converts a tuple of values into a single tuple value. 218 216 Flattening coerces a nested tuple into a flat tuple, \ie it takes a tuple with tuple components and expands it into a tuple with only non-tuple components. … … 220 218 221 219 In \CFA, the design has been simplified to require only the two conversions previously described, which trigger only in function call and return situations. 222 This simplification is a primary contribution of this thesis to the design of tuples in \CFA.223 220 Specifically, the expression resolution algorithm examines all of the possible alternatives for an expression to determine the best match. 224 221 In resolving a function call expression, each combination of function value and list of argument alternatives is examined. … … 257 254 Let $L_i$ for $i$ in $[0, n)$ represent each component of the flattened left side, $R_i$ represent each component of the flattened right side of a multiple assignment, and $R$ represent the right side of a mass assignment. 258 255 259 For a multiple assignment to be valid, both tuples must have the same number of elements when flattened. 260 For example, the following is invalid because the number of components on the left does not match the number of components on the right. 261 \begin{cfacode} 262 [int, int] x, y, z; 263 [x, y] = z; // multiple assignment, invalid 4 != 2 264 \end{cfacode} 265 Multiple assignment assigns $R_i$ to $L_i$ for each $i$. 256 For a multiple assignment to be valid, both tuples must have the same number of elements when flattened. Multiple assignment assigns $R_i$ to $L_i$ for each $i$. 266 257 That is, @?=?(&$L_i$, $R_i$)@ must be a well-typed expression. 267 258 In the previous example, @[x, y] = z@, @z@ is flattened into @z.0, z.1@, and the assignments @x = z.0@ and @y = z.1@ happen. … … 274 265 275 266 Both kinds of tuple assignment have parallel semantics, such that each value on the left side and right side is evaluated \emph{before} any assignments occur. 276 As a result, it is possible to swap the values in two variables without explicitly creating any temporary variables or calling a function .267 As a result, it is possible to swap the values in two variables without explicitly creating any temporary variables or calling a function, 277 268 \begin{cfacode} 278 269 int x = 10, y = 20; … … 305 296 \subsection{Tuple Construction} 306 297 Tuple construction and destruction follow the same rules and semantics as tuple assignment, except that in the case where there is no right side, the default constructor or destructor is called on each component of the tuple. 307 As constructors and destructors did not exist in previous versions of \CFA or in \KWC, this is a primary contribution of this thesis to the design of tuples.308 298 \begin{cfacode} 309 299 struct S; … … 443 433 \section{Casting} 444 434 In C, the cast operator is used to explicitly convert between types. 445 In \CFA, the cast operator has a secondary use, which is type ascription, since it force sthe expression resolution algorithm to choose the lowest cost conversion to the target type.435 In \CFA, the cast operator has a secondary use, which is type ascription, since it force the expression resolution algorithm to choose the lowest cost conversion to the target type. 446 436 That is, a cast can be used to select the type of an expression when it is ambiguous, as in the call to an overloaded function. 447 437 \begin{cfacode} … … 497 487 \section{Polymorphism} 498 488 Due to the implicit flattening and structuring conversions involved in argument passing, @otype@ and @dtype@ parameters are restricted to matching only with non-tuple types. 499 The integration of polymorphism, type assertions, and monomorphic specialization of tuple-assertions are a primary contribution of this thesis to the design of tuples.500 489 \begin{cfacode} 501 490 forall(otype T, dtype U) … … 535 524 It is also important to note that these calls could be disambiguated if the function return types were different, as they likely would be for a reasonable implementation of @?+?@, since the return type is used in overload resolution. 536 525 Still, these semantics are a deficiency of the current argument matching algorithm, and depending on the function, differing return values may not always be appropriate. 537 These issues could be rectified by applying an appropriate co nversion cost to the structuring and flattening conversions, which are currently 0-cost conversions in the expression resolver.526 These issues could be rectified by applying an appropriate cost to the structuring and flattening conversions, which are currently 0-cost conversions. 538 527 Care would be needed in this case to ensure that exact matches do not incur such a cost. 539 528 \begin{cfacode} … … 570 559 \section{Implementation} 571 560 Tuples are implemented in the \CFA translator via a transformation into generic types. 572 Generic types are an independent contribution developed at the same time.573 The transformation into generic types and the generation of tuple-specific code are primary contributions of this thesis to tuples.574 575 561 The first time an $N$-tuple is seen for each $N$ in a scope, a generic type with $N$ type parameters is generated. 576 562 For example, -
doc/rob_thesis/variadic.tex
r6250a312 r0f9bef3 5 5 \section{Design Criteria} % TODO: better section name??? 6 6 C provides variadic functions through the manipulation of @va_list@ objects. 7 In C, avariadic function is one which contains at least one parameter, followed by @...@ as the last token in the parameter list.8 In particular, some form of \emph{argument descriptor} or \emph{sentinel value}is needed to inform the function of the number of arguments and their types.7 A variadic function is one which contains at least one parameter, followed by @...@ as the last token in the parameter list. 8 In particular, some form of \emph{argument descriptor} is needed to inform the function of the number of arguments and their types. 9 9 Two common argument descriptors are format strings or counter parameters. 10 It is important to note that both of these mechanisms are inherently redundant, because they require the user to explicitly specify information that the compiler already knows \footnote{While format specifiers can convey some information the compiler does not know, such as whether to print a number in decimal or hexadecimal, the number of arguments is wholly redundant.}.10 It is important to note that both of these mechanisms are inherently redundant, because they require the user to explicitly specify information that the compiler already knows. 11 11 This required repetition is error prone, because it is easy for the user to add or remove arguments without updating the argument descriptor. 12 12 In addition, C requires the programmer to hard code all of the possible expected types. … … 152 152 That is to say, the programmer who writes @sum@ does not need full program knowledge of every possible data type, unlike what is necessary to write an equivalent function using the standard C mechanisms. 153 153 154 \begin{sloppypar}155 154 Going one last step, it is possible to achieve full generality in \CFA, allowing the summation of arbitrary lists of summable types. 156 155 \begin{cfacode} … … 171 170 \end{cfacode} 172 171 The \CFA translator requires adding explicit @double ?+?(int, double)@ and @double ?+?(double, int)@ functions for this call to work, since implicit conversions are not supported for assertions. 173 \end{sloppypar}174 172 175 173 A notable limitation of this approach is that it heavily relies on recursive assertions. … … 228 226 In the call to @new@, @Array@ is selected to match @T@, and @Params@ is expanded to match @[int, int, int, int]@. To satisfy the assertions, a constructor with an interface compatible with @void ?{}(Array *, int, int, int)@ must exist in the current scope. 229 227 230 The @new@ function provides the combination of polymorphic@malloc@ with a constructor call, so that it becomes impossible to forget to construct dynamically-allocated objects.228 The @new@ function provides the combination of type-safe @malloc@ with a constructor call, so that it becomes impossible to forget to construct dynamically-allocated objects. 231 229 This approach provides the type-safety of @new@ in \CC, without the need to specify the allocated type, thanks to return-type inference. 232 230 -
src/CodeGen/CodeGenerator.cc
r6250a312 r0f9bef3 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : T us May 9 16:50:00201713 // Update Count : 48 411 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Mar 30 16:38:01 2017 13 // Update Count : 482 14 14 // 15 15 … … 41 41 namespace CodeGen { 42 42 int CodeGenerator::tabsize = 4; 43 44 // Pseudo Function: output << lineDirective(currentNode);45 struct lineDirective {46 CodeLocation const & loc;47 lineDirective(CodeLocation const & location) : loc(location) {}48 lineDirective(BaseSyntaxNode const * node) : loc(node->location) {}49 };50 std::ostream & operator<<(std::ostream & out, lineDirective const & ld) {51 if (ld.loc.isSet())52 return out << "\n# " << ld.loc.linenumber << " \""53 << ld.loc.filename << "\"\n";54 return out << "\n// Unset Location\n";55 }56 43 57 44 // the kinds of statements that would ideally be followed by whitespace … … 141 128 142 129 143 // 130 //*** Declarations 144 131 void CodeGenerator::visit( FunctionDecl * functionDecl ) { 145 output << lineDirective( functionDecl );146 147 132 extension( functionDecl ); 148 133 genAttributes( functionDecl->get_attributes() ); … … 168 153 } 169 154 170 output << lineDirective( objectDecl );171 172 155 extension( objectDecl ); 173 156 genAttributes( objectDecl->get_attributes() ); … … 209 192 cur_indent += CodeGenerator::tabsize; 210 193 for ( std::list< Declaration* >::iterator i = memb.begin(); i != memb.end(); i++ ) { 211 output << lineDirective( *i ) <<indent;194 output << indent; 212 195 (*i)->accept( *this ); 213 196 output << ";" << endl; … … 221 204 222 205 void CodeGenerator::visit( StructDecl * structDecl ) { 223 output << lineDirective( structDecl );224 225 206 extension( structDecl ); 226 207 handleAggregate( structDecl, "struct " ); … … 228 209 229 210 void CodeGenerator::visit( UnionDecl * unionDecl ) { 230 output << lineDirective( unionDecl );231 232 211 extension( unionDecl ); 233 212 handleAggregate( unionDecl, "union " ); … … 236 215 void CodeGenerator::visit( EnumDecl * enumDecl ) { 237 216 extension( enumDecl ); 238 output << lineDirective ( enumDecl );239 217 output << "enum "; 240 218 genAttributes( enumDecl->get_attributes() ); … … 252 230 ObjectDecl * obj = dynamic_cast< ObjectDecl* >( *i ); 253 231 assert( obj ); 254 output << lineDirective( obj ) <<indent << mangleName( obj );232 output << indent << mangleName( obj ); 255 233 if ( obj->get_init() ) { 256 234 output << " = "; … … 270 248 void CodeGenerator::visit( TypedefDecl * typeDecl ) { 271 249 assertf( ! genC, "Typedefs are removed and substituted in earlier passes." ); 272 output << lineDirective( typeDecl );273 250 output << "typedef "; 274 251 output << genType( typeDecl->get_base(), typeDecl->get_name(), pretty, genC ) << endl; … … 285 262 } // if 286 263 } else { 287 output << typeDecl->genTypeString() << " " << typeDecl->get_name(); 288 if ( typeDecl->get_kind() != TypeDecl::Any && typeDecl->get_sized() ) { 289 output << " | sized(" << typeDecl->get_name() << ")"; 290 } 264 output << typeDecl->typeString() << " " << typeDecl->get_name(); 291 265 if ( ! typeDecl->get_assertions().empty() ) { 292 266 output << " | { "; … … 342 316 } 343 317 344 // 318 //*** Expressions 345 319 void CodeGenerator::visit( ApplicationExpr * applicationExpr ) { 346 320 extension( applicationExpr ); … … 745 719 void CodeGenerator::visit( StmtExpr * stmtExpr ) { 746 720 std::list< Statement * > & stmts = stmtExpr->get_statements()->get_kids(); 747 output << lineDirective( stmtExpr) <<"({" << std::endl;721 output << "({" << std::endl; 748 722 cur_indent += CodeGenerator::tabsize; 749 723 unsigned int numStmts = stmts.size(); 750 724 unsigned int i = 0; 751 725 for ( Statement * stmt : stmts ) { 752 output << lineDirective( stmt ) << indent; 753 output << printLabels( stmt->get_labels() ); 726 output << indent << printLabels( stmt->get_labels() ); 754 727 if ( i+1 == numStmts ) { 755 728 // last statement in a statement expression needs to be handled specially - … … 773 746 } 774 747 775 // 748 //*** Statements 776 749 void CodeGenerator::visit( CompoundStmt * compoundStmt ) { 777 750 std::list<Statement*> ks = compoundStmt->get_kids(); … … 796 769 void CodeGenerator::visit( ExprStmt * exprStmt ) { 797 770 assert( exprStmt ); 798 Expression * expr = exprStmt->get_expr(); 799 if ( genC ) { 800 // cast the top-level expression to void to reduce gcc warnings. 801 expr = new CastExpr( expr ); 802 } 771 // cast the top-level expression to void to reduce gcc warnings. 772 Expression * expr = new CastExpr( exprStmt->get_expr() ); 803 773 expr->accept( *this ); 804 774 output << ";"; … … 837 807 838 808 void CodeGenerator::visit( IfStmt * ifStmt ) { 839 output << lineDirective( ifStmt );840 809 output << "if ( "; 841 810 ifStmt->get_condition()->accept( *this ); … … 851 820 852 821 void CodeGenerator::visit( SwitchStmt * switchStmt ) { 853 output << lineDirective( switchStmt );854 822 output << "switch ( " ; 855 823 switchStmt->get_condition()->accept( *this ); … … 864 832 865 833 void CodeGenerator::visit( CaseStmt * caseStmt ) { 866 output << lineDirective( caseStmt );867 834 output << indent; 868 835 if ( caseStmt->isDefault()) { -
src/CodeGen/Generate.cc
r6250a312 r0f9bef3 22 22 #include "SynTree/Declaration.h" 23 23 #include "CodeGenerator.h" 24 #include "GenType.h" 25 #include "SynTree/SynTree.h" 26 #include "SynTree/Type.h" 27 #include "SynTree/BaseSyntaxNode.h" 28 // #include "Tuples/Tuples.h" 24 #include "Tuples/Tuples.h" 29 25 30 26 using namespace std; … … 43 39 } // for 44 40 } 45 46 void generate( BaseSyntaxNode * node, std::ostream & os ) {47 if ( Type * type = dynamic_cast< Type * >( node ) ) {48 os << CodeGen::genPrettyType( type, "" );49 } else {50 CodeGen::CodeGenerator cgv( os, true, false );51 node->accept( cgv );52 }53 os << std::endl;54 }55 41 } // namespace CodeGen 56 42 -
src/CodeGen/Generate.h
r6250a312 r0f9bef3 25 25 /// Generates code. doIntrinsics determines if intrinsic functions are printed, pretty formats output nicely (e.g., uses unmangled names, etc.), generateC is true when the output must consist only of C code (allows some assertions, etc.) 26 26 void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC = false ); 27 28 /// Generate code for a single node -- helpful for debugging in gdb29 void generate( BaseSyntaxNode * node, std::ostream & os );30 27 } // namespace CodeGen 31 28 -
src/CodeTools/module.mk
r6250a312 r0f9bef3 15 15 ############################################################################### 16 16 17 SRC += CodeTools/DeclStats.cc \ 18 CodeTools/TrackLoc.cc 17 SRC += CodeTools/DeclStats.cc -
src/Common/utility.h
r6250a312 r0f9bef3 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Fri May 5 11:03:00 201713 // Update Count : 3 211 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Dec 14 21:25:25 2016 13 // Update Count : 31 14 14 // 15 15 … … 322 322 std::string filename; 323 323 324 /// Create a new unset CodeLocation. 325 CodeLocation() 324 CodeLocation() 326 325 : linenumber( -1 ) 327 326 , filename("") 328 327 {} 329 328 330 /// Create a new CodeLocation with the given values.331 329 CodeLocation( const char* filename, int lineno ) 332 330 : linenumber( lineno ) 333 331 , filename(filename ? filename : "") 334 332 {} 335 336 bool isSet () const {337 return -1 != linenumber;338 }339 340 bool isUnset () const {341 return !isSet();342 }343 344 void unset () {345 linenumber = -1;346 filename = "";347 }348 349 // Use field access for set.350 333 }; 351 334 352 335 inline std::string to_string( const CodeLocation& location ) { 353 return location. isSet()? location.filename + ":" + std::to_string(location.linenumber) + " " : "";336 return location.linenumber >= 0 ? location.filename + ":" + std::to_string(location.linenumber) + " " : ""; 354 337 } 355 338 #endif // _UTILITY_H -
src/Concurrency/Keywords.cc
r6250a312 r0f9bef3 246 246 //============================================================================================= 247 247 void ConcurrentSueKeyword::visit(StructDecl * decl) { 248 Visitor::visit(decl);249 248 if( decl->get_name() == type_name ) { 250 249 assert( !type_decl ); … … 386 385 //============================================================================================= 387 386 void MutexKeyword::visit(FunctionDecl* decl) { 388 Visitor::visit(decl);389 390 387 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl ); 391 388 if( mutexArgs.empty() ) return; … … 405 402 406 403 void MutexKeyword::visit(StructDecl* decl) { 407 Visitor::visit(decl);408 409 404 if( decl->get_name() == "monitor_desc" ) { 410 405 assert( !monitor_decl ); … … 509 504 //============================================================================================= 510 505 void ThreadStarter::visit(FunctionDecl * decl) { 511 Visitor::visit(decl);512 513 506 if( ! InitTweak::isConstructor(decl->get_name()) ) return; 514 507 -
src/GenPoly/InstantiateGeneric.cc
r6250a312 r0f9bef3 233 233 } else { 234 234 // normalize possibly dtype-static parameter type 235 out.push_back( new TypeExpr{ 235 out.push_back( new TypeExpr{ 236 236 ScrubTyVars::scrubAll( paramType->get_type()->clone() ) } ); 237 237 gt |= genericType::concrete; … … 369 369 DeclMutator::addDeclaration( concDecl ); 370 370 insert( inst, typeSubs, concDecl ); 371 concDecl->acceptMutator( *this ); // recursively instantiate members372 371 } 373 372 StructInstType *newInst = new StructInstType( inst->get_qualifiers(), concDecl->get_name() ); … … 424 423 DeclMutator::addDeclaration( concDecl ); 425 424 insert( inst, typeSubs, concDecl ); 426 concDecl->acceptMutator( *this ); // recursively instantiate members427 425 } 428 426 UnionInstType *newInst = new UnionInstType( inst->get_qualifiers(), concDecl->get_name() ); -
src/GenPoly/PolyMutator.cc
r6250a312 r0f9bef3 50 50 51 51 Statement * PolyMutator::mutateStatement( Statement *stmt ) { 52 // don't want statements from outer CompoundStmts to be added to this CompoundStmt53 ValueGuard< std::list< Statement* > > oldStmtsToAdd( stmtsToAdd );54 ValueGuard< std::list< Statement* > > oldStmtsToAddAfter( stmtsToAddAfter );55 ValueGuard< TypeSubstitution * > oldEnv( env );56 stmtsToAdd.clear();57 stmtsToAddAfter.clear();58 59 52 Statement *newStmt = maybeMutate( stmt, *this ); 60 53 if ( ! stmtsToAdd.empty() || ! stmtsToAddAfter.empty() ) { … … 90 83 91 84 Statement * PolyMutator::mutate(IfStmt *ifStmt) { 92 ifStmt->set_condition( mutateExpression( ifStmt->get_condition() ) );93 85 ifStmt->set_thenPart( mutateStatement( ifStmt->get_thenPart() ) ); 94 86 ifStmt->set_elsePart( mutateStatement( ifStmt->get_elsePart() ) ); 87 ifStmt->set_condition( mutateExpression( ifStmt->get_condition() ) ); 95 88 return ifStmt; 96 89 } 97 90 98 91 Statement * PolyMutator::mutate(WhileStmt *whileStmt) { 92 whileStmt->set_body( mutateStatement( whileStmt->get_body() ) ); 99 93 whileStmt->set_condition( mutateExpression( whileStmt->get_condition() ) ); 100 whileStmt->set_body( mutateStatement( whileStmt->get_body() ) );101 94 return whileStmt; 102 95 } 103 96 104 97 Statement * PolyMutator::mutate(ForStmt *forStmt) { 98 forStmt->set_body( mutateStatement( forStmt->get_body() ) ); 105 99 mutateAll( forStmt->get_initialization(), *this ); 106 100 forStmt->set_condition( mutateExpression( forStmt->get_condition() ) ); 107 101 forStmt->set_increment( mutateExpression( forStmt->get_increment() ) ); 108 forStmt->set_body( mutateStatement( forStmt->get_body() ) );109 102 return forStmt; 110 103 } 111 104 112 105 Statement * PolyMutator::mutate(SwitchStmt *switchStmt) { 106 mutateStatementList( switchStmt->get_statements() ); 113 107 switchStmt->set_condition( mutateExpression( switchStmt->get_condition() ) ); 114 mutateStatementList( switchStmt->get_statements() );115 108 return switchStmt; 116 109 } 117 110 118 111 Statement * PolyMutator::mutate(CaseStmt *caseStmt) { 112 mutateStatementList( caseStmt->get_statements() ); 119 113 caseStmt->set_condition( mutateExpression( caseStmt->get_condition() ) ); 120 mutateStatementList( caseStmt->get_statements() );121 114 return caseStmt; 122 115 } -
src/Makefile.in
r6250a312 r0f9bef3 108 108 CodeGen/driver_cfa_cpp-OperatorTable.$(OBJEXT) \ 109 109 CodeTools/driver_cfa_cpp-DeclStats.$(OBJEXT) \ 110 CodeTools/driver_cfa_cpp-TrackLoc.$(OBJEXT) \111 110 Concurrency/driver_cfa_cpp-Keywords.$(OBJEXT) \ 112 111 Common/driver_cfa_cpp-SemanticError.$(OBJEXT) \ … … 389 388 CodeGen/FixNames.cc CodeGen/FixMain.cc \ 390 389 CodeGen/OperatorTable.cc CodeTools/DeclStats.cc \ 391 CodeTools/TrackLoc.cc Concurrency/Keywords.cc \ 392 Common/SemanticError.cc Common/UniqueName.cc \ 393 Common/DebugMalloc.cc Common/Assert.cc \ 390 Concurrency/Keywords.cc Common/SemanticError.cc \ 391 Common/UniqueName.cc Common/DebugMalloc.cc Common/Assert.cc \ 394 392 ControlStruct/LabelGenerator.cc ControlStruct/LabelFixer.cc \ 395 393 ControlStruct/MLEMutator.cc ControlStruct/Mutate.cc \ … … 547 545 @: > CodeTools/$(DEPDIR)/$(am__dirstamp) 548 546 CodeTools/driver_cfa_cpp-DeclStats.$(OBJEXT): \ 549 CodeTools/$(am__dirstamp) CodeTools/$(DEPDIR)/$(am__dirstamp)550 CodeTools/driver_cfa_cpp-TrackLoc.$(OBJEXT): \551 547 CodeTools/$(am__dirstamp) CodeTools/$(DEPDIR)/$(am__dirstamp) 552 548 Concurrency/$(am__dirstamp): … … 847 843 -rm -f CodeGen/driver_cfa_cpp-OperatorTable.$(OBJEXT) 848 844 -rm -f CodeTools/driver_cfa_cpp-DeclStats.$(OBJEXT) 849 -rm -f CodeTools/driver_cfa_cpp-TrackLoc.$(OBJEXT)850 845 -rm -f Common/driver_cfa_cpp-Assert.$(OBJEXT) 851 846 -rm -f Common/driver_cfa_cpp-DebugMalloc.$(OBJEXT) … … 959 954 @AMDEP_TRUE@@am__include@ @am__quote@CodeGen/$(DEPDIR)/driver_cfa_cpp-OperatorTable.Po@am__quote@ 960 955 @AMDEP_TRUE@@am__include@ @am__quote@CodeTools/$(DEPDIR)/driver_cfa_cpp-DeclStats.Po@am__quote@ 961 @AMDEP_TRUE@@am__include@ @am__quote@CodeTools/$(DEPDIR)/driver_cfa_cpp-TrackLoc.Po@am__quote@962 956 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/driver_cfa_cpp-Assert.Po@am__quote@ 963 957 @AMDEP_TRUE@@am__include@ @am__quote@Common/$(DEPDIR)/driver_cfa_cpp-DebugMalloc.Po@am__quote@ … … 1201 1195 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o CodeTools/driver_cfa_cpp-DeclStats.obj `if test -f 'CodeTools/DeclStats.cc'; then $(CYGPATH_W) 'CodeTools/DeclStats.cc'; else $(CYGPATH_W) '$(srcdir)/CodeTools/DeclStats.cc'; fi` 1202 1196 1203 CodeTools/driver_cfa_cpp-TrackLoc.o: CodeTools/TrackLoc.cc1204 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT CodeTools/driver_cfa_cpp-TrackLoc.o -MD -MP -MF CodeTools/$(DEPDIR)/driver_cfa_cpp-TrackLoc.Tpo -c -o CodeTools/driver_cfa_cpp-TrackLoc.o `test -f 'CodeTools/TrackLoc.cc' || echo '$(srcdir)/'`CodeTools/TrackLoc.cc1205 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) CodeTools/$(DEPDIR)/driver_cfa_cpp-TrackLoc.Tpo CodeTools/$(DEPDIR)/driver_cfa_cpp-TrackLoc.Po1206 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CodeTools/TrackLoc.cc' object='CodeTools/driver_cfa_cpp-TrackLoc.o' libtool=no @AMDEPBACKSLASH@1207 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@1208 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o CodeTools/driver_cfa_cpp-TrackLoc.o `test -f 'CodeTools/TrackLoc.cc' || echo '$(srcdir)/'`CodeTools/TrackLoc.cc1209 1210 CodeTools/driver_cfa_cpp-TrackLoc.obj: CodeTools/TrackLoc.cc1211 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT CodeTools/driver_cfa_cpp-TrackLoc.obj -MD -MP -MF CodeTools/$(DEPDIR)/driver_cfa_cpp-TrackLoc.Tpo -c -o CodeTools/driver_cfa_cpp-TrackLoc.obj `if test -f 'CodeTools/TrackLoc.cc'; then $(CYGPATH_W) 'CodeTools/TrackLoc.cc'; else $(CYGPATH_W) '$(srcdir)/CodeTools/TrackLoc.cc'; fi`1212 @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) CodeTools/$(DEPDIR)/driver_cfa_cpp-TrackLoc.Tpo CodeTools/$(DEPDIR)/driver_cfa_cpp-TrackLoc.Po1213 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CodeTools/TrackLoc.cc' object='CodeTools/driver_cfa_cpp-TrackLoc.obj' libtool=no @AMDEPBACKSLASH@1214 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@1215 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o CodeTools/driver_cfa_cpp-TrackLoc.obj `if test -f 'CodeTools/TrackLoc.cc'; then $(CYGPATH_W) 'CodeTools/TrackLoc.cc'; else $(CYGPATH_W) '$(srcdir)/CodeTools/TrackLoc.cc'; fi`1216 1217 1197 Concurrency/driver_cfa_cpp-Keywords.o: Concurrency/Keywords.cc 1218 1198 @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT Concurrency/driver_cfa_cpp-Keywords.o -MD -MP -MF Concurrency/$(DEPDIR)/driver_cfa_cpp-Keywords.Tpo -c -o Concurrency/driver_cfa_cpp-Keywords.o `test -f 'Concurrency/Keywords.cc' || echo '$(srcdir)/'`Concurrency/Keywords.cc -
src/Parser/parser.yy
r6250a312 r0f9bef3 393 393 | '(' compound_statement ')' // GCC, lambda expression 394 394 { $$ = new ExpressionNode( build_valexpr( $2 ) ); } 395 | primary_expression '{' argument_expression_list '}' // CFA396 {397 Token fn;398 fn.str = new std::string( "?{}" ); // location undefined - use location of '{'?399 $$ = new ExpressionNode( new ConstructorExpr( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) );400 }401 395 ; 402 396 … … 431 425 | '(' type_name_no_function ')' '{' initializer_list comma_opt '}' // C99, compound-literal 432 426 { $$ = new ExpressionNode( build_compoundLiteral( $2, new InitializerNode( $5, true ) ) ); } 433 | '^' primary_expression '{' argument_expression_list '}' // CFA427 | postfix_expression '{' argument_expression_list '}' // CFA 434 428 { 435 429 Token fn; 436 fn.str = new st ring( "^?{}" ); // location undefined437 $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $2 )->set_last( $4) ) );430 fn.str = new std::string( "?{}" ); // location undefined - use location of '{'? 431 $$ = new ExpressionNode( new ConstructorExpr( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) ); 438 432 } 439 433 ; … … 736 730 | exception_statement 737 731 | asm_statement 732 | '^' postfix_expression '{' argument_expression_list '}' ';' // CFA 733 { 734 Token fn; 735 fn.str = new string( "^?{}" ); // location undefined 736 $$ = new StatementNode( build_expr( new ExpressionNode( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $2 )->set_last( $4 ) ) ) ) ); 737 } 738 ; 738 739 739 740 labeled_statement: -
src/ResolvExpr/AlternativeFinder.cc
r6250a312 r0f9bef3 766 766 } // if 767 767 } // for 768 // function may return struct or union value, in which case we need to add alternatives for implicit conversions to each of the anonymous members 769 for ( const Alternative & alt : alternatives ) { 770 addAnonConversions( alt ); 771 } 768 772 769 773 candidates.clear(); … … 771 775 772 776 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( alternatives ) ); 773 774 // function may return struct or union value, in which case we need to add alternatives for implicit775 // conversions to each of the anonymous members, must happen after findMinCost since anon conversions776 // are never the cheapest expression777 for ( const Alternative & alt : alternatives ) {778 addAnonConversions( alt );779 }780 777 781 778 if ( alternatives.empty() && targetType && ! targetType->isVoid() ) { -
src/SymTab/Validate.cc
r6250a312 r0f9bef3 240 240 ReturnTypeFixer::fix( translationUnit ); // must happen before autogen 241 241 acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions 242 acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist243 VerifyCtorDtorAssign::verify( translationUnit ); // must happen before autogen, because autogen examines existing ctor/dtors244 242 Concurrency::applyKeywords( translationUnit ); 245 243 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecayPass 246 244 Concurrency::implementMutexFuncs( translationUnit ); 247 245 Concurrency::implementThreadStarter( translationUnit ); 246 acceptAll( translationUnit, epc ); 248 247 ReturnChecker::checkFunctionReturns( translationUnit ); 249 248 compoundliteral.mutateDeclarationList( translationUnit ); 250 249 acceptAll( translationUnit, pass3 ); 250 VerifyCtorDtorAssign::verify( translationUnit ); 251 251 ArrayLength::computeLength( translationUnit ); 252 252 } … … 817 817 throw SemanticError( "Constructors, destructors, and assignment functions require at least one parameter ", funcDecl ); 818 818 } 819 PointerType * ptrType = dynamic_cast< PointerType * >( params.front()->get_type() ); 820 if ( ! ptrType || ptrType->is_array() ) { 819 if ( ! dynamic_cast< PointerType * >( params.front()->get_type() ) ) { 821 820 throw SemanticError( "First parameter of a constructor, destructor, or assignment function must be a pointer ", funcDecl ); 822 821 } -
src/SynTree/BaseSyntaxNode.h
r6250a312 r0f9bef3 18 18 19 19 #include "Common/utility.h" 20 #include "Visitor.h"21 20 22 21 class BaseSyntaxNode { 23 22 public: 24 23 CodeLocation location; 25 26 virtual void accept( Visitor & v ) = 0; // temporary -- needs to be here so that BaseSyntaxNode is polymorphic and can be dynamic_cast27 24 }; 28 25 -
src/SynTree/Declaration.h
r6250a312 r0f9bef3 204 204 205 205 virtual std::string typeString() const; 206 virtual std::string genTypeString() const;207 206 208 207 virtual TypeDecl *clone() const { return new TypeDecl( *this ); } -
src/SynTree/PointerType.cc
r6250a312 r0f9bef3 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // PointerType.cc -- 7 // PointerType.cc -- 8 8 // 9 9 // Author : Richard C. Bilson … … 38 38 void PointerType::print( std::ostream &os, int indent ) const { 39 39 Type::print( os, indent ); 40 if ( ! is_array() ) { 41 os << "pointer to "; 42 } else { 43 os << "decayed "; 44 if ( isStatic ) { 45 os << "static "; 46 } // if 47 if ( isVarLen ) { 48 os << "variable length array of "; 49 } else if ( dimension ) { 50 os << "array of "; 51 dimension->print( os, indent ); 52 os << " "; 53 } // if 54 } 40 os << "pointer to "; 41 if ( isStatic ) { 42 os << "static "; 43 } // if 44 if ( isVarLen ) { 45 os << "variable length array of "; 46 } else if ( dimension ) { 47 os << "array of "; 48 dimension->print( os, indent ); 49 } // if 55 50 if ( base ) { 56 51 base->print( os, indent ); -
src/SynTree/SynTree.h
r6250a312 r0f9bef3 21 21 #include <map> 22 22 #include <iostream> 23 24 class BaseSyntaxNode;25 23 26 24 class Declaration; -
src/SynTree/Type.h
r6250a312 r0f9bef3 247 247 void set_isStatic( bool newValue ) { isStatic = newValue; } 248 248 249 bool is_array() const { return isStatic || isVarLen || dimension; }250 251 249 virtual PointerType *clone() const { return new PointerType( *this ); } 252 250 virtual void accept( Visitor & v ) { v.visit( this ); } -
src/SynTree/TypeDecl.cc
r6250a312 r0f9bef3 29 29 } 30 30 31 std::string TypeDecl::genTypeString() const {32 static const std::string kindNames[] = { "otype", "dtype", "ftype", "ttype" };33 return kindNames[ kind ];34 }35 36 31 std::ostream & operator<<( std::ostream & os, const TypeDecl::Data & data ) { 37 32 return os << data.kind << ", " << data.isComplete; -
src/SynTree/Visitor.h
r6250a312 r0f9bef3 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Wed May 3 08:58:00201711 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Feb 9 14:23:24 2017 13 13 // Update Count : 10 14 14 // … … 26 26 virtual ~Visitor(); 27 27 public: 28 // visit: Default implementation of all functions visits the children29 // of the given syntax node, but performs no other action.30 31 28 virtual void visit( ObjectDecl *objectDecl ); 32 29 virtual void visit( FunctionDecl *functionDecl ); -
src/benchmark/CorCtxSwitch.c
r6250a312 r0f9bef3 3 3 #include <thread> 4 4 5 #include "bench.h" 5 #include <unistd.h> // sysconf 6 #include <sys/times.h> // times 7 #include <time.h> 6 8 7 coroutine GreatSuspender {}; 9 inline unsigned long long int Time() { 10 timespec ts; 11 clock_gettime( 12 #if defined( __linux__ ) 13 CLOCK_THREAD_CPUTIME_ID, 14 #elif defined( __freebsd__ ) 15 CLOCK_PROF, 16 #elif defined( __solaris__ ) 17 CLOCK_HIGHRES, 18 #else 19 #error uC++ : internal error, unsupported architecture 20 #endif 21 &ts ); 22 return 1000000000LL * ts.tv_sec + ts.tv_nsec; 23 } // Time 24 25 struct GreatSuspender { 26 coroutine_desc __cor; 27 }; 28 29 DECL_COROUTINE(GreatSuspender); 8 30 9 31 void ?{}( GreatSuspender * this ) { … … 24 46 } 25 47 48 #ifndef N 49 #define N 100000000 50 #endif 51 26 52 int main() { 27 53 const unsigned int NoOfTimes = N; -
src/benchmark/Makefile.am
r6250a312 r0f9bef3 44 44 @rm -f ./a.out 45 45 46 sched-int:47 ${CC} ${AM_CFLAGS} ${CFLAGS} ${ccflags} @CFA_FLAGS@ -nodebug -lrt -DN=10000000 SchedInt.c48 @for number in 1 2 3 4 5 6 7 8 9 10; do \49 ./a.out ; \50 done51 @rm -f ./a.out52 53 monitor:54 ${CC} ${AM_CFLAGS} ${CFLAGS} ${ccflags} @CFA_FLAGS@ -nodebug -lrt -DN=10000000 Monitor.c55 @for number in 1 2 3 4 5 6 7 8 9 10; do \56 ./a.out ; \57 done58 @rm -f ./a.out59 60 46 csv-data: 61 47 @${CC} ${AM_CFLAGS} ${CFLAGS} ${ccflags} @CFA_FLAGS@ -nodebug -lrt -quiet -DN=10000000 csv-data.c -
src/benchmark/Makefile.in
r6250a312 r0f9bef3 492 492 @rm -f ./a.out 493 493 494 sched-int:495 ${CC} ${AM_CFLAGS} ${CFLAGS} ${ccflags} @CFA_FLAGS@ -nodebug -lrt -DN=10000000 SchedInt.c496 @for number in 1 2 3 4 5 6 7 8 9 10; do \497 ./a.out ; \498 done499 @rm -f ./a.out500 501 monitor:502 ${CC} ${AM_CFLAGS} ${CFLAGS} ${ccflags} @CFA_FLAGS@ -nodebug -lrt -DN=10000000 Monitor.c503 @for number in 1 2 3 4 5 6 7 8 9 10; do \504 ./a.out ; \505 done506 @rm -f ./a.out507 508 494 csv-data: 509 495 @${CC} ${AM_CFLAGS} ${CFLAGS} ${ccflags} @CFA_FLAGS@ -nodebug -lrt -quiet -DN=10000000 csv-data.c -
src/benchmark/ThrdCtxSwitch.c
r6250a312 r0f9bef3 3 3 #include <thread> 4 4 5 #include "bench.h" 5 #include <unistd.h> // sysconf 6 #include <sys/times.h> // times 7 #include <time.h> 8 9 inline unsigned long long int Time() { 10 timespec ts; 11 clock_gettime( 12 #if defined( __linux__ ) 13 CLOCK_THREAD_CPUTIME_ID, 14 #elif defined( __freebsd__ ) 15 CLOCK_PROF, 16 #elif defined( __solaris__ ) 17 CLOCK_HIGHRES, 18 #else 19 #error uC++ : internal error, unsupported architecture 20 #endif 21 &ts ); 22 return 1000000000LL * ts.tv_sec + ts.tv_nsec; 23 } // Time 24 25 #ifndef N 26 #define N 100000000 27 #endif 6 28 7 29 int main() { -
src/benchmark/bench.c
r6250a312 r0f9bef3 4 4 #include <thread> 5 5 6 #include "bench.h" 6 #include <unistd.h> // sysconf 7 #include <sys/times.h> // times 8 #include <time.h> 9 10 inline unsigned long long int Time() { 11 timespec ts; 12 clock_gettime( 13 #if defined( __linux__ ) 14 CLOCK_THREAD_CPUTIME_ID, 15 #elif defined( __freebsd__ ) 16 CLOCK_PROF, 17 #elif defined( __solaris__ ) 18 CLOCK_HIGHRES, 19 #else 20 #error uC++ : internal error, unsupported architecture 21 #endif 22 &ts ); 23 return 1000000000LL * ts.tv_sec + ts.tv_nsec; 24 } // Time 7 25 8 26 //======================================= … … 68 86 //======================================= 69 87 70 coroutine CoroutineDummy {}; 88 struct CoroutineDummy { coroutine_desc __cor; }; 89 DECL_COROUTINE(CoroutineDummy); 71 90 void main(CoroutineDummy * this) {} 72 91 … … 98 117 } 99 118 100 coroutineCoroutineResume {119 struct CoroutineResume { 101 120 int N; 121 coroutine_desc __cor; 102 122 }; 123 124 DECL_COROUTINE(CoroutineResume); 103 125 104 126 void ?{}(CoroutineResume* this, int N) { … … 128 150 //======================================= 129 151 130 thread ThreadDummy {}; 152 struct ThreadDummy { thread_desc __thrd; }; 153 DECL_THREAD(ThreadDummy); 131 154 void main(ThreadDummy * this) {} 132 155 … … 154 177 } 155 178 156 threadContextSwitch {179 struct ContextSwitch { 157 180 int N; 158 181 long long result; 182 thread_desc __thrd; 159 183 }; 184 185 DECL_THREAD(ContextSwitch); 160 186 161 187 void main(ContextSwitch * this) { … … 215 241 DynamicTaskCreateDelete( NoOfTimes ); 216 242 { 217 ContextSwitchdummy = { (int)NoOfTimes }; // context switch243 scoped(ContextSwitch) dummy = { (int)NoOfTimes }; // context switch 218 244 } 219 245 sout | "\t" | endl; -
src/benchmark/csv-data.c
r6250a312 r0f9bef3 1 1 #include <fstream> 2 #include <monitor>3 2 #include <stdlib> 4 3 #include <thread> 5 4 6 #include "bench.h" 5 extern "C" { 6 #include <unistd.h> // sysconf 7 #include <sys/times.h> // times 8 #include <time.h> 9 } 7 10 8 coroutine GreatSuspender {}; 11 inline unsigned long long int Time() { 12 timespec ts; 13 clock_gettime( 14 #if defined( __linux__ ) 15 CLOCK_THREAD_CPUTIME_ID, 16 #elif defined( __freebsd__ ) 17 CLOCK_PROF, 18 #elif defined( __solaris__ ) 19 CLOCK_HIGHRES, 20 #else 21 #error uC++ : internal error, unsupported architecture 22 #endif 23 &ts ); 24 return 1000000000LL * ts.tv_sec + ts.tv_nsec; 25 } // Time 26 27 struct GreatSuspender { 28 coroutine_desc __cor; 29 }; 30 31 DECL_COROUTINE(GreatSuspender); 9 32 10 33 void ?{}( GreatSuspender * this ) { … … 29 52 #endif 30 53 31 //----------------------------------------------------------------------------- 32 // coroutine context switch 54 55 33 56 long long int measure_coroutine() { 34 57 const unsigned int NoOfTimes = N; … … 48 71 } 49 72 50 //-----------------------------------------------------------------------------51 // thread context switch52 73 long long int measure_thread() { 53 74 const unsigned int NoOfTimes = N; … … 63 84 } 64 85 65 //-----------------------------------------------------------------------------66 // single monitor entry67 monitor mon_t {};68 void dummy( mon_t * mutex m ) {}69 70 long long int measure_1_monitor_entry() {71 const unsigned int NoOfTimes = N;72 long long int StartTime, EndTime;73 mon_t mon;74 75 StartTime = Time();76 for ( volatile unsigned int i = 0; i < NoOfTimes; i += 1 ) {77 dummy( &mon );78 }79 EndTime = Time();80 81 return ( EndTime - StartTime ) / NoOfTimes;82 }83 84 //-----------------------------------------------------------------------------85 // multi monitor entry86 void dummy( mon_t * mutex m1, mon_t * mutex m2 ) {}87 88 long long int measure_2_monitor_entry() {89 const unsigned int NoOfTimes = N;90 long long int StartTime, EndTime;91 mon_t mon1, mon2;92 93 StartTime = Time();94 for ( volatile unsigned int i = 0; i < NoOfTimes; i += 1 ) {95 dummy( &mon1, &mon2 );96 }97 EndTime = Time();98 99 return ( EndTime - StartTime ) / NoOfTimes;100 }101 102 //-----------------------------------------------------------------------------103 // single internal sched entry104 mon_t mon1;105 106 condition cond1a;107 condition cond1b;108 109 thread thrd1a { long long int * out; };110 thread thrd1b {};111 112 void ?{}( thrd1a * this, long long int * out ) {113 this->out = out;114 }115 116 void side1A( mon_t * mutex a, long long int * out ) {117 long long int StartTime, EndTime;118 119 StartTime = Time();120 for( int i = 0;; i++ ) {121 signal(&cond1a);122 if( i > N ) break;123 wait(&cond1b);124 }125 EndTime = Time();126 127 *out = ( EndTime - StartTime ) / N;128 }129 130 void side1B( mon_t * mutex a ) {131 for( int i = 0;; i++ ) {132 signal(&cond1b);133 if( i > N ) break;134 wait(&cond1a);135 }136 }137 138 void main( thrd1a * this ) { side1A( &mon1, this->out ); }139 void main( thrd1b * this ) { side1B( &mon1 ); }140 141 long long int measure_1_sched_int() {142 long long int t;143 {144 thrd1a a = { &t };145 thrd1b b;146 }147 return t;148 }149 150 //-----------------------------------------------------------------------------151 // multi internal sched entry152 mon_t mon2;153 154 condition cond2a;155 condition cond2b;156 157 thread thrd2a { long long int * out; };158 thread thrd2b {};159 160 void ?{}( thrd2a * this, long long int * out ) {161 this->out = out;162 }163 164 void side2A( mon_t * mutex a, mon_t * mutex b, long long int * out ) {165 long long int StartTime, EndTime;166 167 StartTime = Time();168 for( int i = 0;; i++ ) {169 signal(&cond2a);170 if( i > N ) break;171 wait(&cond2b);172 }173 EndTime = Time();174 175 *out = ( EndTime - StartTime ) / N;176 }177 178 void side2B( mon_t * mutex a, mon_t * mutex b ) {179 for( int i = 0;; i++ ) {180 signal(&cond2b);181 if( i > N ) break;182 wait(&cond2a);183 }184 }185 186 void main( thrd2a * this ) { side2A( &mon1, &mon2, this->out ); }187 void main( thrd2b * this ) { side2B( &mon1, &mon2 ); }188 189 long long int measure_2_sched_int() {190 long long int t;191 {192 thrd2a a = { &t };193 thrd2b b;194 }195 return t;196 }197 198 //-----------------------------------------------------------------------------199 // main loop200 86 int main() 201 87 { 202 sout | time(NULL) | ','; 203 sout | measure_coroutine() | ','; 204 sout | measure_thread() | ','; 205 sout | measure_1_monitor_entry() | ','; 206 sout | measure_2_monitor_entry() | ','; 207 sout | measure_1_sched_int() | ','; 208 sout | measure_2_sched_int() | endl; 88 sout | time(NULL) | ',' | measure_coroutine() | ',' | measure_thread() | endl; 209 89 } -
src/libcfa/concurrency/monitor
r6250a312 r0f9bef3 81 81 } 82 82 83 static inline void ^?{}( condition * this ) {84 free( this->monitors );85 }86 87 83 void wait( condition * this ); 88 84 void signal( condition * this ); -
src/libcfa/concurrency/monitor.c
r6250a312 r0f9bef3 17 17 #include "monitor" 18 18 19 #include <stdlib>20 21 19 #include "kernel_private.h" 22 20 #include "libhdr.h" … … 132 130 this_thread()->current_monitors = this->prev_mntrs; 133 131 this_thread()->current_monitor_count = this->prev_count; 134 }135 136 void debug_break() __attribute__(( noinline ))137 {138 139 132 } 140 133 … … 178 171 179 172 //Find the next thread(s) to run 180 unsigned short thread_count = 0;173 unsigned short thread_count = count; 181 174 thread_desc * threads[ count ]; 182 for(int i = 0; i < count; i++) {183 threads[i] = 0;184 }185 186 debug_break();187 175 188 176 for( int i = 0; i < count; i++) { 189 177 thread_desc * new_owner = next_thread( this->monitors[i] ); 190 thread_count = insert_unique( threads, thread_count, new_owner ); 191 } 192 193 debug_break(); 178 thread_count = insert_unique( threads, i, new_owner ); 179 } 194 180 195 181 LIB_DEBUG_PRINT_SAFE("Will unblock: "); … … 353 339 LIB_DEBUG_PRINT_SAFE("Branding\n"); 354 340 assertf( thrd->current_monitors != NULL, "No current monitor to brand condition", thrd->current_monitors ); 341 this->monitors = thrd->current_monitors; 355 342 this->monitor_count = thrd->current_monitor_count; 356 357 this->monitors = malloc( this->monitor_count * sizeof( *this->monitors ) );358 for( int i = 0; i < this->monitor_count; i++ ) {359 this->monitors[i] = thrd->current_monitors[i];360 }361 343 } 362 344 } 363 345 364 346 static inline unsigned short insert_unique( thread_desc ** thrds, unsigned short end, thread_desc * val ) { 365 if( !val ) return end; 366 367 for(int i = 0; i <= end; i++) { 347 for(int i = 0; i < end; i++) { 368 348 if( thrds[i] == val ) return end; 369 349 } -
src/libcfa/concurrency/thread.c
r6250a312 r0f9bef3 40 40 this->next = NULL; 41 41 42 this->current_monitors = &this->mon;43 this->current_monitor_count = 1;42 this->current_monitors = NULL; 43 this->current_monitor_count = 0; 44 44 } 45 45 -
src/libcfa/rational
r6250a312 r0f9bef3 12 12 // Created On : Wed Apr 6 17:56:25 2016 13 13 // Last Modified By : Peter A. Buhr 14 // Last Modified On : Mon May 1 08:25:06 201715 // Update Count : 3314 // Last Modified On : Wed May 4 14:11:45 2016 15 // Update Count : 16 16 16 // 17 18 17 #ifndef RATIONAL_H 19 18 #define RATIONAL_H … … 22 21 23 22 // implementation 24 typedef long int RationalImpl;25 23 struct Rational { 26 RationalImplnumerator, denominator; // invariant: denominator > 024 long int numerator, denominator; // invariant: denominator > 0 27 25 }; // Rational 28 26 … … 33 31 // constructors 34 32 void ?{}( Rational * r ); 35 void ?{}( Rational * r, RationalImpln );36 void ?{}( Rational * r, RationalImpl n, RationalImpld );33 void ?{}( Rational * r, long int n ); 34 void ?{}( Rational * r, long int n, long int d ); 37 35 38 // getter for numerator/denominator 39 RationalImpl numerator( Rational r ); 40 RationalImpl denominator( Rational r ); 41 [ RationalImpl, RationalImpl ] ?=?( * [ RationalImpl, RationalImpl ] dest, Rational src ); 42 // setter for numerator/denominator 43 RationalImpl numerator( Rational r, RationalImpl n ); 44 RationalImpl denominator( Rational r, RationalImpl d ); 36 // getter/setter for numerator/denominator 37 long int numerator( Rational r ); 38 long int numerator( Rational r, long int n ); 39 long int denominator( Rational r ); 40 long int denominator( Rational r, long int d ); 45 41 46 42 // comparison … … 61 57 // conversion 62 58 double widen( Rational r ); 63 Rational narrow( double f, RationalImplmd );59 Rational narrow( double f, long int md ); 64 60 65 61 // I/O -
src/libcfa/rational.c
r6250a312 r0f9bef3 10 10 // Created On : Wed Apr 6 17:54:28 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Apr 27 17:05:06 201713 // Update Count : 5112 // Last Modified On : Sat Jul 9 11:18:04 2016 13 // Update Count : 40 14 14 // 15 15 … … 30 30 // Calculate greatest common denominator of two numbers, the first of which may be negative. Used to reduce rationals. 31 31 // alternative: https://en.wikipedia.org/wiki/Binary_GCD_algorithm 32 static RationalImpl gcd( RationalImpl a, RationalImplb ) {32 static long int gcd( long int a, long int b ) { 33 33 for ( ;; ) { // Euclid's algorithm 34 RationalImplr = a % b;34 long int r = a % b; 35 35 if ( r == 0 ) break; 36 36 a = b; … … 40 40 } // gcd 41 41 42 static RationalImpl simplify( RationalImpl *n, RationalImpl*d ) {42 static long int simplify( long int *n, long int *d ) { 43 43 if ( *d == 0 ) { 44 44 serr | "Invalid rational number construction: denominator cannot be equal to 0." | endl; … … 56 56 } // rational 57 57 58 void ?{}( Rational * r, RationalImpln ) {58 void ?{}( Rational * r, long int n ) { 59 59 r{ n, 1 }; 60 60 } // rational 61 61 62 void ?{}( Rational * r, RationalImpl n, RationalImpld ) {63 RationalImpl t = simplify( &n, &d );// simplify62 void ?{}( Rational * r, long int n, long int d ) { 63 long int t = simplify( &n, &d ); // simplify 64 64 r->numerator = n / t; 65 65 r->denominator = d / t; … … 67 67 68 68 69 // getter for numerator/denominator70 71 RationalImplnumerator( Rational r ) {69 // getter/setter for numerator/denominator 70 71 long int numerator( Rational r ) { 72 72 return r.numerator; 73 73 } // numerator 74 74 75 RationalImpl denominator( Rational r ) { 76 return r.denominator; 77 } // denominator 78 79 [ RationalImpl, RationalImpl ] ?=?( * [ RationalImpl, RationalImpl ] dest, Rational src ) { 80 return *dest = src.[ numerator, denominator ]; 81 } 82 83 // setter for numerator/denominator 84 85 RationalImpl numerator( Rational r, RationalImpl n ) { 86 RationalImpl prev = r.numerator; 87 RationalImpl t = gcd( abs( n ), r.denominator ); // simplify 75 long int numerator( Rational r, long int n ) { 76 long int prev = r.numerator; 77 long int t = gcd( abs( n ), r.denominator ); // simplify 88 78 r.numerator = n / t; 89 79 r.denominator = r.denominator / t; … … 91 81 } // numerator 92 82 93 RationalImpl denominator( Rational r, RationalImpl d ) { 94 RationalImpl prev = r.denominator; 95 RationalImpl t = simplify( &r.numerator, &d ); // simplify 83 long int denominator( Rational r ) { 84 return r.denominator; 85 } // denominator 86 87 long int denominator( Rational r, long int d ) { 88 long int prev = r.denominator; 89 long int t = simplify( &r.numerator, &d ); // simplify 96 90 r.numerator = r.numerator / t; 97 91 r.denominator = d / t; … … 176 170 177 171 // http://www.ics.uci.edu/~eppstein/numth/frap.c 178 Rational narrow( double f, RationalImplmd ) {172 Rational narrow( double f, long int md ) { 179 173 if ( md <= 1 ) { // maximum fractional digits too small? 180 174 return (Rational){ f, 1}; // truncate fraction … … 182 176 183 177 // continued fraction coefficients 184 RationalImplm00 = 1, m11 = 1, m01 = 0, m10 = 0;185 RationalImplai, t;178 long int m00 = 1, m11 = 1, m01 = 0, m10 = 0; 179 long int ai, t; 186 180 187 181 // find terms until denom gets too big 188 182 for ( ;; ) { 189 ai = ( RationalImpl)f;183 ai = (long int)f; 190 184 if ( ! (m10 * ai + m11 <= md) ) break; 191 185 t = m00 * ai + m01; … … 208 202 forall( dtype istype | istream( istype ) ) 209 203 istype * ?|?( istype *is, Rational *r ) { 210 RationalImplt;204 long int t; 211 205 is | &(r->numerator) | &(r->denominator); 212 206 t = simplify( &(r->numerator), &(r->denominator) ); -
src/main.cc
r6250a312 r0f9bef3 37 37 #include "CodeGen/FixMain.h" 38 38 #include "CodeTools/DeclStats.h" 39 #include "CodeTools/TrackLoc.h"40 39 #include "ControlStruct/Mutate.h" 41 40 #include "SymTab/Validate.h" … … 309 308 } // if 310 309 311 CodeTools::fillLocations( translationUnit );312 310 CodeGen::generate( translationUnit, *output, ! noprotop, prettycodegenp, true ); 313 311 -
src/tests/Makefile.am
r6250a312 r0f9bef3 22 22 concurrent=yes 23 23 quick_test+= coroutine thread monitor 24 concurrent_test=coroutine thread monitor multi-monitor sched-int -disjoint sched-int-barge sched-int-wait sched-ext sched-ext-multipreempt24 concurrent_test=coroutine thread monitor multi-monitor sched-int sched-ext preempt 25 25 else 26 26 concurrent=no -
src/tests/Makefile.in
r6250a312 r0f9bef3 230 230 @BUILD_CONCURRENCY_TRUE@concurrent = yes 231 231 @BUILD_CONCURRENCY_FALSE@concurrent_test = 232 @BUILD_CONCURRENCY_TRUE@concurrent_test = coroutine thread monitor multi-monitor sched-int-disjoint sched-int-barge sched-int-wait sched-ext sched-ext-multi preempt 232 @BUILD_CONCURRENCY_TRUE@concurrent_test = coroutine thread monitor multi-monitor sched-int sched-ext preempt 233 TEST_FLAGS = $(if $(test), 2> .err/${@}.log, ) 233 234 234 235 # applies to both programs 235 236 EXTRA_FLAGS = 236 237 BUILD_FLAGS = -g -Wall -Wno-unused-function @CFA_FLAGS@ ${EXTRA_FLAGS} 237 TEST_FLAGS = $(if $(test), 2> .err/${@}.log, )238 238 fstream_test_SOURCES = fstream_test.c 239 239 vector_test_SOURCES = vector/vector_int.c vector/array.c vector/vector_test.c -
src/tests/rational.c
r6250a312 r0f9bef3 10 10 // Created On : Mon Mar 28 08:43:12 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue May 2 22:11:05 201713 // Update Count : 4112 // Last Modified On : Tue Jul 5 18:29:37 2016 13 // Update Count : 25 14 14 // 15 15 … … 36 36 b = (Rational){ -3, 2 }; 37 37 sout | a | b | endl; 38 // sout | a == 1 | endl; // FIX ME 38 sout | a == 1 | endl; 39 39 sout | a != b | endl; 40 40 sout | a < b | endl; … … 61 61 sout | narrow( 3.14159265358979, 256 ) | endl; 62 62 63 sout | "decompose" | endl;64 RationalImpl n, d;65 // [n, d] = a;66 // sout | a | n | d | endl;67 68 sout | "more tests" | endl;69 63 Rational x = { 1, 2 }, y = { 2 }; 70 64 sout | x - y | endl;
Note: See TracChangeset
for help on using the changeset viewer.