Changeset ba2e8f0
- Timestamp:
- Aug 24, 2021, 4:41:53 PM (4 years ago)
- Branches:
- ADT, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, pthread-emulation, qualifiedEnum
- Children:
- e8bad5c8
- Parents:
- 9cd37d9
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/andrew_beach_MMath/implement.tex
r9cd37d9 rba2e8f0 20 20 21 21 \subsection{Virtual Type} 22 Virtual types only have one change to their structure: the addition of a 23 pointer to the virtual table, which is called the \emph{virtual-table pointer}. 24 Internally, the field is called \snake{virtual_table}. 25 The field is fixed after construction. It is always the first field in the 22 A virtual type~(see \autoref{s:virtuals}) has a pointer to a virtual table, 23 called the \emph{virtual-table pointer}, 24 which binds each instance of a virtual type to a virtual table. 25 Internally, the field is called \snake{virtual_table} 26 and is fixed after construction. 27 This pointer is also the table's id and how the system accesses the 28 virtual table and the virtual members there. 29 It is always the first field in the 26 30 structure so that its location is always known. 27 \todo{Talk about constructors for virtual types (after they are working).} 28 29 The virtual table pointer binds an instance of a virtual type 30 to a virtual table. 31 The pointer is also the table's id and how the system accesses the 32 virtual table and the virtual members there. 31 32 % We have no special rules for these constructors. 33 Virtual table pointers are passed to the constructors of virtual types 34 as part of field-by-field construction. 33 35 34 36 \subsection{Type Id} 35 37 Every virtual type has a unique id. 36 Type ids can be compared for equality, 37 which checks if the types reperented are the same, 38 or used to access the type's type information. 38 These are used in type equality, to check if the representation of two values 39 are the same, and to access the type's type information. 40 This uniqueness means across a program composed of multiple translation 41 units (TU), not uniqueness across all programs or even across multiple 42 processes on the same machine. 43 44 Our approach for program uniqueness is using a static declaration for each 45 type id, where the run-time storage address of that variable is guaranteed to 46 be unique during program execution. 47 The type id storage can also be used for other purposes, 48 and is used for type information. 49 50 The problem is that a type id may appear in multiple TUs that compose a 51 program (see \autoref{ss:VirtualTable}); so the initial solution would seem 52 to be make it external in each translation unit. Honever, the type id must 53 have a declaration in (exactly) one of the TUs to create the storage. 54 No other declaration related to the virtual type has this property, so doing 55 this through standard C declarations would require the user to do it manually. 56 57 Instead the linker is used to handle this problem. 58 % I did not base anything off of C++17; they are solving the same problem. 59 A new feature has been added to \CFA for this purpose, the special attribute 60 \snake{cfa_linkonce}, which uses the special section @.gnu.linkonce@. 61 When used as a prefix (\eg @.gnu.linkonce.example@) the linker does 62 not combine these sections, but instead discards all but one with the same 63 full name. 64 65 So each type id must be given a unique section name with the linkonce 66 prefix. Luckily \CFA already has a way to get unique names, the name mangler. 67 For example, this could be written directly in \CFA: 68 \begin{cfa} 69 __attribute__((cfa_linkonce)) void f() {} 70 \end{cfa} 71 This is translated to: 72 \begin{cfa} 73 __attribute__((section(".gnu.linkonce._X1fFv___1"))) void _X1fFv___1() {} 74 \end{cfa} 75 This is done internally to access the name manglers. 76 This attribute is useful for other purposes, any other place a unique 77 instance required, and should eventually be made part of a public and 78 stable feature in \CFA. 79 80 \subsection{Type Information} 81 82 There is data stored at the type id's declaration, the type information. 39 83 The type information currently is only the parent's type id or, if the 40 84 type has no parent, the null pointer. 41 42 The id's are implemented as pointers to the type's type information instance.43 Dereferencing the pointer gets the type information.44 85 The ancestors of a virtual type are found by traversing type ids through 45 86 the type information. 46 The information pushes the issue of creating a unique value (for 47 the type id) to the problem of creating a unique instance (for type 48 information), which the linker can solve. 49 50 The advanced linker support is used here to avoid having to create 51 a new declaration to attach this data to. 52 With C/\CFA's header/implementation file divide for something to appear 53 exactly once it must come from a declaration that appears in exactly one 54 implementation file; the declarations in header files may exist only once 55 they can be included in many different translation units. 56 Therefore, structure's declaration will not work. 57 Neither will attaching the type information to the virtual table -- although 58 a vtable declarations are in implemention files they are not unique, see 59 \autoref{ss:VirtualTable}. 60 Instead the same type information is generated multiple times and then 61 the new attribute \snake{cfa_linkone} is used to removed duplicates. 87 An example using helper macros looks like: 88 \begin{cfa} 89 struct INFO_TYPE(TYPE) { 90 INFO_TYPE(PARENT) const * parent; 91 }; 92 93 __attribute__((cfa_linkonce)) 94 INFO_TYPE(TYPE) const INFO_NAME(TYPE) = { 95 &INFO_NAME(PARENT), 96 }; 97 \end{cfa} 62 98 63 99 Type information is constructed as follows: 64 100 \begin{enumerate} 65 101 \item 66 Use the type's name to generate a name for the type information structure .67 This is saved so it maybe reused.102 Use the type's name to generate a name for the type information structure, 103 which is saved so it can be reused. 68 104 \item 69 105 Generate a new structure definition to store the type 70 106 information. The layout is the same in each case, just the parent's type id, 71 107 but the types used change from instance to instance. 72 The generated name is used for both this structure and, if rel ivant, the108 The generated name is used for both this structure and, if relevant, the 73 109 parent pointer. 74 110 If the virtual type is polymorphic then the type information structure is 75 111 polymorphic as well, with the same polymorphic arguments. 76 112 \item 77 A sep erate name for instances is generated from the type's name.113 A separate name for instances is generated from the type's name. 78 114 \item 79 The definition is generated and initiali sed.115 The definition is generated and initialized. 80 116 The parent id is set to the null pointer or to the address of the parent's 81 117 type information instance. Name resolution handles the rest. 82 118 \item 83 119 \CFA's name mangler does its regular name mangling encoding the type of 84 the declaration into the instance name. This gives a completely unique name 120 the declaration into the instance name. 121 This process gives a completely unique name 85 122 including different instances of the same polymorphic type. 86 123 \end{enumerate} 87 \todo{The list is making me reali se, some of this isn't ordered.}124 \todo{The list is making me realize, some of this isn't ordered.} 88 125 89 126 Writing that code manually, with helper macros for the early name mangling, … … 100 137 \end{cfa} 101 138 139 \begin{comment} 102 140 \subsubsection{\lstinline{cfa\_linkonce} Attribute} 103 % I just reali sed: This is an extension of the inline keyword.141 % I just realized: This is an extension of the inline keyword. 104 142 % An extension of C's at least, it is very similar to C++'s. 105 143 Another feature added to \CFA is a new attribute: \texttt{cfa\_linkonce}. … … 126 164 everything that comes after the special prefix, then only one is used 127 165 and the other is discarded. 166 \end{comment} 128 167 129 168 \subsection{Virtual Table} … … 176 215 type's alignment, is set using an @alignof@ expression. 177 216 178 \subs ubsection{Concurrency Integration}217 \subsection{Concurrency Integration} 179 218 Coroutines and threads need instances of @CoroutineCancelled@ and 180 219 @ThreadCancelled@ respectively to use all of their functionality. When a new … … 183 222 at the definition of the main function. 184 223 185 This is showned through code re-writing in 186 \autoref{f:ConcurrencyTypeTransformation} and 187 \autoref{f:ConcurrencyMainTransformation}. 188 In both cases the original declaration is not modified, 224 These transformations are shown through code re-writing in 225 \autoref{f:CoroutineTypeTransformation} and 226 \autoref{f:CoroutineMainTransformation}. 227 Threads use the same pattern, with some names and types changed. 228 In both cases, the original declaration is not modified, 189 229 only new ones are added. 190 230 191 \begin{figure} 231 \begin{figure}[htb] 192 232 \begin{cfa} 193 233 coroutine Example { … … 207 247 extern CoroutineCancelled_vtable & _default_vtable; 208 248 \end{cfa} 209 \caption{Co ncurrencyType Transformation}210 \label{f:Co ncurrencyTypeTransformation}249 \caption{Coroutine Type Transformation} 250 \label{f:CoroutineTypeTransformation} 211 251 \end{figure} 212 252 … … 229 269 &_default_vtable_object_declaration; 230 270 \end{cfa} 231 \caption{Co ncurrencyMain Transformation}232 \label{f:Co ncurrencyMainTransformation}271 \caption{Coroutine Main Transformation} 272 \label{f:CoroutineMainTransformation} 233 273 \end{figure} 234 274 … … 242 282 \begin{cfa} 243 283 void * __cfa__virtual_cast( 244 struct __cfavir_type_td parent, 245 struct __cfavir_type_id const * child ); 246 \end{cfa} 247 The type id of target type of the virtual cast is passed in as @parent@ and 284 struct __cfavir_type_id * parent, 285 struct __cfavir_type_id * const * child ); 286 \end{cfa} 287 The type id for the target type of the virtual cast is passed in as 288 @parent@ and 248 289 the cast target is passed in as @child@. 249 250 For generated C code wraps both arguments and the result with type casts. 290 The generated C code wraps both arguments and the result with type casts. 251 291 There is also an internal check inside the compiler to make sure that the 252 292 target type is a virtual type. … … 260 300 261 301 \section{Exceptions} 262 % Anything about exception construction. 302 \todo{The entire exceptions section.} 263 303 264 304 \section{Unwinding} … … 274 314 stack. On function entry and return, unwinding is handled directly by the 275 315 call/return code embedded in the function. 276 In many cases, the position of the instruction pointer (relative to parameter 277 and local declarations) is enough to know the current size of the stack 278 frame. 279 316 317 % Discussing normal stack unwinding: 280 318 Usually, the stack-frame size is known statically based on parameter and 281 local variable declarations. Even withdynamic stack-size, the information319 local variable declarations. Even for a dynamic stack-size, the information 282 320 to determine how much of the stack has to be removed is still contained 283 321 within the function. … … 285 323 bumping the hardware stack-pointer up or down as needed. 286 324 Constructing/destructing values within a stack frame has 287 a similar complexity but can add additional work and take longer. 288 325 a similar complexity but larger constants. 326 327 % Discussing multiple frame stack unwinding: 289 328 Unwinding across multiple stack frames is more complex because that 290 329 information is no longer contained within the current function. 291 With seperate compilation a function has no way of knowing what its callers 292 are so it can't know how large those frames are. 293 Without altering the main code path it is also hard to pass that work off 294 to the caller. 330 With seperate compilation, 331 a function does not know its callers nor their frame layout. 332 Even using the return address, that information is encoded in terms of 333 actions in code, intermixed with the actions required finish the function. 334 Without changing the main code path it is impossible to select one of those 335 two groups of actions at the return site. 295 336 296 337 The traditional unwinding mechanism for C is implemented by saving a snap-shot … … 302 343 This approach is fragile and requires extra work in the surrounding code. 303 344 304 With respect to the extra work in the sur ounding code,345 With respect to the extra work in the surrounding code, 305 346 many languages define clean-up actions that must be taken when certain 306 347 sections of the stack are removed. Such as when the storage for a variable 307 is removed from the stack or when a try statement with a finally clause is 348 is removed from the stack, possibly requiring a destructor call, 349 or when a try statement with a finally clause is 308 350 (conceptually) popped from the stack. 309 None of these should be handled by the user --- that would contradict the351 None of these cases should be handled by the user --- that would contradict the 310 352 intention of these features --- so they need to be handled automatically. 311 353 … … 348 390 In plain C (which \CFA currently compiles down to) this 349 391 flag only handles the cleanup attribute: 392 %\label{code:cleanup} 350 393 \begin{cfa} 351 394 void clean_up( int * var ) { ... } … … 355 398 in this case @clean_up@, run when the variable goes out of scope. 356 399 This feature is enough to mimic destructors, 357 but not try statements which can effect400 but not try statements that affect 358 401 the unwinding. 359 402 … … 399 442 @_UA_FORCE_UNWIND@ specifies a forced unwind call. Forced unwind only performs 400 443 the cleanup phase and uses a different means to decide when to stop 401 (see \ vref{s:ForcedUnwind}).444 (see \autoref{s:ForcedUnwind}). 402 445 \end{enumerate} 403 446 404 447 The @exception_class@ argument is a copy of the 405 448 \code{C}{exception}'s @exception_class@ field, 406 which is a number that identifies the exception handling mechanism449 which is a number that identifies the EHM 407 450 that created the exception. 408 451 … … 494 537 needs its own exception context. 495 538 496 The exception context should be retrieved by calling the function539 The current exception context should be retrieved by calling the function 497 540 \snake{this_exception_context}. 498 541 For sequential execution, this function is defined as … … 519 562 The first step of a termination raise is to copy the exception into memory 520 563 managed by the exception system. Currently, the system uses @malloc@, rather 521 than reserved memory or the stack top. The exception handling mechanismmanages564 than reserved memory or the stack top. The EHM manages 522 565 memory for the exception as well as memory for libunwind and the system's own 523 566 per-exception storage. … … 618 661 \subsection{Try Statements and Catch Clauses} 619 662 The try statement with termination handlers is complex because it must 620 compensate for the C code-generation versus 663 compensate for the C code-generation versus proper 621 664 assembly-code generated from \CFA. Libunwind 622 665 requires an LSDA and personality function for control to unwind across a 623 666 function. The LSDA in particular is hard to mimic in generated C code. 624 667 625 The workaround is a function called @__cfaehm_try_terminate@ in the standard626 library. The contents of a try block and the termination handlers are converted 627 into functions. These are then passed to the try terminate function and it 628 calls them.668 The workaround is a function called \snake{__cfaehm_try_terminate} in the 669 standard \CFA library. The contents of a try block and the termination 670 handlers are converted into nested functions. These are then passed to the 671 try terminate function and it calls them, appropriately. 629 672 Because this function is known and fixed (and not an arbitrary function that 630 happens to contain a try statement), theLSDA can be generated ahead673 happens to contain a try statement), its LSDA can be generated ahead 631 674 of time. 632 675 633 Both the LSDA and the personality function are set ahead of time using 676 Both the LSDA and the personality function for \snake{__cfaehm_try_terminate} 677 are set ahead of time using 634 678 embedded assembly. This assembly code is handcrafted using C @asm@ statements 635 679 and contains 636 enough information for a single try statement the function repersents.680 enough information for the single try statement the function represents. 637 681 638 682 The three functions passed to try terminate are: … … 646 690 decides if a catch clause matches the termination exception. It is constructed 647 691 from the conditional part of each handler and runs each check, top to bottom, 648 in turn, first checking to see if the exception type matches and then if the 649 condition is true. It takes a pointer to the exception and returns 0 if the 692 in turn, to see if the exception matches this handler. 693 The match is performed in two steps, first a virtual cast is used to check 694 if the raised exception is an instance of the declared exception type or 695 one of its descendant types, and then the condition is evaluated, if 696 present. 697 The match function takes a pointer to the exception and returns 0 if the 650 698 exception is not handled here. Otherwise the return value is the id of the 651 699 handler that matches the exception. … … 660 708 All three functions are created with GCC nested functions. GCC nested functions 661 709 can be used to create closures, 662 in other words functions that can refer to the state of other 663 functions on the stack. This approach allows the functions to refer to all the 710 in other words, 711 functions that can refer to variables in their lexical scope even 712 those variables are part of a different function. 713 This approach allows the functions to refer to all the 664 714 variables in scope for the function containing the @try@ statement. These 665 715 nested functions and all other functions besides @__cfaehm_try_terminate@ in … … 669 719 670 720 \autoref{f:TerminationTransformation} shows the pattern used to transform 671 a \CFA try statement with catch clauses into the appropr ate C functions.721 a \CFA try statement with catch clauses into the appropriate C functions. 672 722 \todo{Explain the Termination Transformation figure.} 673 723 … … 738 788 Instead of storing the data in a special area using assembly, 739 789 there is just a linked list of possible handlers for each stack, 740 with each node on the list rep erenting a try statement on the stack.790 with each node on the list representing a try statement on the stack. 741 791 742 792 The head of the list is stored in the exception context. … … 744 794 to the head of the list. 745 795 Instead of traversing the stack, resumption handling traverses the list. 746 At each node, the EHM checks to see if the try statement the node rep ersents796 At each node, the EHM checks to see if the try statement the node represents 747 797 can handle the exception. If it can, then the exception is handled and 748 798 the operation finishes, otherwise the search continues to the next node. 749 799 If the search reaches the end of the list without finding a try statement 750 that can handle the exception, the default handler is executed and the 751 operation finishes. 800 with a handler clause 801 that can handle the exception, the default handler is executed. 802 If the default handler returns, control continues after the raise statement. 752 803 753 804 Each node has a handler function that does most of the work. 754 805 The handler function is passed the raised exception and returns true 755 806 if the exception is handled and false otherwise. 756 757 807 The handler function checks each of its internal handlers in order, 758 808 top-to-bottom, until it funds a match. If a match is found that handler is … … 760 810 If no match is found the function returns false. 761 811 The match is performed in two steps, first a virtual cast is used to see 762 if the thrown exception is an instance of the declared exception or one of 763 its descendant type, then check to see if passes the custom predicate if one 764 is defined. This ordering gives the type guarantee used in the predicate. 812 if the raised exception is an instance of the declared exception type or one 813 of its descendant types, if so then it is passed to the custom predicate 814 if one is defined. 815 % You need to make sure the type is correct before running the predicate 816 % because the predicate can depend on that. 765 817 766 818 \autoref{f:ResumptionTransformation} shows the pattern used to transform … … 814 866 (see \vpageref{s:ResumptionMarking}), which ignores parts of 815 867 the stack 816 already examined, is accomplished by updating the front of the list as the 817 search continues. Before the handler at a node is called, the head of the list 868 already examined, and is accomplished by updating the front of the list as 869 the search continues. 870 Before the handler is called at a matching node, the head of the list 818 871 is updated to the next node of the current node. After the search is complete, 819 872 successful or not, the head of the list is reset. … … 822 875 been checked are not on the list while a handler is run. If a resumption is 823 876 thrown during the handling of another resumption, the active handlers and all 824 the other handler checked up to this point are not checked again.877 the other handlers checked up to this point are not checked again. 825 878 % No paragraph? 826 879 This structure also supports new handlers added while the resumption is being … … 830 883 831 884 \begin{figure} 885 \centering 832 886 \input{resumption-marking} 833 887 \caption{Resumption Marking} … … 851 905 \section{Finally} 852 906 % Uses destructors and GCC nested functions. 853 A finally clause is placed into a GCC nested-function with a unique name, 854 and no arguments or return values. 855 This nested function is then set as the cleanup 856 function of an empty object that is declared at the beginning of a block placed 857 around the context of the associated @try@ statement. 858 859 The rest is handled by GCC. The try block and all handlers are inside this 860 block. At completion, control exits the block and the empty object is cleaned 907 908 %\autoref{code:cleanup} 909 A finally clause is handled by converting it into a once-off destructor. 910 The code inside the clause is placed into GCC nested-function 911 with a unique name, and no arguments or return values. 912 This nested function is 913 then set as the cleanup function of an empty object that is declared at the 914 beginning of a block placed around the context of the associated try 915 statement (see \autoref{f:FinallyTransformation}). 916 917 \begin{figure} 918 \begin{cfa} 919 try { 920 // TRY BLOCK 921 } finally { 922 // FINALLY BLOCK 923 } 924 \end{cfa} 925 926 \transformline 927 928 \begin{cfa} 929 { 930 void finally(void *__hook){ 931 // FINALLY BLOCK 932 } 933 __attribute__ ((cleanup(finally))) 934 struct __cfaehm_cleanup_hook __finally_hook; 935 { 936 // TRY BLOCK 937 } 938 } 939 \end{cfa} 940 941 \caption{Finally Transformation} 942 \label{f:FinallyTransformation} 943 \end{figure} 944 945 The rest is handled by GCC. 946 The TRY BLOCK 947 contains the try block itself as well as all code generated for handlers. 948 Once that code has completed, 949 control exits the block and the empty object is cleaned 861 950 up, which runs the function that contains the finally code. 862 951 … … 887 976 passed to the forced-unwind function. The general pattern of all three stop 888 977 functions is the same: continue unwinding until the end of stack and 889 then p reform the appropriate transfer.978 then perform the appropriate transfer. 890 979 891 980 For main stack cancellation, the transfer is just a program abort.
Note: See TracChangeset
for help on using the changeset viewer.