Changeset 0c4df43 for doc/theses/andrew_beach_MMath
- Timestamp:
- May 4, 2021, 2:04:26 PM (3 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 9d7e5cb
- Parents:
- 1716e1c
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/andrew_beach_MMath/implement.tex
r1716e1c r0c4df43 14 14 15 15 \subsection{Virtual Type} 16 Virtual types only have one change to their structure: the addition of a 17 pointer to the virtual table, called the \emph{virtual-table pointer}. 18 Internally, the field is called 19 @virtual_table@. 20 This constant pointer is always the first field of the table so when 21 casting to a supertype, the field's location is always known. 22 The field is initialized as part of all generated constructors. 16 Virtual types only have one change to their structure, the addition of a 17 pointer to the virtual table. This is always the first field so that 18 if it is cast to a supertype the field's location is still known. 19 20 This field is set as part of all new generated constructors. 23 21 \todo{They only come as part exceptions and don't work.} 24 %After the object is created the field is constant. 25 Dereferencing it gives the virtual table and access to the 22 After the object is created the field is constant. 23 24 However it can be read from, internally it is just a regular field called 25 @virtual_table@. Dereferencing it gives the virtual table and access to the 26 26 type's virtual members. 27 27 28 28 \subsection{Virtual Table} 29 % PAB: These 2 paragraphs are repeated below, and maybe some of the paragraph above, too. 30 \begin{comment} 31 Every time a virtual type is defined, a new virtual table-type is 32 instantiated. 33 The uniqueness of the virtual-table 34 instance is important because its address 35 is used as the identifier for the virtual type. Hence, a pointer to the 36 virtual table and the ID for the virtual type are interchangeable. 29 Every time a virtual type is defined the new virtual table type must also be 30 defined. 31 32 The unique instance is important because the address of the virtual table 33 instance is used as the identifier for the virtual type. So a pointer to the 34 virtual table and the ID for the virtual type are interchangable. 37 35 \todo{Unique instances might be going so we will have to talk about the new 38 36 system instead.} 39 37 40 The first step is creating the virtual-table type. 41 The virtual-table type is a structure and is described in terms of 42 its fields. The first field contains the parent-type ID (or a pointer to 43 the parent virtual-table) or 0 (null pointer). 44 Next are repeated fields from on the parent virtual-table. 45 Finally, the fields used to store any new virtual members of the new 46 the virtual type. 47 \end{comment} 48 49 %The virtual system is accessed through a private constant field inserted at the 50 %beginning of every virtual type. This field 51 The virtual-table pointer 52 points at a type's virtual table (see Figure~\vref{f:VirtualTableLayout}). 53 %and is assigned during the object's 54 %construction. 55 The address of a virtual table acts as the unique identifier for 38 The first step in putting it all together is to create the virtual table type. 39 The virtual table type is just a structure and can be described in terms of 40 its fields. The first field is always the parent type ID (or a pointer to 41 the parent virtual table) or 0 (the null pointer). 42 Next are other fields on the parent virtual table are repeated. 43 Finally are the fields used to store any new virtual members of the new 44 The virtual type 45 46 The virtual system is accessed through a private constant field inserted at the 47 beginning of every virtual type, called the virtual-table pointer. This field 48 points at a type's virtual table and is assigned during the object's 49 construction. The address of a virtual table acts as the unique identifier for 56 50 the virtual type, and the first field of a virtual table is a pointer to the 57 parent virtual-table or @0p@ (null pointer). The remaining fields are duplicated from the51 parent virtual-table or @0p@. The remaining fields are duplicated from the 58 52 parent tables in this type's inheritance chain, followed by any fields this type 59 introduces. Parent fields are duplicated so they can be changed, \ie all virtual 60 members are overridable, while the parent pointer allows access to the original values. 61 Hence, references to the dispatched type 53 introduces. Parent fields are duplicated so they can be changed (all virtual 54 members are overridable), so that references to the dispatched type 62 55 are replaced with the current virtual type. 63 56 % These are always taken by pointer or reference. 64 57 65 \begin{figure}66 58 % Simple ascii diragram: 67 \begin{ cfa}68 parent_pointer // \C{parent pointer to access its fields}69 parent_field0 // \C{same layout as parent to allow replacement}70 ... 71 parent_fieldN 72 child_field0 // \C{new types for this virtual table}59 \begin{verbatim} 60 parent_pointer \ 61 parent_field0 | 62 ... | Same layout as parent. 63 parent_fieldN / 64 child_field0 73 65 ... 74 66 child_fieldN 75 size 76 alignment 77 \end{cfa} 78 %\todo{Refine the diagram} 79 \caption{Virtual Table Layout} 80 \label{f:VirtualTableLayout} 81 \end{figure} 67 \end{verbatim} 68 \todo{Refine the diagram} 82 69 83 70 % For each virtual type, a virtual table is constructed. This is both a new type … … 86 73 % the type and the instance. 87 74 88 \begin{comment} 89 PAB: seems to be said already. 90 A virtual table is created when a virtual type is created. The name of the 75 A virtual table is created when the virtual type is created. The name of the 91 76 type is created by mangling the name of the base type. The name of the instance 92 77 is also generated by name mangling. The fields are initialized automatically. 93 78 The parent field is initialized by getting the type of the parent field and 94 using that to calculate the mangled name of the parent's virtual-table type. 95 \end{comment} 79 using that to calculate the mangled name of the parent's virtual table type. 96 80 There are two special fields that are included like normal fields but have 97 81 special initialization rules: the @size@ field is the type's size and is … … 102 86 103 87 These operations are split up into several groups depending on where they take 104 place ,which varies for monomorphic and polymorphic types. The first devision is88 place which varies for monomorphic and polymorphic types. The first devision is 105 89 between the declarations and the definitions. Declarations, such as a function 106 signature or a naggregate's name, must always be visible but may be repeated in90 signature or a aggregate's name, must always be visible but may be repeated in 107 91 the form of forward declarations in headers. Definitions, such as function 108 92 bodies and a aggregate's layout, can be separately compiled but must occur 109 93 exactly once in a source file. 110 94 111 The declarations include the virtual-type definition and forward declarations 112 of the virtual-table instance, constructor, message function and 95 \begin{sloppypar} 96 The declarations include the virtual type definition and forward declarations 97 of the virtual table instance, constructor, message function and 113 98 @get_exception_vtable@. The definition includes the storage and initialization 114 99 of the virtual table instance and the bodies of the three functions. 115 116 Monomorphic instances put all of these two groups in one place. 117 Polymorphic instances split out the core declarations and definitions from 118 the per-instance information. The virtual-table type and most of the functions 119 are polymorphic so they are all part of the core. The virtual-table instance 120 and the @get_exception_vtable@ function \PAB{ are ...}. 121 100 \end{sloppypar} 101 102 Monomorphic instances put all of these two groups in one place each. 103 Polymorphic instances also split out the core declarations and definitions from 104 the per-instance information. The virtual table type and most of the functions 105 are polymorphic so they are all part of the core. The virtual table instance 106 and the @get_exception_vtable@ function. 107 108 \begin{sloppypar} 122 109 Coroutines and threads need instances of @CoroutineCancelled@ and 123 110 @ThreadCancelled@ respectively to use all of their functionality. When a new 124 data type is declared with @coroutine@ or @thread@ ,the forward declaration for111 data type is declared with @coroutine@ or @thread@ the forward declaration for 125 112 the instance is created as well. The definition of the virtual table is created 126 113 at the definition of the main function. 127 128 \PAB{You need an example here to show what happens for this case.} 129 114 \end{sloppypar} 130 115 131 116 \subsection{Virtual Cast} … … 136 121 The function is 137 122 \begin{cfa} 138 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent, 123 void * __cfa__virtual_cast( 124 struct __cfa__parent_vtable const * parent, 139 125 struct __cfa__parent_vtable const * const * child ); 140 126 \end{cfa} 141 and it is implemented in the standard library. The structure represents the 142 head of a virtual table, which is the pointer to the parent virtual table. The 143 @parent@ points directly at the parent-type virtual-table, while the @child@ 144 points at the object of the (possible) child type. 145 146 \PAB{Need a figure to show this relationship.} 147 148 In terms of the virtual-cast expression, @parent@ comes from looking up the 127 and it is implemented in the standard library. The structure reperents the 128 head of a vtable which is the pointer to the parent virtual table. The 129 @parent@ points directly at the parent type virtual table while the @child@ 130 points at the object of the (possibe) child type. 131 132 In terms of the virtual cast expression, @parent@ comes from looking up the 149 133 type being cast to and @child@ is the result of the expression being cast. 150 Because the complier outputs C code, some C-type casts are also used.151 The last bit of glue is a map that saves every virtual type the compiler152 sees. This tableis used to check the type used in a virtual cast is a virtual134 Because the complier outputs C code, some type C type casts are also used. 135 The last bit of glue is an map that saves every virtual type the compiler 136 sees. This is used to check the type used in a virtual cast is a virtual 153 137 type and to get its virtual table. 154 138 (It also checks for conflicting definitions.) 155 139 156 \PAB{Can this be rolled into the figure above?} 157 158 Inside the function is a simple conditional. If the type represented by 159 @parent@ is an ancestor of the type represented by @*child@ (it 160 requires one more level of dereference to pass through the object) then @child@ 140 Inside the function it is a simple conditional. If the type repersented by 141 @parent@ is or is an ancestor of the type repersented by @*child@ (it 142 requires one more level of derefence to pass through the object) then @child@ 161 143 is returned, otherwise the null pointer is returned. 162 144 163 The check i s a simple linear search (like \Cpp RTTI). If the child164 virtual table or any of its ancestors (which are retr ieved through the first165 field of every virtual table) are the same as the parent virtual -table then145 The check itself is preformed is a simple linear search. If the child 146 virtual table or any of its ancestors (which are retreved through the first 147 field of every virtual table) are the same as the parent virtual table then 166 148 the cast succeeds. 167 149 … … 174 156 % resumption doesn't as well. 175 157 176 % Many modern languages work with an inter nal stack that function push and pop158 % Many modern languages work with an interal stack that function push and pop 177 159 % their local data to. Stack unwinding removes large sections of the stack, 178 160 % often across functions. 179 161 180 162 Stack unwinding is the process of removing stack frames (activations) from the 181 stack. On function entry and return, unwinding is handled directly by the c all/return code182 embedded in afunction. Usually, the stack-frame size is known statically163 stack. On function entry and return, unwinding is handled directly by the code 164 embedded in the function. Usually, the stack-frame size is known statically 183 165 based on parameter and local variable declarations. For dynamically-sized 184 local variables. 185 (Often called a variable-length array or VLA, even when the variable type is an aggregate.) 186 For VLAs, a runtime computation is necessary to know the frame 166 local variables, a runtime computation is necessary to know the frame 187 167 size. Finally, a function's frame-size may change during execution as local 188 variables (static or dynamic sized) go in and out of scope , which is a form of VLA.168 variables (static or dynamic sized) go in and out of scope. 189 169 Allocating/deallocating stack space is usually an $O(1)$ operation achieved by 190 170 bumping the hardware stack-pointer up or down as needed. 191 171 192 Unwinding across multiple stack frames is more complex because individual stack -management193 code associated with each frame can bebypassed. That is, the location172 Unwinding across multiple stack frames is more complex because individual stack 173 management code associated with each frame is bypassed. That is, the location 194 174 of a function's frame-management code is largely unknown and dispersed 195 175 throughout the function, hence the current frame size managed by that code is … … 211 191 reseting to a snap-shot of an arbitrary but existing function frame on the 212 192 stack. It is up to the programmer to ensure the snap-shot is valid when it is 213 reset and that unwound frames do not have side-effects. 214 Hence, this unwinding approach is fragile with potential errors that are 193 reset, making this unwinding approach fragile with potential errors that are 215 194 difficult to debug because the stack becomes corrupted. 216 195 217 With respect to stack side-effects, many languages define cleanup actions that must be taken when objects 218 are deallocated from the stack, when the function of blocks within the function end, such as running a variable's 219 destructor or a @try@ statement's @finally@ clause. 220 The purpose of these side-effects is to reestablish the global state of the program, such as dynamic memory-allocation or file access. 221 Handling these side-effect mechanisms 196 However, many languages define cleanup actions that must be taken when objects 197 are deallocated from the stack or blocks end, such as running a variable's 198 destructor or a @try@ statement's @finally@ clause. Handling these mechanisms 222 199 requires walking the stack and checking each stack frame for these potential 223 actions , where a frame can be any block with declarations.224 225 In languages like \Cpp and Java, it must be possible to walk the stack frames in search of @try@200 actions. 201 202 For exceptions, it must be possible to walk the stack frames in search of @try@ 226 203 statements to match and execute a handler. For termination exceptions, it must 227 204 also be possible to unwind all stack frames from the throw to the matching 228 catch (including the @try@ block), and each of these frames must be checked for cleanup actions. Stack205 catch, and each of these frames must be checked for cleanup actions. Stack 229 206 walking is where most of the complexity and expense of exception handling 230 207 appears. … … 249 226 LSDA can contain any information but conventionally it is a table with entries 250 227 representing regions of the function and what has to be done there during 251 unwinding. These regions are bracketed by instruction addresses. If the228 unwinding. These regions are bracketed by the instruction pointer. If the 252 229 instruction pointer is within a region's start/end, then execution is currently 253 230 executing in that region. Regions are used to mark out the scopes of objects … … 261 238 262 239 The GCC compilation flag @-fexceptions@ causes the generation of an LSDA and 263 attaches its personality function. 264 It attaches a series of opaque directives (@.cfi_personality@ directive) 265 used internally and not part of this work. 266 However, this 240 attaches its personality function. However, this 267 241 flag only handles the cleanup attribute: 242 \todo{Peter: What is attached? Andrew: It uses the .cfi\_personality directive 243 and that's all I know.} 268 244 \begin{cfa} 269 245 void clean_up( int * var ) { ... } 270 246 int avar __attribute__(( cleanup(clean_up) )); 271 247 \end{cfa} 272 that is used on a variable and specifies a function, in this case @clean_up@, 273 run when the variable goes out of scope, which is used to mimic destructors. 248 which is used on a variable and specifies a function, in this case @clean_up@, 249 run when the variable goes out of scope. 250 The function is passed a pointer to the object being removed from the stack 251 so it can be used to mimic destructors. 274 252 However, this feature cannot be used to mimic @try@ statements as it cannot 275 253 control the unwinding. … … 279 257 section covers some of the important parts of the interface. 280 258 281 A personality function can p erform different actions depending on how it is259 A personality function can preform different actions depending on how it is 282 260 called. 283 261 \begin{lstlisting}[language=C,{moredelim=**[is][\color{red}]{@}{@}}] … … 290 268 \end{lstlisting} 291 269 The @action@ argument is a bitmask of possible actions: 292 \begin{enumerate} [topsep=5pt]270 \begin{enumerate} 293 271 \item 294 272 @_UA_SEARCH_PHASE@ specifies a search phase and tells the personality function … … 313 291 @_UA_FORCE_UNWIND@ specifies a forced unwind call. Forced unwind only performs 314 292 the cleanup phase and uses a different means to decide when to stop 315 (see Section~\vref{s:ForcedUnwind}).293 (see \vref{s:ForcedUnwind}). 316 294 \end{enumerate} 317 295 318 296 The @exception_class@ argument is a copy of the 319 297 \lstinline[language=C]|exception|'s @exception_class@ field. 320 \PAB{Say more.}321 298 322 299 The \lstinline[language=C]|exception| argument is a pointer to the user 323 300 provided storage object. It has two public fields, the exception class, which 324 is just a number, identifying the exception handling mechanism that301 is actually just a number, identifying the exception handling mechanism that 325 302 created it, and the cleanup function. The cleanup function is called if 326 303 required by the exception. … … 332 309 that can be passed several places in libunwind. It includes a number of 333 310 messages for special cases (some of which should never be used by the 334 personality function) and error codes . However, unless otherwise noted,the311 personality function) and error codes but unless otherwise noted the 335 312 personality function should always return @_URC_CONTINUE_UNWIND@. 336 313 … … 347 324 @_URC_END_OF_STACK@. 348 325 349 Second, when a handler is matched, raise exception walks the stack again performingthe cleanup326 Second, when a handler is matched, raise exception continues onto the cleanup 350 327 phase. 351 328 Once again, it calls the personality functions of each stack frame from newest … … 361 338 Forced Unwind is the other central function in libunwind. 362 339 \begin{cfa} 363 _Unwind_Reason_Code _Unwind_ForcedUnwind( _Unwind_Exception *,340 _Unwind_Reason_Code _Unwind_ForcedUnwind( _Unwind_Exception *, 364 341 _Unwind_Stop_Fn, void *); 365 342 \end{cfa} … … 403 380 Each stack must have its own exception context. In a sequential \CFA program, 404 381 there is only one stack with a single global exception-context. However, when 405 the library @libcfathread@ is linked, there are multiple stacks ,where each382 the library @libcfathread@ is linked, there are multiple stacks where each 406 383 needs its own exception context. 407 384 408 The function @this_exception_context@ provides general access to the exception context. 409 For sequential execution, this function is defined as385 General access to the exception context is provided by function 386 @this_exception_context@. For sequential execution, this function is defined as 410 387 a weak symbol in the \CFA system-library, @libcfa@. When a \CFA program is 411 388 concurrent, it links with @libcfathread@, where this function is defined with a … … 413 390 414 391 The sequential @this_exception_context@ returns a hard-coded pointer to the 415 global ex ception context.392 global execption context. 416 393 The concurrent version adds the exception context to the data stored at the 417 base of each stack. When @this_exception_context@ is called ,it retrieves the394 base of each stack. When @this_exception_context@ is called it retrieves the 418 395 active stack and returns the address of the context saved there. 419 396 … … 422 399 % catches. Talk about GCC nested functions. 423 400 424 Termination exceptions use libunwind heavily because \CFA termination exceptions match425 \Cpp exceptions closely. The main complication for \CFA is that the401 Termination exceptions use libunwind heavily because it matches the intended 402 use from \Cpp exceptions closely. The main complication for \CFA is that the 426 403 compiler generates C code, making it very difficult to generate the assembly to 427 404 form the LSDA for try blocks or destructors. … … 430 407 The first step of a termination raise is to copy the exception into memory 431 408 managed by the exception system. Currently, the system uses @malloc@, rather 432 than reserved memory or the stack top. The exception -handling mechanism manages409 than reserved memory or the stack top. The exception handling mechanism manages 433 410 memory for the exception as well as memory for libunwind and the system's own 434 411 per-exception storage. 435 412 436 \begin{figure} 413 [Quick ASCII diagram to get started.] 437 414 \begin{verbatim} 438 415 Fixed Header | _Unwind_Exception <- pointer target … … 443 420 V ... 444 421 \end{verbatim} 445 \caption{Exception Layout} 446 \label{f:ExceptionLayout} 447 \end{figure} 448 449 Exceptions are stored in variable-sized blocks (see Figure~\vref{f:ExceptionLayout}). 450 The first component is a fixed-sized data-structure that contains the 422 423 Exceptions are stored in variable-sized blocks. 424 The first component is a fixed sized data structure that contains the 451 425 information for libunwind and the exception system. The second component is an 452 426 area of memory big enough to store the exception. Macros with pointer arthritic … … 454 428 @_Unwind_Exception@ to the entire node. 455 429 456 Multiple exceptions can exist because handlers can call functions that raise 457 exceptions. Figure~\vref{f:MultipleExceptions} shows a \Cpp program where 458 exceptions are handled, and then a function is called from the handler that 459 raises a new exception. The previous exception must persist because it is 460 unhandled, and hence, control can return to the handler and that exception is 461 reraised. 462 463 \begin{figure} 464 \centering 465 \newsavebox{\myboxA} 466 \newsavebox{\myboxB} 467 \begin{lrbox}{\myboxA} 468 \begin{lstlisting}[language=C++,{moredelim=**[is][\color{red}]{@}{@}}] 469 struct E {}; 470 int cnt = 3; 471 void f( int i ) { 472 if ( i == 0 ) @throw E();@ 473 try { 474 @f( i - 1 );@ 475 } catch( E ) { // handler h 476 cnt -= 1; 477 if ( cnt > 0 ) @f( 2 );@ 478 } 479 } 480 int main() { @f( 2 );@ } 481 \end{lstlisting} 482 \end{lrbox} 483 484 \begin{lrbox}{\myboxB} 485 \begin{lstlisting} 486 h $\makebox[0pt][l]{\textbackslash}f$ 487 f 488 f 489 h $\makebox[0pt][l]{\textbackslash}f$ throw E$\(_2\)$ 490 f 491 f 492 h $\makebox[0pt][l]{\textbackslash}f$ throw E$\(_1\)$ 493 f 494 f 495 \end{lstlisting} 496 \end{lrbox} 497 498 {\usebox\myboxA} 499 \hspace{25pt} 500 {\usebox\myboxB} 501 502 \caption{Multiple Exceptions} 503 \label{f:MultipleExceptions} 504 \end{figure} 505 506 In this case, the exception nodes are linked together in a list, one list per stack, with the 430 All of these nodes are linked together in a list, one list per stack, with the 507 431 list head stored in the exception context. Within each linked list, the most 508 432 recently thrown exception is at the head followed by older thrown … … 515 439 exception, the copy function, and the free function, so they are specific to an 516 440 exception type. The size and copy function are used immediately to copy an 517 exception into managed memory. After the exception is handled ,the free function441 exception into managed memory. After the exception is handled the free function 518 442 is used to clean up the exception and then the entire node is passed to free 519 443 so the memory can be given back to the heap. … … 521 445 \subsection{Try Statements and Catch Clauses} 522 446 The try statement with termination handlers is complex because it must 523 compensate for the lack of assembly 447 compensate for the lack of assembly-code generated from \CFA. Libunwind 524 448 requires an LSDA and personality function for control to unwind across a 525 449 function. The LSDA in particular is hard to mimic in generated C code. … … 530 454 calls them. 531 455 Because this function is known and fixed (and not an arbitrary function that 532 happens to contain a try statement) ,this means the LSDA can be generated ahead456 happens to contain a try statement) this means the LSDA can be generated ahead 533 457 of time. 534 458 535 459 Both the LSDA and the personality function are set ahead of time using 536 embedded assembly. This assembly codeis handcrafted using C @asm@ statements and contains537 enough information for the single try statement the function rep resents.460 embedded assembly. This is handcrafted using C @asm@ statements and contains 461 enough information for the single try statement the function repersents. 538 462 539 463 The three functions passed to try terminate are: … … 563 487 nested functions and all other functions besides @__cfaehm_try_terminate@ in 564 488 \CFA use the GCC personality function and the @-fexceptions@ flag to generate 565 the LSDA. Through this mechanism, \CFA destructors are implemented via the cleanup attribute. 566 567 \PAB{Try to put together an example try statement illustrating these components.} 489 the LSDA. This allows destructors to be implemented with the cleanup attribute. 568 490 569 491 \section{Resumption} 570 492 % The stack-local data, the linked list of nodes. 571 493 572 Resumption is simpler to implement than termination because there is no stack 573 unwinding. \PAB{You need to explain how the \lstinline{catchResume} clauses are 574 handled. Do you use the personality mechanism in libunwind or do you roll your 575 own mechanism?} 576 577 The 494 Resumption simple to implement because there is no stack unwinding. The 578 495 resumption raise uses a list of nodes for its stack traversal. The head of the 579 496 list is stored in the exception context. The nodes in the list have a pointer 580 497 to the next node and a pointer to the handler function. 498 581 499 A resumption raise traverses this list. At each node the handler function is 582 500 called, passing the exception by pointer. It returns true if the exception is … … 594 512 the stack 595 513 already examined, is accomplished by updating the front of the list as the 596 search continues. Before the handler at a node is called ,the head of the list514 search continues. Before the handler at a node is called the head of the list 597 515 is updated to the next node of the current node. After the search is complete, 598 516 successful or not, the head of the list is reset. … … 603 521 the other handler checked up to this point are not checked again. 604 522 605 This structure also supports new handler sadded while the resumption is being523 This structure also supports new handler added while the resumption is being 606 524 handled. These are added to the front of the list, pointing back along the 607 525 stack -- the first one points over all the checked handlers -- and the ordering 608 526 is maintained. 609 610 \PAB{Again, a figure to show how this works would be helpful.}611 527 612 528 \label{p:zero-cost} … … 623 539 % that unwind is required knowledge for that chapter. 624 540 625 \PAB{This paragraph needs to be moved to the start of this Section, where I have have my other comment.}626 627 541 \section{Finally} 628 542 % Uses destructors and GCC nested functions. 629 A finally clause is placed into a GCC nested-function with a unique mangledname, and no543 Finally clauses is placed into a GCC nested-function with a unique name, and no 630 544 arguments or return values. This nested function is then set as the cleanup 631 545 function of an empty object that is declared at the beginning of a block placed 632 around the context of anassociated @try@ statement.633 634 The rest is handled by GCC. The try block and all handlers are inside th is546 around the context of the associated @try@ statement. 547 548 The rest is handled by GCC. The try block and all handlers are inside the 635 549 block. At completion, control exits the block and the empty object is cleaned 636 550 up, which runs the function that contains the finally code. … … 640 554 641 555 Cancellation also uses libunwind to do its stack traversal and unwinding, 642 however it uses a different primary function ,@_Unwind_ForcedUnwind@. Details643 of its interface can be found in Section~\vref{s:ForcedUnwind}.556 however it uses a different primary function @_Unwind_ForcedUnwind@. Details 557 of its interface can be found in the \vref{s:ForcedUnwind}. 644 558 645 559 The first step of cancellation is to find the cancelled stack and its type: 646 coroutine or thread. Fortunately, the thread library stores the program-main thread 647 pointer and the current-thread pointer, and every thread stores a pointer to 648 the current coroutine it is executing. 649 650 \PAB{I don't know if my corrections in the previous paragraph are correct.} 651 652 When the active thread and coroutine are the same, the current stack is the thread stack, otherwise it is a coroutine 653 stack. 654 % PAB: repeated? 655 % If it is a thread stack, then an equality check with the stored main 656 % thread pointer and current thread pointer is enough to tell if the current 657 % thread is the main thread or not. 560 coroutine or thread. Fortunately, the thread library stores the main thread 561 pointer and the current thread pointer, and every thread stores a pointer to 562 its main coroutine and the coroutine it is currently executing. 563 564 So if the active thread's main and current coroutine are the same. If they 565 are then the current stack is a thread stack, otherwise it is a coroutine 566 stack. If it is a thread stack then an equality check with the stored main 567 thread pointer and current thread pointer is enough to tell if the current 568 thread is the main thread or not. 569 658 570 However, if the threading library is not linked, the sequential execution is on 659 571 the main stack. Hence, the entire check is skipped because the weak-symbol … … 663 575 Regardless of how the stack is chosen, the stop function and parameter are 664 576 passed to the forced-unwind function. The general pattern of all three stop 665 functions is the same: continue unwinding until the end of stack.666 %when they 667 %do there primary work. 577 functions is the same: they continue unwinding until the end of stack when they 578 do there primary work. 579 668 580 For main stack cancellation, the transfer is just a program abort. 669 581 670 For coroutine cancellation, the exception is stored in the coroutine's stack,582 For coroutine cancellation, the exception is stored on the coroutine's stack, 671 583 and the coroutine context switches to its last resumer. The rest is handled on 672 584 the backside of the resume, which check if the resumed coroutine is
Note: See TracChangeset
for help on using the changeset viewer.