Ignore:
Timestamp:
May 14, 2021, 4:03:12 PM (17 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
arm-eh, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
299b8b2
Parents:
0c4df43
Message:

Andrew MMath: First draft of the latest round of fixes to implement complete. More will be needed.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/andrew_beach_MMath/implement.tex

    r0c4df43 r9d7e5cb  
    1414
    1515\subsection{Virtual Type}
    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.
    21 \todo{They only come as part exceptions and don't work.}
    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 type's virtual members.
     16Virtual types only have one change to their structure: the addition of a
     17pointer to the virtual table, which is called the \emph{virtual-table pointer}.
     18Internally, the field is called @virtual_table@.
     19The field is fixed after construction. It is always the first field in the
     20structure so that its location is always known.
     21\todo{Talk about constructors for virtual types (after they are working).}
     22
     23This is what binds an instance of a virtual type to a virtual table. This
     24pointer can be used as an identity check. It can also be used to access the
     25virtual table and the virtual members there.
     26
     27\subsection{Type Id}
     28Every virtual type has a unique id.
     29Type ids can be compared for equality (the types reperented are the same)
     30or used to access the type's type information.
     31The type information currently is only the parent's type id or, if the
     32type has no parent, zero.
     33
     34The id's are implemented as pointers to the type's type information instance.
     35Derefencing the pointer gets the type information.
     36By going back-and-forth between the type id and
     37the type info one can find every ancestor of a virtual type.
     38It also pushes the issue of creating a unique value (for
     39the type id) to the problem of creating a unique instance (for type
     40information) which the linker can solve.
     41
     42Advanced linker support is required because there is no place that appears
     43only once to attach the type information to. There should be one structure
     44definition but it is included in multiple translation units. Each virtual
     45table definition should be unique but there are an arbitrary number of thoses.
     46So the special section prefix \texttt{.gnu.linkonce} is used.
     47With a unique suffix (making the entire section name unique) the linker will
     48remove multiple definition making sure only one version exists after linking.
     49Then it is just a matter of making sure there is a unique name for each type.
     50
     51This is done in three phases.
     52The first phase is to generate a new structure definition to store the type
     53information. The layout is the same in each case, just the parent's type id,
     54but the types are changed.
     55The structure's name is change, it is based off the virtual type's name, and
     56the type of the parent's type id.
     57If the virtual type is polymorphic then the type information structure is
     58polymorphic as well, with the same polymorphic arguments.
     59
     60The second phase is to generate an instance of the type information with a
     61almost unique name, generated by mangling the virtual type name.
     62
     63The third phase is implicit with \CFA's overloading scheme. \CFA mangles
     64names with type information so that all of the symbols exported to the linker
     65are unique even if in \CFA code they are the same. Having two declarations
     66with the same name and same type is forbidden because it is impossible for
     67overload resolution to pick between them. This is why a unique type is
     68generated for each virtual type.
     69Polymorphic information is included in this mangling so polymorphic
     70types will have seperate instances for each set of polymorphic arguments.
     71
     72\begin{cfa}
     73struct /* type name */ {
     74        /* parent type name */ const * parent;
     75};
     76
     77__attribute__((section(".gnu.linkonce./* instance name */")))
     78/* type name */ const /* instance name */ = {
     79        &/* parent instance name */,
     80};
     81\end{cfa}
    2782
    2883\subsection{Virtual Table}
    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.
    35 \todo{Unique instances might be going so we will have to talk about the new
    36 system instead.}
    37 
    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
    50 the virtual type, and the first field of a virtual table is a pointer to the
    51 parent virtual-table or @0p@. The remaining fields are duplicated from the
    52 parent tables in this type's inheritance chain, followed by any fields this 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
    55 are replaced with the current virtual type.
    56 % These are always taken by pointer or reference.
    57 
    58 % Simple ascii diragram:
    59 \begin{verbatim}
    60 parent_pointer  \
    61 parent_field0   |
    62 ...             | Same layout as parent.
    63 parent_fieldN   /
     84Each virtual type has a virtual table type that stores its type id and
     85virtual members.
     86Each virtual type instance is bound to a table instance that is filled with
     87the values of virtual members.
     88Both the layout of the fields and their value are decided by the rules given
     89below.
     90
     91The layout always comes in three parts.
     92The first section is just the type id at the head of the table. It is always
     93there to ensure that
     94The second section are all the virtual members of the parent, in the same
     95order as they appear in the parent's virtual table. Note that the type may
     96change slightly as references to the ``this" will change. This is limited to
     97inside pointers/references and via function pointers so that the size (and
     98hence the offsets) are the same.
     99The third section is similar to the second except that it is the new virtual
     100members introduced at this level in the hierarchy.
     101
     102\begin{figure}
     103\begin{cfa}
     104type_id
     105parent_field0
     106...
     107parent_fieldN
    64108child_field0
    65109...
    66110child_fieldN
    67 \end{verbatim}
    68 \todo{Refine the diagram}
    69 
    70 % For each virtual type, a virtual table is constructed. This is both a new type
    71 % and an instance of that type. Other instances of the type could be created
    72 % but the system doesn't use them. So this section will go over the creation of
    73 % the type and the instance.
    74 
    75 A virtual table is created when the virtual type is created. The name of the
    76 type is created by mangling the name of the base type. The name of the instance
    77 is also generated by name mangling. The fields are initialized automatically.
    78 The parent field is initialized by getting the type of the parent field and
    79 using that to calculate the mangled name of the parent's virtual table type.
    80 There are two special fields that are included like normal fields but have
    81 special initialization rules: the @size@ field is the type's size and is
    82 initialized with a @sizeof@ expression, the @align@ field is the type's
    83 alignment and uses an @alignof@ expression. The remaining fields are resolved
    84 to a name matching the field's name and type using the normal visibility and
    85 overload resolution rules of the type system.
    86 
    87 These operations are split up into several groups depending on where they take
    88 place which varies for monomorphic and polymorphic types. The first devision is
    89 between the declarations and the definitions. Declarations, such as a function
    90 signature or a aggregate's name, must always be visible but may be repeated in
    91 the form of forward declarations in headers. Definitions, such as function
    92 bodies and a aggregate's layout, can be separately compiled but must occur
    93 exactly once in a source file.
    94 
    95 \begin{sloppypar}
    96 The declarations include the virtual type definition and forward declarations
    97 of the virtual table instance, constructor, message function and
    98 @get_exception_vtable@. The definition includes the storage and initialization
    99 of the virtual table instance and the bodies of the three functions.
    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}
     111\end{cfa}
     112\caption{Virtual Table Layout}
     113\label{f:VirtualTableLayout}
     114\todo*{Improve the Virtual Table Layout diagram.}
     115\end{figure}
     116
     117The first and second sections together mean that every virtual table has a
     118prefix that has the same layout and types as its parent virtual table.
     119This, combined with the fixed offset to the virtual table pointer, means that
     120for any virtual type it doesn't matter if we have it or any of its
     121descendants, it is still always safe to access the virtual table through
     122the virtual table pointer.
     123From there it is safe to check the type id to identify the exact type of the
     124underlying object, access any of the virtual members and pass the object to
     125any of the method-like virtual members.
     126\todo{Introduce method-like virtual members.}
     127
     128When a virtual table is declared the user decides where to declare it and its
     129name. The initialization of the virtual table is entirely automatic based on
     130the context of the declaration.
     131
     132The type id is always fixed, each virtual table type will always have one
     133exactly one possible type id.
     134The virtual members are usually filled in by resolution. The best match for
     135a given name and type at the declaration site is filled in.
     136There are two exceptions to that rule: the @size@ field is the type's size
     137and is set to the result of a @sizeof@ expression, the @align@ field is the
     138type's alignment and similarly uses an @alignof@ expression.
     139
     140\subsubsection{Concurrency Integration}
    109141Coroutines and threads need instances of @CoroutineCancelled@ and
    110142@ThreadCancelled@ respectively to use all of their functionality. When a new
     
    112144the instance is created as well. The definition of the virtual table is created
    113145at the definition of the main function.
    114 \end{sloppypar}
     146\todo{Add an example with code snipits.}
    115147
    116148\subsection{Virtual Cast}
     
    119151% The C-cast is just to make sure the generated code is correct so the rest of
    120152% the section is about that function.
    121 The function is
     153The function is implemented in the standard library and has the following
     154signature:
    122155\begin{cfa}
    123156void * __cfa__virtual_cast(
     
    125158        struct __cfa__parent_vtable const * const * child );
    126159\end{cfa}
    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
    133 type being cast to and @child@ is the result of the expression being cast.
    134 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
    137 type and to get its virtual table.
    138 (It also checks for conflicting definitions.)
    139 
    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@
    143 is returned, otherwise the null pointer is returned.
    144 
    145 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
    148 the cast succeeds.
     160\todo{Get rid of \_\_cfa\_\_parent\_vtable in the standard library and then
     161the document.}
     162The type id of target type of the virtual cast is passed in as @parent@ and
     163the cast target is passed in as @child@.
     164
     165For C generation both arguments and the result are wrapped with type casts.
     166There is also an internal store inside the compiler to make sure that the
     167target type is a virtual type.
     168% It also checks for conflicting definitions.
     169
     170The virtual cast either returns the original pointer as a new type or null.
     171So the function just does the parent check and returns the approprate value.
     172The parent check is a simple linear search of child's ancestors using the
     173type information.
    149174
    150175\section{Exceptions}
     
    161186
    162187Stack unwinding is the process of removing stack frames (activations) from the
    163 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
    165 based on parameter and local variable declarations. For dynamically-sized
    166 local variables, a runtime computation is necessary to know the frame
    167 size. Finally, a function's frame-size may change during execution as local
    168 variables (static or dynamic sized) go in and out of scope.
     188stack. On function entry and return, unwinding is handled directly by the
     189call/return code embedded in the function.
     190In many cases the position of the instruction pointer (relative to parameter
     191and local declarations) is enough to know the current size of the stack
     192frame.
     193
     194Usually, the stack-frame size is known statically based on parameter and
     195local variable declarations. Even with dynamic stack-size the information
     196to determain how much of the stack has to be removed is still contained
     197within the function.
    169198Allocating/deallocating stack space is usually an $O(1)$ operation achieved by
    170199bumping the hardware stack-pointer up or down as needed.
    171 
    172 Unwinding across multiple stack frames is more complex because individual stack
    173 management code associated with each frame is bypassed. That is, the location
    174 of a function's frame-management code is largely unknown and dispersed
    175 throughout the function, hence the current frame size managed by that code is
    176 also unknown. Hence, code unwinding across frames does not have direct
    177 knowledge about what is on the stack, and hence, how much of the stack needs to
    178 be removed.
    179 
    180 % At a very basic level this can be done with @setjmp@ \& @longjmp@ which simply
    181 % move the top of the stack, discarding everything on the stack above a certain
    182 % point. However this ignores all the cleanup code that should be run when
    183 % certain sections of the stack are removed (for \CFA these are from destructors
    184 % and finally clauses) and also requires that the point to which the stack is
    185 % being unwound is known ahead of time. libunwind is used to address both of
    186 % these problems.
     200Constructing/destructing values on the stack takes longer put in terms of
     201figuring out what needs to be done is of similar complexity.
     202
     203Unwinding across multiple stack frames is more complex because that
     204information is no longer contained within the current function.
     205With seperate compilation a function has no way of knowing what its callers
     206are so it can't know how large those frames are.
     207Without altering the main code path it is also hard to pass that work off
     208to the caller.
    187209
    188210The traditional unwinding mechanism for C is implemented by saving a snap-shot
     
    191213reseting to a snap-shot of an arbitrary but existing function frame on the
    192214stack. It is up to the programmer to ensure the snap-shot is valid when it is
    193 reset, making this unwinding approach fragile with potential errors that are
    194 difficult to debug because the stack becomes corrupted.
    195 
    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
    199 requires walking the stack and checking each stack frame for these potential
    200 actions.
    201 
    202 For exceptions, it must be possible to walk the stack frames in search of @try@
    203 statements to match and execute a handler. For termination exceptions, it must
    204 also be possible to unwind all stack frames from the throw to the matching
    205 catch, and each of these frames must be checked for cleanup actions. Stack
    206 walking is where most of the complexity and expense of exception handling
    207 appears.
     215reset and that all required clean-up from the unwound stacks is preformed.
     216This approach is fragile and forces a work onto the surounding code.
     217
     218With respect to that work forced onto the surounding code,
     219many languages define clean-up actions that must be taken when certain
     220sections of the stack are removed. Such as when the storage for a variable
     221is removed from the stack or when a try statement with a finally clause is
     222(conceptually) popped from the stack.
     223None of these should be handled by the user, that would contradict the
     224intention of these features, so they need to be handled automatically.
     225
     226To safely remove sections of the stack the language must be able to find and
     227run these clean-up actions even when removing multiple functions unknown at
     228the beginning of the unwinding.
    208229
    209230One of the most popular tools for stack management is libunwind, a low-level
     
    226247LSDA can contain any information but conventionally it is a table with entries
    227248representing regions of the function and what has to be done there during
    228 unwinding. These regions are bracketed by the instruction pointer. If the
     249unwinding. These regions are bracketed by instruction addresses. If the
    229250instruction pointer is within a region's start/end, then execution is currently
    230251executing in that region. Regions are used to mark out the scopes of objects
     
    238259
    239260The GCC compilation flag @-fexceptions@ causes the generation of an LSDA and
    240 attaches its personality function. However, this
     261attaches a personality function to each function.
     262In plain C (which \CFA currently compiles down to) this
    241263flag 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.}
    244264\begin{cfa}
    245265void clean_up( int * var ) { ... }
    246266int avar __attribute__(( cleanup(clean_up) ));
    247267\end{cfa}
    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.
    252 However, this feature cannot be used to mimic @try@ statements as it cannot
    253 control the unwinding.
     268The attribue is used on a variable and specifies a function,
     269in this case @clean_up@, run when the variable goes out of scope.
     270This is enough to mimic destructors, but not try statements which can effect
     271the unwinding.
     272
     273To get full unwinding support all of this has to be done directly with
     274assembly and assembler directives. Partiularly the cfi directives
     275\texttt{.cfi\_lsda} and \texttt{.cfi\_personality}.
    254276
    255277\subsection{Personality Functions}
     
    268290\end{lstlisting}
    269291The @action@ argument is a bitmask of possible actions:
    270 \begin{enumerate}
     292\begin{enumerate}[topsep=5pt]
    271293\item
    272294@_UA_SEARCH_PHASE@ specifies a search phase and tells the personality function
     
    295317
    296318The @exception_class@ argument is a copy of the
    297 \lstinline[language=C]|exception|'s @exception_class@ field.
    298 
    299 The \lstinline[language=C]|exception| argument is a pointer to the user
    300 provided storage object. It has two public fields, the exception class, which
    301 is actually just a number, identifying the exception handling mechanism that
    302 created it, and the cleanup function. The cleanup function is called if
    303 required by the exception.
     319\code{C}{exception}'s @exception_class@ field.
     320This a number that identifies the exception handling mechanism that created
     321the
     322
     323The \code{C}{exception} argument is a pointer to the user
     324provided storage object. It has two public fields: the @exception_class@,
     325which is described above, and the @exception_cleanup@ function.
     326The clean-up function is used by the EHM to clean-up the exception if it
     327should need to be freed at an unusual time, it takes an argument that says
     328why it had to be cleaned up.
    304329
    305330The @context@ argument is a pointer to an opaque type passed to helper
     
    309334that can be passed several places in libunwind. It includes a number of
    310335messages for special cases (some of which should never be used by the
    311 personality function) and error codes but unless otherwise noted the
     336personality function) and error codes. However, unless otherwise noted, the
    312337personality function should always return @_URC_CONTINUE_UNWIND@.
    313338
     
    324349@_URC_END_OF_STACK@.
    325350
    326 Second, when a handler is matched, raise exception continues onto the cleanup
    327 phase.
     351Second, when a handler is matched, raise exception moves to the clean-up
     352phase and walks the stack a second time.
    328353Once again, it calls the personality functions of each stack frame from newest
    329354to oldest. This pass stops at the stack frame containing the matching handler.
     
    338363Forced Unwind is the other central function in libunwind.
    339364\begin{cfa}
    340 _Unwind_Reason_Code _Unwind_ForcedUnwind( _Unwind_Exception *,
     365_Unwind_Reason_Code _Unwind_ForcedUnwind(_Unwind_Exception *,
    341366        _Unwind_Stop_Fn, void *);
    342367\end{cfa}
     
    380405Each stack must have its own exception context. In a sequential \CFA program,
    381406there is only one stack with a single global exception-context. However, when
    382 the library @libcfathread@ is linked, there are multiple stacks where each
     407the library @libcfathread@ is linked, there are multiple stacks and each
    383408needs its own exception context.
    384409
    385 General access to the exception context is provided by function
     410The exception context should be retrieved by calling the function
    386411@this_exception_context@. For sequential execution, this function is defined as
    387412a weak symbol in the \CFA system-library, @libcfa@. When a \CFA program is
     
    390415
    391416The sequential @this_exception_context@ returns a hard-coded pointer to the
    392 global execption context.
     417global exception context.
    393418The concurrent version adds the exception context to the data stored at the
    394 base of each stack. When @this_exception_context@ is called it retrieves the
     419base of each stack. When @this_exception_context@ is called, it retrieves the
    395420active stack and returns the address of the context saved there.
    396421
     
    399424% catches. Talk about GCC nested functions.
    400425
    401 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\CFA termination exceptions use libunwind heavily because they match \Cpp
     427\Cpp exceptions closely. The main complication for \CFA is that the
    403428compiler generates C code, making it very difficult to generate the assembly to
    404429form the LSDA for try blocks or destructors.
     
    411436per-exception storage.
    412437
    413 [Quick ASCII diagram to get started.]
     438\begin{figure}
    414439\begin{verbatim}
    415440Fixed Header  | _Unwind_Exception   <- pointer target
     
    420445              V ...
    421446\end{verbatim}
    422 
    423 Exceptions are stored in variable-sized blocks.
    424 The first component is a fixed sized data structure that contains the
     447\caption{Exception Layout}
     448\label{f:ExceptionLayout}
     449\end{figure}
     450\todo*{Convert the exception layout to an actual diagram.}
     451
     452Exceptions are stored in variable-sized blocks (see \vref{f:ExceptionLayout}).
     453The first component is a fixed-sized data structure that contains the
    425454information for libunwind and the exception system. The second component is an
    426455area of memory big enough to store the exception. Macros with pointer arthritic
     
    428457@_Unwind_Exception@ to the entire node.
    429458
    430 All of these nodes are linked together in a list, one list per stack, with the
     459Multipe exceptions can exist at the same time because exceptions can be
     460raised inside handlers, destructors and finally blocks.
     461Figure~\vref{f:MultipleExceptions} shows a program that has multiple
     462exceptions active at one time.
     463Each time an exception is thrown and caught the stack unwinds and the finally
     464clause runs. This will throw another exception (until @num_exceptions@ gets
     465high enough) which must be allocated. The previous exceptions may not be
     466freed because the handler/catch clause has not been run.
     467So the EHM must keep them alive while it allocates exceptions for new throws.
     468
     469\begin{figure}
     470\centering
     471% Andrew: Figure out what these do and give them better names.
     472\newsavebox{\myboxA}
     473\newsavebox{\myboxB}
     474\begin{lrbox}{\myboxA}
     475\begin{lstlisting}[language=CFA,{moredelim=**[is][\color{red}]{@}{@}}]
     476unsigned num_exceptions = 0;
     477void throws() {
     478    try {
     479        try {
     480            ++num_exceptions;
     481            throw (Example){table};
     482        } finally {
     483            if (num_exceptions < 3) {
     484                throws();
     485            }
     486        }
     487    } catch (exception_t *) {
     488        --num_exceptions;
     489    }
     490}
     491int main() {
     492    throws();
     493}
     494\end{lstlisting}
     495\end{lrbox}
     496
     497\begin{lrbox}{\myboxB}
     498\begin{lstlisting}
     499\end{lstlisting}
     500\end{lrbox}
     501
     502{\usebox\myboxA}
     503\hspace{25pt}
     504{\usebox\myboxB}
     505
     506\caption{Multiple Exceptions}
     507\label{f:MultipleExceptions}
     508\end{figure}
     509\todo*{Work on multiple exceptions code sample.}
     510
     511All exceptions are stored in nodes which are then linked together in lists,
     512one list per stack, with the
    431513list head stored in the exception context. Within each linked list, the most
    432514recently thrown exception is at the head followed by older thrown
     
    439521exception, the copy function, and the free function, so they are specific to an
    440522exception type. The size and copy function are used immediately to copy an
    441 exception into managed memory. After the exception is handled the free function
    442 is used to clean up the exception and then the entire node is passed to free
    443 so the memory can be given back to the heap.
     523exception into managed memory. After the exception is handled, the free
     524function is used to clean up the exception and then the entire node is
     525passed to free so the memory can be given back to the heap.
    444526
    445527\subsection{Try Statements and Catch Clauses}
     
    454536calls them.
    455537Because this function is known and fixed (and not an arbitrary function that
    456 happens to contain a try statement) this means the LSDA can be generated ahead
     538happens to contain a try statement), the LSDA can be generated ahead
    457539of time.
    458540
    459541Both the LSDA and the personality function are set ahead of time using
    460 embedded assembly. This is handcrafted using C @asm@ statements and contains
     542embedded assembly. This assembly code is handcrafted using C @asm@ statements
     543and contains
    461544enough information for the single try statement the function repersents.
    462545
     
    487570nested functions and all other functions besides @__cfaehm_try_terminate@ in
    488571\CFA use the GCC personality function and the @-fexceptions@ flag to generate
    489 the LSDA. This allows destructors to be implemented with the cleanup attribute.
     572the LSDA.
     573Using this pattern, \CFA implements destructors with the cleanup attribute.
     574\todo{Add an example of the conversion from try statement to functions.}
    490575
    491576\section{Resumption}
    492577% The stack-local data, the linked list of nodes.
    493578
    494 Resumption simple to implement because there is no stack unwinding. The
    495 resumption raise uses a list of nodes for its stack traversal. The head of the
    496 list is stored in the exception context. The nodes in the list have a pointer
    497 to the next node and a pointer to the handler function.
    498 
    499 A resumption raise traverses this list. At each node the handler function is
    500 called, passing the exception by pointer. It returns true if the exception is
    501 handled and false otherwise.
    502 
    503 The handler function does both the matching and handling. It computes the
    504 condition of each @catchResume@ in top-to-bottom order, until it finds a
    505 handler that matches. If no handler matches then the function returns
    506 false. Otherwise the matching handler is run; if it completes successfully, the
    507 function returns true. Rethrowing, through the @throwResume;@ statement,
    508 causes the function to return true.
     579Resumption simpler to implement than termination
     580because there is no stack unwinding.
     581Instead of storing the data in a special area using assembly,
     582there is just a linked list of possible handlers for each stack,
     583with each node on the list reperenting a try statement on the stack.
     584
     585The head of the list is stored in the exception context.
     586The nodes are stored in order, with the more recent try statements closer
     587to the head of the list.
     588Instead of traversing the stack resumption handling traverses the list.
     589At each node the EHM checks to see if the try statement the node repersents
     590can handle the exception. If it can, then the exception is handled and
     591the operation finishes, otherwise the search continues to the next node.
     592If the search reaches the end of the list without finding a try statement
     593that can handle the exception the default handler is executed and the
     594operation finishes.
     595
     596In each node is a handler function which does most of the work there.
     597The handler function is passed the raised the exception and returns true
     598if the exception is handled and false if it cannot be handled here.
     599
     600For each @catchResume@ clause the handler function will:
     601check to see if the raised exception is a descendant type of the declared
     602exception type, if it is and there is a conditional expression then it will
     603run the test, if both checks pass the handling code for the clause is run
     604and the function returns true, otherwise it moves onto the next clause.
     605If this is the last @catchResume@ clause then instead of moving onto
     606the next clause the function returns false as no handler could be found.
     607
     608\todo{Diagram showing a try statement being converted into resumption handlers.}
    509609
    510610% Recursive Resumption Stuff:
     
    512612the stack
    513613already examined, is accomplished by updating the front of the list as the
    514 search continues. Before the handler at a node is called the head of the list
     614search continues. Before the handler at a node is called, the head of the list
    515615is updated to the next node of the current node. After the search is complete,
    516616successful or not, the head of the list is reset.
     
    525625stack -- the first one points over all the checked handlers -- and the ordering
    526626is maintained.
     627\todo{Add a diagram for resumption marking.}
    527628
    528629\label{p:zero-cost}
     
    541642\section{Finally}
    542643% Uses destructors and GCC nested functions.
    543 Finally clauses is placed into a GCC nested-function with a unique name, and no
    544 arguments or return values. This nested function is then set as the cleanup
     644A finally clause is placed into a GCC nested-function with a unique name,
     645and no arguments or return values.
     646This nested function is then set as the cleanup
    545647function of an empty object that is declared at the beginning of a block placed
    546648around the context of the associated @try@ statement.
    547649
    548 The rest is handled by GCC. The try block and all handlers are inside the
     650The rest is handled by GCC. The try block and all handlers are inside this
    549651block. At completion, control exits the block and the empty object is cleaned
    550652up, which runs the function that contains the finally code.
     
    554656
    555657Cancellation also uses libunwind to do its stack traversal and unwinding,
    556 however it uses a different primary function @_Unwind_ForcedUnwind@. Details
    557 of its interface can be found in the \vref{s:ForcedUnwind}.
     658however it uses a different primary function: @_Unwind_ForcedUnwind@. Details
     659of its interface can be found in the Section~\vref{s:ForcedUnwind}.
    558660
    559661The first step of cancellation is to find the cancelled stack and its type:
     
    561663pointer and the current thread pointer, and every thread stores a pointer to
    562664its 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.
     665\todo*{Consider adding a description of how threads are coroutines.}
     666
     667If a the current thread's main and current coroutines are the same then the
     668current stack is a thread stack. Furthermore it is easy to compare the
     669current thread to the main thread to see if they are the same. And if this
     670is not a thread stack then it must be a coroutine stack.
    569671
    570672However, if the threading library is not linked, the sequential execution is on
     
    575677Regardless of how the stack is chosen, the stop function and parameter are
    576678passed to the forced-unwind function. The general pattern of all three stop
    577 functions is the same: they continue unwinding until the end of stack when they
    578 do there primary work.
     679functions is the same: they continue unwinding until the end of stack and
     680then preform their transfer.
    579681
    580682For main stack cancellation, the transfer is just a program abort.
Note: See TracChangeset for help on using the changeset viewer.