Changeset 9cdfa5fb for doc/theses/andrew_beach_MMath/implement.tex
- Timestamp:
- Sep 10, 2021, 10:43:15 AM (3 years ago)
- Branches:
- ADT, ast-experimental, enum, forall-pointer-decay, master, pthread-emulation, qualifiedEnum
- Children:
- 63b3279
- Parents:
- d0b9247
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/andrew_beach_MMath/implement.tex
rd0b9247 r9cdfa5fb 14 14 \label{s:VirtualSystem} 15 15 % Virtual table rules. Virtual tables, the pointer to them and the cast. 16 While the \CFA virtual system currently has only onepublic features, virtual16 While the \CFA virtual system currently has only two public features, virtual 17 17 cast and virtual tables, 18 % ??? refs (see the virtual cast feature \vpageref{p:VirtualCast}),19 18 substantial structure is required to support them, 20 19 and provide features for exception handling and the standard library. … … 35 34 as part of field-by-field construction. 36 35 37 \subsection{Type I d}38 Every virtual type has a unique id.36 \subsection{Type ID} 37 Every virtual type has a unique ID. 39 38 These are used in type equality, to check if the representation of two values 40 39 are the same, and to access the type's type information. … … 44 43 45 44 Our approach for program uniqueness is using a static declaration for each 46 type id, where the run-time storage address of that variable is guaranteed to45 type ID, where the run-time storage address of that variable is guaranteed to 47 46 be unique during program execution. 48 The type idstorage can also be used for other purposes,47 The type ID storage can also be used for other purposes, 49 48 and is used for type information. 50 49 51 The problem is that a type idmay appear in multiple TUs that compose a52 program (see \autoref{ss:VirtualTable}) ;so the initial solution would seem53 to be make it external in each translation unit. Hovever, the type idmust50 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. Hovever, the type ID must 54 53 have a declaration in (exactly) one of the TUs to create the storage. 55 54 No other declaration related to the virtual type has this property, so doing 56 55 this through standard C declarations would require the user to do it manually. 57 56 58 Instead the linker is used to handle this problem.57 Instead, the linker is used to handle this problem. 59 58 % I did not base anything off of C++17; they are solving the same problem. 60 59 A new feature has been added to \CFA for this purpose, the special attribute 61 60 \snake{cfa_linkonce}, which uses the special section @.gnu.linkonce@. 62 When used as a prefix (\eg @.gnu.linkonce.example@) the linker does61 When used as a prefix (\eg @.gnu.linkonce.example@), the linker does 63 62 not combine these sections, but instead discards all but one with the same 64 63 full name. 65 64 66 So each type id must be given a unique section name with the linkonce67 prefix. Luckily \CFA already has a way to get unique names, the name mangler.65 So, each type ID must be given a unique section name with the \snake{linkonce} 66 prefix. Luckily, \CFA already has a way to get unique names, the name mangler. 68 67 For example, this could be written directly in \CFA: 69 68 \begin{cfa} … … 74 73 __attribute__((section(".gnu.linkonce._X1fFv___1"))) void _X1fFv___1() {} 75 74 \end{cfa} 76 This is done internally to access the name mangler s.75 This is done internally to access the name mangler. 77 76 This attribute is useful for other purposes, any other place a unique 78 77 instance required, and should eventually be made part of a public and … … 81 80 \subsection{Type Information} 82 81 83 There is data stored at the type id's declaration, the type information.84 The type information currently is only the parent's type idor, if the82 There is data stored at the type ID's declaration, the type information. 83 The type information currently is only the parent's type ID or, if the 85 84 type has no parent, the null pointer. 86 The ancestors of a virtual type are found by traversing type ids through85 The ancestors of a virtual type are found by traversing type IDs through 87 86 the type information. 88 87 An example using helper macros looks like: … … 105 104 \item 106 105 Generate a new structure definition to store the type 107 information. The layout is the same in each case, just the parent's type id,106 information. The layout is the same in each case, just the parent's type ID, 108 107 but the types used change from instance to instance. 109 108 The generated name is used for both this structure and, if relevant, the … … 115 114 \item 116 115 The definition is generated and initialized. 117 The parent idis set to the null pointer or to the address of the parent's116 The parent ID is set to the null pointer or to the address of the parent's 118 117 type information instance. Name resolution handles the rest. 119 118 \item … … 151 150 file as if it was a forward declaration, except no definition is required. 152 151 153 This technique is used for type -idinstances. A link-once definition is152 This technique is used for type ID instances. A link-once definition is 154 153 generated each time the structure is seen. This will result in multiple 155 154 copies but the link-once attribute ensures all but one are removed for a … … 168 167 \subsection{Virtual Table} 169 168 \label{ss:VirtualTable} 170 Each virtual type has a virtual table type that stores its type id and 169 %\todo{Clarify virtual table type vs. virtual table instance.} 170 Each virtual type has a virtual table type that stores its type ID and 171 171 virtual members. 172 172 Each virtual type instance is bound to a table instance that is filled with … … 176 176 177 177 The layout always comes in three parts (see \autoref{f:VirtualTableLayout}). 178 The first section is just the type idat the head of the table. It is always178 The first section is just the type ID at the head of the table. It is always 179 179 there to ensure that it can be found even when the accessing code does not 180 180 know which virtual type it has. 181 The second section areall the virtual members of the parent, in the same181 The second section is all the virtual members of the parent, in the same 182 182 order as they appear in the parent's virtual table. Note that the type may 183 183 change slightly as references to the ``this" change. This is limited to … … 199 199 This, combined with the fixed offset to the virtual table pointer, means that 200 200 for any virtual type, it is always safe to access its virtual table and, 201 from there, it is safe to check the type idto identify the exact type of the201 from there, it is safe to check the type ID to identify the exact type of the 202 202 underlying object, access any of the virtual members and pass the object to 203 203 any of the method-like virtual members. … … 207 207 the context of the declaration. 208 208 209 The type id is always fixed;with each virtual table type having210 exactly one possible type id.209 The type ID is always fixed, with each virtual table type having 210 exactly one possible type ID. 211 211 The virtual members are usually filled in by type resolution. 212 212 The best match for a given name and type at the declaration site is used. 213 213 There are two exceptions to that rule: the @size@ field, the type's size, 214 is set using a @sizeof@ expression and the @align@ field, the214 is set using a @sizeof@ expression, and the @align@ field, the 215 215 type's alignment, is set using an @alignof@ expression. 216 216 217 217 Most of these tools are already inside the compiler. Using simple 218 code transformations early on in compilation ,allows most of that work to be218 code transformations early on in compilation allows most of that work to be 219 219 handed off to the existing tools. \autoref{f:VirtualTableTransformation} 220 shows an example transformation ,this example shows an exception virtual table.220 shows an example transformation; this example shows an exception virtual table. 221 221 It also shows the transformation on the full declaration. 222 222 For a forward declaration, the @extern@ keyword is preserved and the … … 312 312 struct __cfavir_type_id * const * child ); 313 313 \end{cfa} 314 The type idfor the target type of the virtual cast is passed in as314 The type ID for the target type of the virtual cast is passed in as 315 315 @parent@ and 316 316 the cast target is passed in as @child@. … … 322 322 The virtual cast either returns the original pointer or the null pointer 323 323 as the new type. 324 So the function does the parent check and returns the appropriate value.325 The parent check is a simple linear search of child's ancestors using the324 The function does the parent check and returns the appropriate value. 325 The parent check is a simple linear search of the child's ancestors using the 326 326 type information. 327 327 … … 329 329 % The implementation of exception types. 330 330 331 Creating exceptions can roughly divided into two parts,331 Creating exceptions can be roughly divided into two parts: 332 332 the exceptions themselves and the virtual system interactions. 333 333 … … 361 361 362 362 All types associated with a virtual type, 363 the types of the virtual table and the type id,363 the types of the virtual table and the type ID, 364 364 are generated when the virtual type (the exception) is first found. 365 The type id(the instance) is generated with the exception, if it is365 The type ID (the instance) is generated with the exception, if it is 366 366 a monomorphic type. 367 However, if the exception is polymorphic, then a different type idhas to367 However, if the exception is polymorphic, then a different type ID has to 368 368 be generated for every instance. In this case, generation is delayed 369 369 until a virtual table is created. … … 372 372 When a virtual table is created and initialized, two functions are created 373 373 to fill in the list of virtual members. 374 The first is a copyfunction that adapts the exception's copy constructor374 The first is the @copy@ function that adapts the exception's copy constructor 375 375 to work with pointers, avoiding some issues with the current copy constructor 376 376 interface. 377 Second is the msgfunction that returns a C-string with the type's name,377 Second is the @msg@ function that returns a C-string with the type's name, 378 378 including any polymorphic parameters. 379 379 … … 402 402 403 403 % Discussing multiple frame stack unwinding: 404 Unwinding across multiple stack frames is more complex because that404 Unwinding across multiple stack frames is more complex, because that 405 405 information is no longer contained within the current function. 406 406 With separate compilation, 407 407 a function does not know its callers nor their frame layout. 408 408 Even using the return address, that information is encoded in terms of 409 actions in code, intermixed with the actions required finish the function.409 actions in code, intermixed with the actions required to finish the function. 410 410 Without changing the main code path it is impossible to select one of those 411 411 two groups of actions at the return site. 412 412 413 The traditional unwinding mechanism for C is implemented by saving a snap -shot414 of a function's state with @setjmp@ and restoring that snap -shot with413 The traditional unwinding mechanism for C is implemented by saving a snapshot 414 of a function's state with @setjmp@ and restoring that snapshot with 415 415 @longjmp@. This approach bypasses the need to know stack details by simply 416 reseting to a snap -shot of an arbitrary but existing function frame on the417 stack. It is up to the programmer to ensure the snap -shot is valid when it is418 reset and that all required clean -up from the unwound stacks is performed.416 reseting to a snapshot of an arbitrary but existing function frame on the 417 stack. It is up to the programmer to ensure the snapshot is valid when it is 418 reset and that all required cleanup from the unwound stacks is performed. 419 419 This approach is fragile and requires extra work in the surrounding code. 420 420 421 421 With respect to the extra work in the surrounding code, 422 many languages define clean -up actions that must be taken when certain423 sections of the stack are removed . Such as when the storage for a variable422 many languages define cleanup actions that must be taken when certain 423 sections of the stack are removed, such as when the storage for a variable 424 424 is removed from the stack, possibly requiring a destructor call, 425 425 or when a try statement with a finally clause is 426 426 (conceptually) popped from the stack. 427 None of these cases should be handled by the user -- -that would contradict the428 intention of these features -- -so they need to be handled automatically.427 None of these cases should be handled by the user -- that would contradict the 428 intention of these features -- so they need to be handled automatically. 429 429 430 430 To safely remove sections of the stack, the language must be able to find and 431 run these clean -up actions even when removing multiple functions unknown at431 run these cleanup actions even when removing multiple functions unknown at 432 432 the beginning of the unwinding. 433 433 … … 529 529 provided storage object. It has two public fields: the @exception_class@, 530 530 which is described above, and the @exception_cleanup@ function. 531 The clean -up function is used by the EHM to clean-up the exception, if it531 The cleanup function is used by the EHM to clean up the exception. If it 532 532 should need to be freed at an unusual time, it takes an argument that says 533 533 why it had to be cleaned up. … … 551 551 of the most recent stack frame. It continues to call personality functions 552 552 traversing the stack from newest to oldest until a function finds a handler or 553 the end of the stack is reached. In the latter case, raise exception returns554 @_U RC_END_OF_STACK@.555 556 Second, when a handler is matched, raise exception moves to the clean-up557 phase and walks the stack a second time.553 the end of the stack is reached. In the latter case, 554 @_Unwind_RaiseException@ returns @_URC_END_OF_STACK@. 555 556 Second, when a handler is matched, @_Unwind_RaiseException@ 557 moves to the cleanup phase and walks the stack a second time. 558 558 Once again, it calls the personality functions of each stack frame from newest 559 559 to oldest. This pass stops at the stack frame containing the matching handler. 560 If that personality function has not install a handler, it is an error.561 562 If an error is encountered, raise exceptionreturns either560 If that personality function has not installed a handler, it is an error. 561 562 If an error is encountered, @_Unwind_RaiseException@ returns either 563 563 @_URC_FATAL_PHASE1_ERROR@ or @_URC_FATAL_PHASE2_ERROR@ depending on when the 564 564 error occurred. … … 571 571 _Unwind_Stop_Fn, void *); 572 572 \end{cfa} 573 It also unwinds the stack but it does not use the search phase. Instead another 573 It also unwinds the stack but it does not use the search phase. Instead, 574 another 574 575 function, the stop function, is used to stop searching. The exception is the 575 same as the one passed to raise exception. The extra arguments are the stop 576 same as the one passed to @_Unwind_RaiseException@. 577 The extra arguments are the stop 576 578 function and the stop parameter. The stop function has a similar interface as a 577 579 personality function, except it is also passed the stop parameter. … … 721 723 one list per stack, with the 722 724 list head stored in the exception context. Within each linked list, the most 723 recently thrown exception is at the head followed by older thrown725 recently thrown exception is at the head, followed by older thrown 724 726 exceptions. This format allows exceptions to be thrown, while a different 725 727 exception is being handled. The exception at the head of the list is currently … … 732 734 exception into managed memory. After the exception is handled, the free 733 735 function is used to clean up the exception and then the entire node is 734 passed to free, returning the memory back to the heap.736 passed to @free@, returning the memory back to the heap. 735 737 736 738 \subsection{Try Statements and Catch Clauses} … … 757 759 The three functions passed to try terminate are: 758 760 \begin{description} 759 \item[try function:] This function is the try block , it is where all the code761 \item[try function:] This function is the try block. It is where all the code 760 762 from inside the try block is placed. It takes no parameters and has no 761 763 return value. This function is called during regular execution to run the try … … 766 768 from the conditional part of each handler and runs each check, top to bottom, 767 769 in turn, to see if the exception matches this handler. 768 The match is performed in two steps , firsta virtual cast is used to check770 The match is performed in two steps: first, a virtual cast is used to check 769 771 if the raised exception is an instance of the declared exception type or 770 772 one of its descendant types, and then the condition is evaluated, if 771 773 present. 772 774 The match function takes a pointer to the exception and returns 0 if the 773 exception is not handled here. Otherwise the return value is the idof the775 exception is not handled here. Otherwise, the return value is the ID of the 774 776 handler that matches the exception. 775 777 … … 782 784 \end{description} 783 785 All three functions are created with GCC nested functions. GCC nested functions 784 can be used to create closures ,786 can be used to create closures; 785 787 in other words, 786 functions that can refer to variables in their lexical scope even 788 functions that can refer to variables in their lexical scope even though 787 789 those variables are part of a different function. 788 790 This approach allows the functions to refer to all the … … 869 871 At each node, the EHM checks to see if the try statement the node represents 870 872 can handle the exception. If it can, then the exception is handled and 871 the operation finishes , otherwisethe search continues to the next node.873 the operation finishes; otherwise, the search continues to the next node. 872 874 If the search reaches the end of the list without finding a try statement 873 875 with a handler clause … … 879 881 if the exception is handled and false otherwise. 880 882 The handler function checks each of its internal handlers in order, 881 top-to-bottom, until it f unds a match. If a match is found that handler is883 top-to-bottom, until it finds a match. If a match is found that handler is 882 884 run, after which the function returns true, ignoring all remaining handlers. 883 885 If no match is found the function returns false. 884 The match is performed in two steps , first a virtual cast is used to see886 The match is performed in two steps. First a virtual cast is used to see 885 887 if the raised exception is an instance of the declared exception type or one 886 of its descendant types, if so then it is passed to the custom predicate 888 of its descendant types, if so, then the second step is to see if the 889 exception passes the custom predicate 887 890 if one is defined. 888 891 % You need to make sure the type is correct before running the predicate … … 936 939 % Recursive Resumption Stuff: 937 940 \autoref{f:ResumptionMarking} shows search skipping 938 (see \ vpageref{s:ResumptionMarking}), which ignores parts of941 (see \autoref{s:ResumptionMarking}), which ignores parts of 939 942 the stack 940 943 already examined, and is accomplished by updating the front of the list as … … 951 954 This structure also supports new handlers added while the resumption is being 952 955 handled. These are added to the front of the list, pointing back along the 953 stack -- - the first one points over all the checked handlers ---956 stack -- the first one points over all the checked handlers -- 954 957 and the ordering is maintained. 955 958 … … 979 982 %\autoref{code:cleanup} 980 983 A finally clause is handled by converting it into a once-off destructor. 981 The code inside the clause is placed into GCC nested-function984 The code inside the clause is placed into a GCC nested-function 982 985 with a unique name, and no arguments or return values. 983 986 This nested function is 984 987 then set as the cleanup function of an empty object that is declared at the 985 988 beginning of a block placed around the context of the associated try 986 statement (see \autoref{f:FinallyTransformation}).989 statement, as shown in \autoref{f:FinallyTransformation}. 987 990 988 991 \begin{figure} … … 1024 1027 % Stack selections, the three internal unwind functions. 1025 1028 1026 Cancellation also uses libunwind to do its stack traversal and unwinding ,1027 howeverit uses a different primary function: @_Unwind_ForcedUnwind@. Details1028 of its interface can be found in theSection~\vref{s:ForcedUnwind}.1029 Cancellation also uses libunwind to do its stack traversal and unwinding. 1030 However, it uses a different primary function: @_Unwind_ForcedUnwind@. Details 1031 of its interface can be found in Section~\vref{s:ForcedUnwind}. 1029 1032 1030 1033 The first step of cancellation is to find the cancelled stack and its type:
Note: See TracChangeset
for help on using the changeset viewer.