Changeset 4f1b8f3f
- Timestamp:
- Jun 15, 2021, 12:18:33 PM (3 years ago)
- Branches:
- ADT, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 2f19e03, 64780c1
- Parents:
- 1f05c83 (diff), 6f8c46d (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. - Location:
- doc/theses/andrew_beach_MMath
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/andrew_beach_MMath/future.tex
r1f05c83 r4f1b8f3f 7 7 that I had to workaround while building an exception handling system largely in 8 8 the \CFA language (some C components). The following are a few of these 9 issues, and once implemented/fixed, how th iswould affect the exception system.9 issues, and once implemented/fixed, how they would affect the exception system. 10 10 \begin{itemize} 11 11 \item … … 13 13 hand-crafted assembly statements. These sections must be ported by hand to 14 14 support more hardware architectures, such as the ARM processor. 15 \PAB{I think this is a straw-man problem because the hand-coded assembler code 16 has to be generated somewhere, and that somewhere is hand-coded.} 15 17 \item 16 18 Due to a type-system problem, the catch clause cannot bind the exception to a 17 19 reference instead of a pointer. Since \CFA has a very general reference 18 20 capability, programmers will want to use it. Once fixed, this capability should 19 result in little or no change in the exception system .21 result in little or no change in the exception system but simplify usage. 20 22 \item 21 23 Termination handlers cannot use local control-flow transfers, \eg by @break@, … … 28 30 There is no detection of colliding unwinds. It is possible for clean-up code 29 31 run during an unwind to trigger another unwind that escapes the clean-up code 30 itself ; such asa termination exception caught further down the stack or a31 cancellation. There do exist ways to handle this but currently they are not32 even detected and the first unwind will simply be forgotten, often leaving33 it in a bad state. 32 itself, \eg, a termination exception caught further down the stack or a 33 cancellation. There do exist ways to handle this issue, but currently they are not 34 even detected and the first unwind is simply dropped, often leaving 35 it in a bad state. \Cpp terminates the program in this case, and Java picks the ... 34 36 \item 35 37 Also the exception system did not have a lot of time to be tried and tested. … … 41 43 The virtual system should be completed. It was not supposed to be part of this 42 44 project, but was thrust upon it to do exception inheritance; hence, only 43 minimal work was done. A draft for a complete virtual system is available but45 minimal work is done. A draft for a complete virtual system is available but 44 46 it is not finalized. A future \CFA project is to complete that work and then 45 47 update the exception system that uses the current version. … … 67 69 bad software engineering. 68 70 69 Non-local/concurrent r equires more coordination between the concurrency system71 Non-local/concurrent raise requires more coordination between the concurrency system 70 72 and the exception system. Many of the interesting design decisions centre 71 around masking (controlling which exceptions may be thrown at a stack). It73 around masking, \ie controlling which exceptions may be thrown at a stack. It 72 74 would likely require more of the virtual system and would also effect how 73 75 default handlers are set. … … 85 87 86 88 \section{Checked Exceptions} 87 Checked exceptions make exceptions part of a function's type by adding the89 Checked exceptions make exceptions part of a function's type by adding an 88 90 exception signature. An exception signature must declare all checked 89 exceptions that could prop ogate from the function (either because they were91 exceptions that could propagate from the function (either because they were 90 92 raised inside the function or came from a sub-function). This improves safety 91 93 by making sure every checked exception is either handled or consciously 92 94 passed on. 93 95 94 However checked exceptions were never seriously considered for this project 95 for two reasons. The first is due to time constraints, even copying an 96 existing checked exception system would be pushing the remaining time and 97 trying to address the second problem would take even longer. The second 98 problem is that checked exceptions have some real usability trade-offs in 96 However checked exceptions were never seriously considered for this project because 97 they have significant usability and reuse trade-offs in 99 98 exchange for the increased safety. 100 101 99 These trade-offs are most problematic when trying to pass exceptions through 102 100 higher-order functions from the functions the user passed into the 103 101 higher-order function. There are no well known solutions to this problem 104 that were s tatifactory for \CFA (which carries some of C's flexability105 over safety design) so one would have to be researched and developed.102 that were satisfactory for \CFA (which carries some of C's flexibility 103 over safety design) so additional research is needed. 106 104 107 Follow-up work might add checked exceptions to\CFA, possibly using108 polymorphic exception signatures, a form of tunneling\cite{Zhang19} or105 Follow-up work might find a compromise design for checked exceptions in \CFA, possibly using 106 polymorphic exception signatures, a form of tunneling\cite{Zhang19}, or 109 107 checked and unchecked raises. 110 108 … … 150 148 For instance, resumption could be extended to cover this use by allowing local 151 149 control flow out of it. This approach would require an unwind as part of the 152 transition as there are stack frames that have to be removed . This approach153 means there is no notify raise, but because \CFA does not have exception154 signatures, a termination canbe thrown from within any resumption handler so155 there is already a way to do mimic this in existing \CFA.150 transition as there are stack frames that have to be removed back to the resumption handler. This approach 151 means no special statement is required in the handler to continue after it. 152 Currently, \CFA allows a termination exception to be thrown from within any resumption handler so 153 there is already a way to partially mimic signal exceptions. 156 154 157 155 % Maybe talk about the escape; and escape CONTROL_STMT; statements or how -
doc/theses/andrew_beach_MMath/implement.tex
r1f05c83 r4f1b8f3f 2 2 \label{c:implement} 3 3 4 The implementation work for this thesis covers t wo components: thevirtual4 The implementation work for this thesis covers the two components: virtual 5 5 system and exceptions. Each component is discussed in detail. 6 6 … … 17 17 pointer to the virtual table, which is called the \emph{virtual-table pointer}. 18 18 Internally, the field is called \snake{virtual_table}. 19 The field is fixed after construction . It is always the first field in the19 The field is fixed after construction and is the first field in the 20 20 structure so that its location is always known. 21 21 \todo{Talk about constructors for virtual types (after they are working).} 22 22 23 Th is is what binds an instance of a virtual type to avirtual table. This24 pointer can be used as an identity check. It can also be used to access the23 The virtual-table pointer is what binds an instance of a virtual type to its virtual table. This 24 pointer is used as an identity check, and to access the 25 25 virtual table and the virtual members there. 26 26 27 27 \subsection{Type Id} 28 28 Every virtual type has a unique id. 29 Type ids can be compared for equality ( the types reperented are the same)29 Type ids can be compared for equality (\ie the types represented are the same) 30 30 or used to access the type's type information. 31 31 The type information currently is only the parent's type id or, if the 32 type has no parent, zero.32 type has no parent, @0p@. 33 33 34 34 The id's are implemented as pointers to the type's type information instance. 35 Derefe ncing the pointer gets the type information.36 By going back-and-forth between the type id and 37 the type info one can find every ancestor of a virtual type.38 Italso pushes the issue of creating a unique value (for35 Dereferencing the pointer gets the type information. 36 The ancestors of a virtual type are found by traversing the type id through 37 the type information. 38 An id also pushes the issue of creating a unique value (for 39 39 the type id) to the problem of creating a unique instance (for type 40 information) which the linker can solve.40 information), which the linker can solve. 41 41 42 42 Advanced linker support is required because there is no place that appears 43 43 only once to attach the type information to. There should be one structure 44 definition but it is included in multiple translation units . Each virtual45 table definition should be unique but there are an arbitrary number of th oses.46 So the special section prefix \texttt{.gnu.linkonce} is used.47 With a unique suffix (making the entire section name unique) the linker will48 remove multiple definition making sureonly one version exists after linking.44 definition but it is included in multiple translation units because of separate compilation. Each virtual 45 table definition should be unique but there are an arbitrary number of these, 46 so the special section prefix \texttt{.gnu.linkonce} is used. 47 With a generated unique suffix (making the entire section name unique) the linker 48 removes multiple definition ensuring only one version exists after linking. 49 49 Then it is just a matter of making sure there is a unique name for each type. 50 50 51 This is done in three phases. 51 These steps are done in three phases. 52 \begin{enumerate} 53 \item 52 54 The first phase is to generate a new structure definition to store the type 53 55 information. The layout is the same in each case, just the parent's type id, … … 55 57 The structure's name is change, it is based off the virtual type's name, and 56 58 the type of the parent's type id. 57 If the virtual type is polymorphic then the type information structure is59 If the virtual type is polymorphic, then the type information structure is 58 60 polymorphic as well, with the same polymorphic arguments. 59 61 \item 60 62 The second phase is to generate an instance of the type information with a 61 63 almost unique name, generated by mangling the virtual type name. 62 64 \item 63 65 The third phase is implicit with \CFA's overloading scheme. \CFA mangles 64 66 names with type information so that all of the symbols exported to the linker 65 are unique even if in \CFA code they are the same. Having two declarations67 are unique even if in the \CFA code they are the same. Having two declarations 66 68 with the same name and same type is forbidden because it is impossible for 67 overload resolution to pick between them. This is why a unique type is69 overload resolution to pick between them. This is the reason why a unique type is 68 70 generated for each virtual type. 69 71 Polymorphic information is included in this mangling so polymorphic 70 types will have seperate instances for each set of polymorphic arguments. 71 72 types have separate instances for each set of polymorphic arguments. 73 \end{enumerate} 74 The following example shows the components for a generated virtual type. 72 75 \begin{cfa} 73 76 struct TYPE_ID_TYPE { … … 81 84 \end{cfa} 82 85 83 \subsubsection{ cfa\_linkonceAttribute}86 \subsubsection{\lstinline{cfa_linkonce} Attribute} 84 87 Another feature added to \CFA is a new attribute: \texttt{cfa\_linkonce}. 85 This attribute can be put onan object or function definition86 (any global declaration with a name and a type) .87 This allows you to define that object or functionmultiple times.88 All definitions should have the link-once attribute on them and allshould88 This attribute is attached to an object or function definition 89 (any global declaration with a name and a type) 90 allowing it to be defined multiple times. 91 All matching definitions must have the link-once attribute on them and should 89 92 be identical. 90 91 The simplist way to use it is to put a definition in a header where the 92 forward declaration would usually go. 93 This is how it is used for type-id instances. There was is no unique location 94 associated with a type except for the type definition which is in a header. 95 This allows the unique type-id object to be generated there. 96 97 Internally @cfa_linkonce@ removes all @section@ attributes 98 from the declaration (as well as itself) and replaces them with 93 This attributed prototype is placed in a header file with other 94 forward declaration. 95 96 This technique is used for type-id instances, as there is no unique location 97 associated with a type, except for the type definition in a header. 98 The result is the unique type-id object generated by the linker. 99 100 Internally, @cfa_linkonce@ is replaced with 99 101 @section(".gnu.linkonce.NAME")@ where \texttt{NAME} is replaced by the 100 102 mangled name of the object. 103 Any other @section@ attributes are also removed from the declaration. 101 104 The prefix \texttt{.gnu.linkonce} in section names is recognized by the 102 linker. If two of these sections with the same name, including everything103 that comes after the special prefix, then only one will beused and the other104 will bediscarded.105 linker. If two of these sections appear with the same name, including everything 106 that comes after the special prefix, then only one is used and the other 107 discarded. 105 108 106 109 \subsection{Virtual Table} … … 112 115 below. 113 116 114 The layout always comes in three parts. 117 Figure~\ref{f:VirtualTableLayout} shows the layout is in three parts. 118 \PAB{Number the parts in the figure.} 119 \begin{enumerate} 120 \item 115 121 The first section is just the type id at the head of the table. It is always 116 there to ensure that 122 there to ensure that \PAB{... missing text to end this sentence} 123 \item 117 124 The second section are all the virtual members of the parent, in the same 118 125 order as they appear in the parent's virtual table. Note that the type may 119 change slightly as references to the ``this" will change. Thisis limited to126 change slightly as references to the @this@ change. This structure is limited to 120 127 inside pointers/references and via function pointers so that the size (and 121 128 hence the offsets) are the same. 129 \item 122 130 The third section is similar to the second except that it is the new virtual 123 131 members introduced at this level in the hierarchy. 132 \end{enumerate} 124 133 125 134 \begin{figure} … … 133 142 prefix that has the same layout and types as its parent virtual table. 134 143 This, combined with the fixed offset to the virtual table pointer, means that 135 for any virtual type it doesn't matter if we haveit or any of its136 descendants , it is still always safe to access the virtual tablethrough144 for any virtual type, it or any of its 145 descendants can be accessed through 137 146 the virtual table pointer. 138 From there it is safe to check the type id to identify the exact type of the139 underlying object, access any of the virtual members and pass the object to147 From there, it is safe to check the type id to identify the exact type of the 148 underlying object, access any of the virtual members, and pass the object to 140 149 any of the method-like virtual members. 141 150 142 When a virtual table is declared the user decides where to declare it and its151 When a virtual table is declared, the user decides where to declare it and its 143 152 name. The initialization of the virtual table is entirely automatic based on 144 153 the context of the declaration. 145 154 146 The type id is always fixed , each virtual table type will always have one155 The type id is always fixed with each virtual table type having 147 156 exactly one possible type id. 148 The virtual members are usually filled in byresolution. The best match for149 a given name and type at the declaration site is filled in.157 The virtual members are usually filled in during type resolution. The best match for 158 a given name and type at the declaration site is used. 150 159 There are two exceptions to that rule: the @size@ field is the type's size 151 and is set to the result of a @sizeof@ expression,the @align@ field is the152 type's alignment and similarly usesan @alignof@ expression.160 set using a @sizeof@ expression, and the @align@ field is the 161 type's alignment set using an @alignof@ expression. 153 162 154 163 \subsubsection{Concurrency Integration} 155 164 Coroutines and threads need instances of @CoroutineCancelled@ and 156 165 @ThreadCancelled@ respectively to use all of their functionality. When a new 157 data type is declared with @coroutine@ or @thread@ theforward declaration for166 data type is declared with @coroutine@ or @thread@, a forward declaration for 158 167 the instance is created as well. The definition of the virtual table is created 159 168 at the definition of the main function. 169 170 Figure~\ref{f:ConcurrencyTransformations} shows ... 171 \todo{Improve Concurrency Transformations figure.} 160 172 161 173 \begin{figure} … … 194 206 \label{f:ConcurrencyTransformations} 195 207 \end{figure} 196 \todo{Improve Concurrency Transformations figure.}197 208 198 209 \subsection{Virtual Cast} … … 211 222 the cast target is passed in as @child@. 212 223 213 For C generation both arguments and the result are wrappedwith type casts.214 There is also an internal storeinside the compiler to make sure that the224 The generated C code wraps both arguments and the result with type casts. 225 There is also an internal check inside the compiler to make sure that the 215 226 target type is a virtual type. 216 227 % It also checks for conflicting definitions. 217 228 218 The virtual cast either returns the original pointer as a new type or null.219 So the function just does the parent check and returns the appropr ate value.229 The virtual cast either returns the original pointer as a new type or 0p. 230 So the function just does the parent check and returns the appropriate value. 220 231 The parent check is a simple linear search of child's ancestors using the 221 232 type information. … … 229 240 % resumption doesn't as well. 230 241 231 % Many modern languages work with an inter al stack that function push and pop242 % Many modern languages work with an internal stack that function push and pop 232 243 % their local data to. Stack unwinding removes large sections of the stack, 233 244 % often across functions. … … 236 247 stack. On function entry and return, unwinding is handled directly by the 237 248 call/return code embedded in the function. 238 In many cases the position of the instruction pointer (relative to parameter249 In many cases, the position of the instruction pointer (relative to parameter 239 250 and local declarations) is enough to know the current size of the stack 240 251 frame. 241 252 242 253 Usually, the stack-frame size is known statically based on parameter and 243 local variable declarations. Even with dynamic stack-size the information244 to determ ainhow much of the stack has to be removed is still contained254 local variable declarations. Even with dynamic stack-size, the information 255 to determine how much of the stack has to be removed is still contained 245 256 within the function. 246 257 Allocating/deallocating stack space is usually an $O(1)$ operation achieved by 247 258 bumping the hardware stack-pointer up or down as needed. 248 Constructing/destructing values on the stack takes longer put in terms of 249 figuring out what needs to be done is of similar complexity. 259 In fact, constructing/destructing values within a stack frame is of similar complexity but often takes longer. 250 260 251 261 Unwinding across multiple stack frames is more complex because that 252 262 information is no longer contained within the current function. 253 With sep erate compilation a function has no way of knowing what its callers254 are so it can't know how large those frames are.255 Without altering the main code path it is also hard to pass that work off263 With separate compilation a function has no way of knowing what its callers 264 so it can not know how large those frames are. 265 Without altering the main code path, it is also hard to pass that work off 256 266 to the caller. 257 267 … … 261 271 reseting to a snap-shot of an arbitrary but existing function frame on the 262 272 stack. It is up to the programmer to ensure the snap-shot is valid when it is 263 reset and that all required clean-up from the unwound stacks is p reformed.264 This approach is fragile and forces a work onto the surounding code.265 266 With respect to th at work forced onto the surounding code,273 reset and that all required clean-up from the unwound stacks is performed. 274 This approach is fragile and forces extra work in the surrounding code. 275 276 With respect to the extra work in the surrounding code, 267 277 many languages define clean-up actions that must be taken when certain 268 278 sections of the stack are removed. Such as when the storage for a variable 269 is removed from the stack or when a trystatement with a finally clause is279 is removed from the stack or when a @try@ statement with a finally clause is 270 280 (conceptually) popped from the stack. 271 None of these should be handled by the user,that would contradict the272 intention of these features ,so they need to be handled automatically.273 274 To safely remove sections of the stack the language must be able to find and281 None of these should be handled explicitly by the user --- that would contradict the 282 intention of these features --- so they need to be handled automatically. 283 284 To safely remove sections of the stack, the language must be able to find and 275 285 run these clean-up actions even when removing multiple functions unknown at 276 286 the beginning of the unwinding. … … 294 304 current stack frame, and what handlers should be checked. Theoretically, the 295 305 LSDA can contain any information but conventionally it is a table with entries 296 representing regions of thefunction and what has to be done there during306 representing regions of a function and what has to be done there during 297 307 unwinding. These regions are bracketed by instruction addresses. If the 298 308 instruction pointer is within a region's start/end, then execution is currently 299 309 executing in that region. Regions are used to mark out the scopes of objects 300 with destructors and tryblocks.310 with destructors and @try@ blocks. 301 311 302 312 % Libunwind actually does very little, it simply moves down the stack from … … 314 324 int avar __attribute__(( cleanup(clean_up) )); 315 325 \end{cfa} 316 The attribu e is used on a variable and specifies a function,326 The attribute is used on a variable and specifies a function, 317 327 in this case @clean_up@, run when the variable goes out of scope. 318 This is enough to mimic destructors, but not trystatements which can effect328 This capability is enough to mimic destructors, but not @try@ statements which can effect 319 329 the unwinding. 320 330 321 To get full unwinding support all of this has to bedone directly with322 assembly and assembler directives . Partiularly the cfi directives323 \snake{.cfi_ lsda} and \snake{.cfi_personality}.331 To get full unwinding support, all of these components must done directly with 332 assembly and assembler directives, particularly the cfi directives 333 \snake{.cfi_Leda} and \snake{.cfi_personality}. 324 334 325 335 \subsection{Personality Functions} … … 327 337 section covers some of the important parts of the interface. 328 338 329 A personality function can p reform different actions depending on how it is339 A personality function can perform different actions depending on how it is 330 340 called. 331 341 \begin{lstlisting} … … 364 374 365 375 The @exception_class@ argument is a copy of the 366 \code{C}{exception}'s @exception_class@ field .367 This a number that identifies the exception handling mechanism that created368 the 369 370 The \code{C}{exception} argument is a pointer to theuser376 \code{C}{exception}'s @exception_class@ field, 377 which is a number that identifies the exception handling mechanism that created 378 the \PAB{... missing text to end this sentence} 379 380 The \code{C}{exception} argument is a pointer to a user 371 381 provided storage object. It has two public fields: the @exception_class@, 372 382 which is described above, and the @exception_cleanup@ function. 373 The clean-up function is used by the EHM to clean-up the exception if it383 The clean-up function is used by the EHM to clean-up the exception, if it 374 384 should need to be freed at an unusual time, it takes an argument that says 375 385 why it had to be cleaned up. … … 382 392 messages for special cases (some of which should never be used by the 383 393 personality function) and error codes. However, unless otherwise noted, the 384 personality function shouldalways return @_URC_CONTINUE_UNWIND@.394 personality function always return @_URC_CONTINUE_UNWIND@. 385 395 386 396 \subsection{Raise Exception} 387 Raising an exception is the central function of libunwind and it performs a397 Raising an exception is the central function of libunwind and it performs the 388 398 two-staged unwinding. 389 399 \begin{cfa} … … 472 482 % catches. Talk about GCC nested functions. 473 483 474 \CFA termination exceptions use libunwind heavily because they match \Cpp484 \CFA termination exceptions use libunwind heavily because they match 475 485 \Cpp exceptions closely. The main complication for \CFA is that the 476 486 compiler generates C code, making it very difficult to generate the assembly to 477 form the LSDA for tryblocks or destructors.487 form the LSDA for @try@ blocks or destructors. 478 488 479 489 \subsection{Memory Management} … … 485 495 486 496 \begin{figure} 497 \centering 487 498 \input{exception-layout} 488 499 \caption{Exception Layout} … … 491 502 \todo*{Convert the exception layout to an actual diagram.} 492 503 493 Exceptions are stored in variable-sized blocks (see \vref{f:ExceptionLayout}).504 Exceptions are stored in variable-sized blocks (see Figure~\vref{f:ExceptionLayout}). 494 505 The first component is a fixed-sized data structure that contains the 495 506 information for libunwind and the exception system. The second component is an … … 498 509 @_Unwind_Exception@ to the entire node. 499 510 500 Multip e exceptions can exist at the same time because exceptions can be511 Multiple exceptions can exist at the same time because exceptions can be 501 512 raised inside handlers, destructors and finally blocks. 502 513 Figure~\vref{f:MultipleExceptions} shows a program that has multiple 503 514 exceptions active at one time. 504 515 Each time an exception is thrown and caught the stack unwinds and the finally 505 clause runs. This will throwanother exception (until @num_exceptions@ gets506 high enough) which must be allocated. The previous exceptions may not be516 clause runs. This handler throws another exception (until @num_exceptions@ gets 517 high enough), which must be allocated. The previous exceptions may not be 507 518 freed because the handler/catch clause has not been run. 508 So the EHM must keep themalive while it allocates exceptions for new throws.519 Therefore, the EHM must keep all of these exceptions alive while it allocates exceptions for new throws. 509 520 510 521 \begin{figure} … … 559 570 \todo*{Work on multiple exceptions code sample.} 560 571 561 All exceptions are stored in nodes which are then linked together in lists,572 All exceptions are stored in nodes, which are then linked together in lists 562 573 one list per stack, with the 563 574 list head stored in the exception context. Within each linked list, the most … … 566 577 exception is being handled. The exception at the head of the list is currently 567 578 being handled, while other exceptions wait for the exceptions before them to be 568 removed.579 handled and removed. 569 580 570 581 The virtual members in the exception's virtual table provide the size of the … … 573 584 exception into managed memory. After the exception is handled, the free 574 585 function is used to clean up the exception and then the entire node is 575 passed to free so the memory can be given backto the heap.586 passed to free so the memory is returned to the heap. 576 587 577 588 \subsection{Try Statements and Catch Clauses} 578 The trystatement with termination handlers is complex because it must579 compensate for the lack of assembly-code generatedfrom \CFA. Libunwind589 The @try@ statement with termination handlers is complex because it must 590 compensate for the C code-generation versus assembly-code generation from \CFA. Libunwind 580 591 requires an LSDA and personality function for control to unwind across a 581 592 function. The LSDA in particular is hard to mimic in generated C code. 582 593 583 594 The workaround is a function called @__cfaehm_try_terminate@ in the standard 584 library. The contents of a tryblock and the termination handlers are converted595 library. The contents of a @try@ block and the termination handlers are converted 585 596 into functions. These are then passed to the try terminate function and it 586 597 calls them. 587 598 Because this function is known and fixed (and not an arbitrary function that 588 happens to contain a trystatement), the LSDA can be generated ahead599 happens to contain a @try@ statement), the LSDA can be generated ahead 589 600 of time. 590 601 … … 592 603 embedded assembly. This assembly code is handcrafted using C @asm@ statements 593 604 and contains 594 enough information for the single try statement the function repersents.605 enough information for a single @try@ statement the function represents. 595 606 596 607 The three functions passed to try terminate are: 597 608 \begin{description} 598 \item[try function:] This function is the try block,all the code inside the599 try block is placed inside the tryfunction. It takes no parameters and has no609 \item[try function:] This function is the @try@ block, where all the code inside the 610 @try@ block is wrapped inside the function. It takes no parameters and has no 600 611 return value. This function is called during regular execution to run the try 601 612 block. … … 609 620 handler that matches the exception. 610 621 611 \item[handler function:] This function handles the exception. It takes a 622 \item[handler function:] This function handles the exception, where the code inside 623 is constructed by stitching together the bodies of 624 each handler of a @try@ statement and dispatches to the selected handler. 625 It takes a 612 626 pointer to the exception and the handler's id and returns nothing. It is called 613 after the cleanup phase. It is constructed by stitching together the bodies of 614 each handler and dispatches to the selected handler. 627 after the cleanup phase. 615 628 \end{description} 616 629 All three functions are created with GCC nested functions. GCC nested functions 617 can be used to create closures, functions that can refer to the state of other630 can be used to create closures, \ie functions that can refer to the state of other 618 631 functions on the stack. This approach allows the functions to refer to all the 619 632 variables in scope for the function containing the @try@ statement. These … … 623 636 Using this pattern, \CFA implements destructors with the cleanup attribute. 624 637 638 Figure~\ref{f:TerminationTransformation} shows an example transformation for a \CFA @try@ 639 statement with @catch@ clauses into corresponding C functions. \PAB{Walk the reader through the example code.} 640 625 641 \begin{figure} 626 642 \begin{cfa} … … 633 649 } 634 650 \end{cfa} 651 652 \medskip 653 \hrule 654 \medskip 635 655 636 656 \begin{cfa} … … 683 703 % The stack-local data, the linked list of nodes. 684 704 685 Resumption simpler to implement than termination705 Resumption is simpler to implement than termination 686 706 because there is no stack unwinding. 687 707 Instead of storing the data in a special area using assembly, 688 708 there is just a linked list of possible handlers for each stack, 689 with each node on the list reperenting a trystatement on the stack.709 with each list node representing a @try@ statement on the stack. 690 710 691 711 The head of the list is stored in the exception context. 692 The nodes are stored in order, with the more recent trystatements closer712 The nodes are stored in order, with the more recent @try@ statements closer 693 713 to the head of the list. 694 Instead of traversing the stack resumption handling traverses the list.695 At each node the EHM checks to see if the try statement the node repersents714 Instead of traversing the stack, resumption handling traverses the list. 715 At each node, the EHM checks to see if the @try@ statement it represents 696 716 can handle the exception. If it can, then the exception is handled and 697 717 the operation finishes, otherwise the search continues to the next node. 698 If the search reaches the end of the list without finding a trystatement699 that can handle the exception the default handler is executed and the718 If the search reaches the end of the list without finding a @try@ statement 719 that can handle the exception, the default handler is executed and the 700 720 operation finishes. 701 721 702 In each node is a handler function which does most of the work there. 703 The handler function is passed the raised the exception and returns true 704 if the exception is handled and false if it cannot be handled here. 705 706 For each @catchResume@ clause the handler function will: 707 check to see if the raised exception is a descendant type of the declared 708 exception type, if it is and there is a conditional expression then it will 709 run the test, if both checks pass the handling code for the clause is run 710 and the function returns true, otherwise it moves onto the next clause. 722 Each node has a handler function that does most of the work. 723 The handler function is passed the raised exception and returns true 724 if the exception is handled and false otherwise. 725 726 For each @catchResume@ clause, the handler function: 727 \begin{itemize} 728 \item 729 checks to see if the raised exception is a descendant type of the declared 730 exception type, 731 \item 732 if it is and there is a conditional expression then it 733 runs the test, 734 \item 735 if both checks pass the handling code for the clause is run and the function returns true, 736 \item 737 otherwise it moves onto the next clause. 738 \end{itemize} 711 739 If this is the last @catchResume@ clause then instead of moving onto 712 740 the next clause the function returns false as no handler could be found. 741 742 Figure~\ref{f:ResumptionTransformation} shows an example transformation for a \CFA @try@ 743 statement with @catchResume@ clauses into corresponding C functions. \PAB{Walk the reader through the example code.} 713 744 714 745 \begin{figure} … … 753 784 754 785 % Recursive Resumption Stuff: 755 Search skipping (see \vpageref{s:ResumptionMarking}), which ignores parts of786 Figure~\ref{f:ResumptionMarking} shows the search skipping (see \vpageref{s:ResumptionMarking}), which ignores parts of 756 787 the stack 757 788 already examined, is accomplished by updating the front of the list as the … … 759 790 is updated to the next node of the current node. After the search is complete, 760 791 successful or not, the head of the list is reset. 761 762 792 This mechanism means the current handler and every handler that has already 763 793 been checked are not on the list while a handler is run. If a resumption is 764 thrown during the handling of another resumption the active handlers and all794 thrown during the handling of another resumption, the active handlers and all 765 795 the other handler checked up to this point are not checked again. 766 767 This structure also supports new handler added while the resumption is being 796 This structure also supports new handlers added while the resumption is being 768 797 handled. These are added to the front of the list, pointing back along the 769 798 stack -- the first one points over all the checked handlers -- and the ordering 770 799 is maintained. 800 \PAB{Maybe number the figure and use the numbers in the description to help the reader follow.} 771 801 772 802 \begin{figure} … … 778 808 779 809 \label{p:zero-cost} 780 Note, the resumption implementation has a cost for entering/exiting a @try@810 Finally, the resumption implementation has a cost for entering/exiting a @try@ 781 811 statement with @catchResume@ clauses, whereas a @try@ statement with @catch@ 782 812 clauses has zero-cost entry/exit. While resumption does not need the stack … … 798 828 around the context of the associated @try@ statement. 799 829 800 The rest is handled by GCC. The tryblock and all handlers are inside this830 The rest is handled by GCC. The @try@ block and all handlers are inside this 801 831 block. At completion, control exits the block and the empty object is cleaned 802 832 up, which runs the function that contains the finally code. … … 812 842 coroutine or thread. Fortunately, the thread library stores the main thread 813 843 pointer and the current thread pointer, and every thread stores a pointer to 814 its main coroutine and the coroutine it is currently executing. 815 \todo*{Consider adding a description of how threads are coroutines.} 816 817 If a the current thread's main and current coroutines are the same then the 818 current stack is a thread stack. Furthermore it is easy to compare the 819 current thread to the main thread to see if they are the same. And if this 820 is not a thread stack then it must be a coroutine stack. 844 its coroutine and the coroutine it is currently executing. 845 If the current thread's main and current coroutines are the same then the 846 current stack is a thread stack, otherwise it is a coroutine stack. 847 Note, the runtime considers a thread as a coroutine with an associated user-level thread; 848 hence, for many operations a thread and coroutine are treated uniformly. 849 %\todo*{Consider adding a description of how threads are coroutines.} 850 851 % Furthermore it is easy to compare the 852 % current thread to the main thread to see if they are the same. And if this 853 % is not a thread stack then it must be a coroutine stack. 821 854 822 855 However, if the threading library is not linked, the sequential execution is on 823 856 the main stack. Hence, the entire check is skipped because the weak-symbol 824 function is loaded. Therefore, amain thread cancellation is unconditionally857 function is loaded. Therefore, main thread cancellation is unconditionally 825 858 performed. 826 859 827 860 Regardless of how the stack is chosen, the stop function and parameter are 828 861 passed to the forced-unwind function. The general pattern of all three stop 829 functions is the same: theycontinue unwinding until the end of stack and830 then p reform theirtransfer.862 functions is the same: continue unwinding until the end of stack and 863 then perform the appropriate transfer. 831 864 832 865 For main stack cancellation, the transfer is just a program abort. … … 834 867 For coroutine cancellation, the exception is stored on the coroutine's stack, 835 868 and the coroutine context switches to its last resumer. The rest is handled on 836 the backside of the resume, which check if the resumed coroutine is869 the backside of the resume, which checks if the resumed coroutine is 837 870 cancelled. If cancelled, the exception is retrieved from the resumed coroutine, 838 871 and a @CoroutineCancelled@ exception is constructed and loaded with the 839 872 cancelled exception. It is then resumed as a regular exception with the default 840 873 handler coming from the context of the resumption call. 874 This semantics allows a cancellation to cascade through an arbitrary set of resumed 875 coroutines back to the thread's coroutine, performing cleanup along the way. 841 876 842 877 For thread cancellation, the exception is stored on the thread's main stack and … … 848 883 null (as it is for the auto-generated joins on destructor call), the default is 849 884 used, which is a program abort. 885 This semantics allows a cancellation to cascade through an arbitrary set of joining 886 threads back to the program's main, performing cleanup along the way. 850 887 %; which gives the required handling on implicate join. -
doc/theses/andrew_beach_MMath/performance.tex
r1f05c83 r4f1b8f3f 6 6 7 7 Performance has been of secondary importance for most of this project. 8 The driving for has been to get the features working, the only performance 9 requirements were to make sure the tests for correctness rain in a reasonable 8 Instead, the goal has been to get the features working. 9 The only performance 10 requirements is to ensure the exception tests for correctness ran in a reasonable 10 11 amount of time. 11 Still this is an implementation others could use for similar prototypes and 12 so the results still have some use. 12 Much of the implementation is still reasonable and could be used for similar prototypes. 13 Hence, 14 the work still has some use. 15 To get a rough idea about the \CFA implementation, tests are run on \CFA, C++ and Java, which have similar termination-handling exceptions. 16 Tests are also run on \CFA and uC++, which has similar resumption-handling exceptions. 13 17 14 \section{Test Set-Up} 15 Tests will be run on \CFA, C++ and Java. 16 18 \section{Termination Comparison} 17 19 C++ is the most comparable language because both it and \CFA use the same 18 20 framework, libunwind. 19 In fact the comparison is almost entirely a quality of implementation21 In fact, the comparison is almost entirely a quality of implementation 20 22 comparison. \CFA's EHM has had significantly less time to be optimized and 21 23 does not generate its own assembly. It does have a slight advantage in that 22 24 there are some features it does not handle. 23 25 24 % Some languages I left out: 25 % Python: Its a scripting language, different 26 % uC++: Not well known and should the same results as C++, except for 27 % resumption which should be the same. 28 \todo{Can we find a good language to compare resumptions in.} 26 The Java comparison is an opportunity to compare a managed memory model with unmanaged, 27 to see if there are any effects related to the exception model. 29 28 30 All tests will be run inside a main loop which will perform the test 31 repeatedly. This is to avoid letting and start-up or tear-down time from 29 \subsection{Test Set-Up} 30 All tests are run inside a main loop that performs the test 31 repeatedly. This design avoids start-up or tear-down time from 32 32 affecting the timing results. 33 This also means that tests cannot terminate the program, which does limit33 A consequence is that tests cannot terminate the program, which does limit 34 34 how tests can be implemented. There are catch-alls to keep unhandled 35 exceptions from terminating t he program.35 exceptions from terminating tests. 36 36 37 The exceptions used in this test will always bea new exception based off of38 the base exception. This should minimize and preformance differences based37 The exceptions used in this test are always a new exception based off of 38 the base exception. This requirement minimizes performance differences based 39 39 on the object model. 40 Catch-alls will be done by catching the root exception type (not using \Cpp's40 Catch-alls are done by catching the root exception type (not using \Cpp's 41 41 \code{C++}{catch(...)}). 42 42 … … 44 44 hot. 45 45 46 \section{Tests} 46 \subsection{Tests} 47 The following tests capture the most important aspects of exception handling and should provide 48 a reasonable guide to programmers of where EHM costs occur. 49 47 50 \paragraph{Raise/Handle} 48 51 What is the basic cost to raise and handle an exception? 49 52 50 There are a number of factors that can effect this, for \CFA this includes 53 There are a number of factors that can effect this. 54 For \CFA this includes 51 55 the type of raise, 52 56 … … 61 65 This has the same set-up as the raise/handle test except the intermediate 62 66 stack frames contain either an object declaration with a destructor or a 63 try statement with no handlers except for a finallyclause.67 @try@ statement with no handlers except and a @finally@ clause. 64 68 65 69 \paragraph{Enter/Leave} … … 67 71 is thrown? 68 72 69 Th is is the simplist pattern to test as it is a simple matter of entering73 The test is a simple matter of entering 70 74 and leaving a try statement. 71 75 … … 74 78 75 79 \paragraph{Re-throw and Conditional-Catch} 76 How expen cive it is to run a non-exception type check for a handler?80 How expensive it is to run a non-exception type check for a handler? 77 81 78 82 In this case different languages approach this problem differently, either 79 83 through a re-throw or a conditional-catch. 80 Where \CFA uses its condition other languages will have tounconditionally84 Where \CFA uses its condition, other languages must unconditionally 81 85 catch the exception then re-throw if the condition if the condition is false. 82 86 … … 86 90 % We could do a Cforall test without the catch all and a new default handler 87 91 % that does a catch all. 88 As a point of comparison one of the raise/handle tests (which one?) has92 As a point of comparison, one of the raise/handle tests (which one?) has 89 93 same layout but never catches anything. 90 94 … … 100 104 %(I haven't actually figured out how to compare this, probably using something 101 105 %related to -fexceptions.) 106 107 108 \section{Resumption Comparison} 109 % Some languages I left out: 110 % Python: Its a scripting language, different 111 % uC++: Not well known and should the same results as C++, except for 112 % resumption which should be the same. 113 \todo{Can we find a good language to compare resumptions in.}
Note: See TracChangeset
for help on using the changeset viewer.