Changeset 6250a312 for doc/rob_thesis/ctordtor.tex
- Timestamp:
- May 10, 2017, 5:00:47 PM (7 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- 8514fe19, dbfb35d
- Parents:
- 0f9bef3 (diff), 29cf9c8 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/rob_thesis/ctordtor.tex
r0f9bef3 r6250a312 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 provide a garbage collector. 9 As well, \CFA is not an object-oriented programming language, \ie, structures cannot have routine members. 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. 10 11 Nevertheless, one important goal is to reduce programming complexity and increase safety. 11 12 To that end, \CFA provides support for implicit pre/post-execution of routines for objects, via constructors and destructors. … … 32 33 The key difference between assignment and initialization being that assignment occurs on a live object (\ie, an object that contains data). 33 34 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. 34 Use of uninitialized variables yields undefined behaviour , which is a common source of errors in C programs.35 Use of uninitialized variables yields undefined behaviour \cite[p.~558]{C11}, which is a common source of errors in C programs. 35 36 36 37 Initialization of a declaration is strictly optional, permitting uninitialized variables to exist. … … 70 71 int x2 = opaque_get(x, 2); 71 72 \end{cfacode} 72 This pattern is cumbersome to use since every access becomes a function call .73 This pattern is cumbersome to use since every access becomes a function call, requiring awkward syntax and a performance cost. 73 74 While useful in some situations, this compromise is too restrictive. 74 75 Furthermore, even with this idiom it is easy to make mistakes, such as forgetting to destroy an object or destroying it multiple times. 75 76 76 77 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. 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 impossibleto forget to initialize such objects, as long as all constructors perform some sensible form of initialization.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. 79 80 80 81 In \CFA, a constructor is a function with the name @?{}@. … … 114 115 In other words, a default constructor is a constructor that takes a single argument: the @this@ parameter. 115 116 116 In \CFA, a destructor is a function much like a constructor, except that its name is \lstinline!^?{}! and it takes only one argument.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. 117 118 A destructor for the @Array@ type can be defined as: 118 119 \begin{cfacode} … … 135 136 On line 2, @z@ is initialized with the value of @x@, while on line 3, @y@ is assigned the value of @x@. 136 137 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. 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. 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. 138 140 139 141 \begin{cfacode}[emph={other}, emphstyle=\color{red}] … … 151 153 } 152 154 \end{cfacode} 153 The two functions above handle the se 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.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. 155 157 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. 156 160 The four functions (default constructor, destructor, copy constructor, and assignment operator) are special in that they safely control the state of most objects. 157 161 … … 216 220 A * y = malloc(); // copy construct: ?{}(&y, malloc()) 217 221 222 ^?{}(&x); // explicit destroy x, in different order 218 223 ?{}(&x); // explicit construct x, second construction 224 ^?{}(y); // explicit destroy y 219 225 ?{}(y, x); // explit construct y from x, second construction 220 ^?{}(&x); // explicit destroy x, in different order221 ^?{}(y); // explicit destroy y222 226 223 227 // implicit ^?{}(&y); … … 279 283 \end{cfacode} 280 284 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 281 288 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. 282 289 \begin{cfacode} … … 300 307 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. 301 308 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.309 While it is possible to use operator syntax with destructors, destructors invalidate their argument, thus operator syntax with destructors is void-typed expression. 303 310 304 311 \subsection{Function Generation} … … 308 315 If the translator can expect these functions to exist, then it can unconditionally attempt to resolve them. 309 316 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. 310 318 311 319 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 type 326 void f() { 327 int x; // initialized to 0 328 int * p; // initialized to 0 329 } 330 \end{cfacode} 331 %%%%%%%%%%%%%%%%%%%%%%%%%% line width %%%%%%%%%%%%%%%%%%%%%%%%%% 312 332 313 333 There are several options for user-defined types: structures, unions, and enumerations. 314 334 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. 315 335 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. 316 338 317 339 The generated functions for enumerations are the simplest. … … 338 360 } 339 361 \end{cfacode} 340 In the future, \CFA will introduce strongly-typed enumerations, like those in \CC .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. 341 363 The existing generated routines are sufficient to express this restriction, since they are currently set up to take in values of that enumeration type. 342 364 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@. … … 492 514 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. 493 515 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. 494 It is recommended that most objects be managed by sensible constructors and destructors, except where absolutely necessary .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. 495 517 496 518 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. … … 545 567 \end{cfacode} 546 568 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. 547 571 \begin{cfacode} 548 572 void ?{}(A * a) { … … 556 580 } 557 581 582 void ?{}(A * a, int x) { 583 // object forwarded to another constructor, 584 // does not implicitly construct any members 585 (&a){}; 586 } 587 558 588 void ^?{}(A * a) { 559 589 ^(&a->x){}; // explicit destructor call 560 590 } // z, y, w implicitly destructed, in this order 561 591 \end{cfacode} 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. 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. 565 593 566 594 Despite great effort, some forms of C syntax do not work well with constructors in \CFA. … … 619 647 The body of @A@ has been omitted, since only the constructor interfaces are important. 620 648 621 It should be noted that unmanaged objects can still make use of designations and nested initializers in \CFA.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. 622 650 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 literal 661 }; 662 \end{cfacode} 663 %%%%%%%%%%%%%%%%%%%%%%%%%% line width %%%%%%%%%%%%%%%%%%%%%%%%%% 623 664 624 665 \subsection{Implicit Destructors} … … 744 785 \end{cfacode} 745 786 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 argument 795 } 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 746 801 \subsection{Implicit Copy Construction} 747 802 \label{s:implicit_copy_construction} … … 750 805 Exempt from these rules are intrinsic and built-in functions. 751 806 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. 752 That is, since the parameter is not marked as an unmanaged object using \ateq, it is becopy 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.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. 753 808 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. 754 809 \begin{cfacode} 755 struct A ;810 struct A { ... }; 756 811 void ?{}(A *); 757 812 void ?{}(A *, A); … … 810 865 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. 811 866 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 812 872 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. 813 873 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. … … 908 968 \subsection{Array Initialization} 909 969 Arrays are a special case in the C type-system. 910 C arrays do not carry around their size, making it impossible to write a standalone \CFA function that constructs or destructs an arraywhile maintaining the standard interface for constructors and destructors.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. 911 971 Instead, \CFA defines the initialization and destruction of an array recursively. 912 972 That is, when an array is defined, each of its elements is constructed in order from element 0 up to element $n-1$. … … 1147 1207 \end{cfacode} 1148 1208 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 1149 1215 \subsection{Polymorphism} 1150 1216 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@. … … 1172 1238 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. 1173 1239 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.
Note: See TracChangeset
for help on using the changeset viewer.