Ignore:
Timestamp:
Aug 14, 2017, 2:03:39 PM (8 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
74b007ba
Parents:
fd344aa (diff), 54cd58b0 (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.
Message:

Merge branch 'master' into references

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/libcfa/exception.c

    rfd344aa r9236060  
    1010// Created On       : Mon Jun 26 15:13:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tus Jul 11 16:36:00 2017
    13 // Update Count     : 1
     12// Last Modified On : Fri Aug  4 15:20:00 2017
     13// Update Count     : 6
    1414//
     15
     16#include <stddef.h> // for size_t
    1517
    1618#include "exception.h"
     
    2224#include <unwind.h>
    2325
     26// FIX ME: temporary hack to keep ARM build working
     27#ifndef _URC_FATAL_PHASE1_ERROR
     28#define _URC_FATAL_PHASE1_ERROR 2
     29#endif // ! _URC_FATAL_PHASE1_ERROR
     30#ifndef _URC_FATAL_PHASE2_ERROR
     31#define _URC_FATAL_PHASE2_ERROR 2
     32#endif // ! _URC_FATAL_PHASE2_ERROR
     33
    2434#include "lsda.h"
    2535
     36
     37// Base exception vtable is abstract, you should not have base exceptions.
     38struct __cfaehm__base_exception_t_vtable
     39                ___cfaehm__base_exception_t_vtable_instance = {
     40        .parent = NULL,
     41        .size = 0,
     42        .copy = NULL,
     43        .free = NULL,
     44        .msg = NULL
     45};
     46
     47
    2648// Temperary global exception context. Does not work with concurency.
    27 struct shared_stack_t {
     49struct exception_context_t {
    2850    struct __cfaehm__try_resume_node * top_resume;
    2951    struct __cfaehm__try_resume_node * current_resume;
    3052
    31     exception current_exception;
     53    exception * current_exception;
    3254    int current_handler_index;
    3355} shared_stack = {NULL, NULL, 0, 0};
    3456
    35 
    36 
    37 // This macro should be the only thing that needs to change across machines.
    38 // Used in the personality function, way down in termination.
     57// Get the current exception context.
     58// There can be a single global until multithreading occurs, then each stack
     59// needs its own. It will have to be updated to handle that.
     60struct exception_context_t * this_exception_context() {
     61        return &shared_stack;
     62}
     63//#define SAVE_EXCEPTION_CONTEXT(to_name)
     64//struct exception_context_t * to_name = this_exception_context();
     65//exception * this_exception() {
     66//    return this_exception_context()->current_exception;
     67//}
     68
     69
     70// This macro should be the only thing that needs to change across machines.  Used in the personality function, way down
     71// in termination.
    3972// struct _Unwind_Context * -> _Unwind_Reason_Code(*)(exception *)
    4073#define MATCHER_FROM_CONTEXT(ptr_to_context) \
     
    4780
    4881        // DEBUG
    49         printf("Throwing resumption exception %d\n", *except);
     82        printf("Throwing resumption exception\n");
    5083
    5184        struct __cfaehm__try_resume_node * original_head = shared_stack.current_resume;
     
    6194        }
    6295
    63         printf("Unhandled exception %d\n", *except);
     96        printf("Unhandled exception\n");
    6497        shared_stack.current_resume = original_head;
    6598
     
    69102}
    70103
    71 /* Do we control where exceptions get thrown even with concurency?
    72  * If not these are not quite thread safe, the cleanup hook has to be added
    73  * after the node is built but before it is made the top node.
    74  */
     104// Do we control where exceptions get thrown even with concurency?  If not these are not quite thread safe, the cleanup
     105// hook has to be added after the node is built but before it is made the top node.
     106
    75107void __cfaehm__try_resume_setup(struct __cfaehm__try_resume_node * node,
    76108                        int (*handler)(exception * except)) {
     
    87119// TERMINATION ===============================================================
    88120
    89 // Requires -fexceptions to work.
    90 
    91 // Global which defines the current exception
    92 // Currently an int just to make matching easier
    93 //int this_exception; (became shared_stack.current_exception)
     121// MEMORY MANAGEMENT (still for integers)
     122// May have to move to cfa for constructors and destructors (references).
     123
     124struct __cfaehm__node {
     125        struct __cfaehm__node * next;
     126};
     127
     128#define NODE_TO_EXCEPT(node) ((exception *)(1 + (node)))
     129#define EXCEPT_TO_NODE(except) ((struct __cfaehm__node *)(except) - 1)
     130
     131// Creates a copy of the indicated exception and sets current_exception to it.
     132static void __cfaehm__allocate_exception( exception * except ) {
     133        struct exception_context_t * context = this_exception_context();
     134
     135        // Allocate memory for the exception.
     136        struct __cfaehm__node * store = malloc(
     137                sizeof( struct __cfaehm__node ) + except->virtual_table->size );
     138
     139        if ( ! store ) {
     140                // Failure: cannot allocate exception. Terminate thread.
     141                abort(); // <- Although I think it might be the process.
     142        }
     143
     144        // Add the node to the list:
     145        store->next = EXCEPT_TO_NODE(context->current_exception);
     146        context->current_exception = NODE_TO_EXCEPT(store);
     147
     148        // Copy the exception to storage.
     149        except->virtual_table->copy( context->current_exception, except );
     150}
     151
     152// Delete the provided exception, unsetting current_exception if relivant.
     153static void __cfaehm__delete_exception( exception * except ) {
     154        struct exception_context_t * context = this_exception_context();
     155
     156        // DEBUG
     157        printf( "Deleting Exception\n");
     158
     159        // Remove the exception from the list.
     160        struct __cfaehm__node * to_free = EXCEPT_TO_NODE(except);
     161        struct __cfaehm__node * node;
     162
     163        if ( context->current_exception == except ) {
     164                node = to_free->next;
     165                context->current_exception = (node) ? NODE_TO_EXCEPT(node) : 0;
     166        } else {
     167                node = EXCEPT_TO_NODE(context->current_exception);
     168                // It may always be in the first or second position.
     169                while( to_free != node->next ) {
     170                        node = node->next;
     171                }
     172                node->next = to_free->next;
     173        }
     174
     175        // Free the old exception node.
     176        except->virtual_table->free( except );
     177        free( to_free );
     178}
     179
     180// If this isn't a rethrow (*except==0), delete the provided exception.
     181void __cfaehm__cleanup_terminate( void * except ) {
     182        if ( *(void**)except ) __cfaehm__delete_exception( *(exception**)except );
     183}
     184
    94185
    95186// We need a piece of storage to raise the exception
     
    111202}
    112203
    113 void __cfaehm__throw_terminate( exception * val ) {
    114         // Store the current exception
    115         shared_stack.current_exception = *val;
    116 
    117         // DEBUG
    118         printf("Throwing termination exception %d\n", *val);
     204// The exception that is being thrown must already be stored.
     205__attribute__((noreturn)) void __cfaehm__begin_unwind(void) {
     206        if ( ! this_exception_context()->current_exception ) {
     207                printf("UNWIND ERROR missing exception in begin unwind\n");
     208                abort();
     209        }
     210
    119211
    120212        // Call stdlibc to raise the exception
    121213        _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
    122214
    123         // If we reach here it means something happened
    124         // For resumption to work we need to find a way to return back to here
    125         // Most of them will probably boil down to setting a global flag and making the phase 1 either stop or fail.
    126         // Causing an error on purpose may help avoiding unnecessary work but it might have some weird side effects.
    127         // If we just pretend no handler was found that would work but may be expensive for no reason since we will always
    128         // search the whole stack
     215        // If we reach here it means something happened.  For resumption to work we need to find a way to return back to
     216        // here.  Most of them will probably boil down to setting a global flag and making the phase 1 either stop or
     217        // fail.  Causing an error on purpose may help avoiding unnecessary work but it might have some weird side
     218        // effects.  If we just pretend no handler was found that would work but may be expensive for no reason since we
     219        // will always search the whole stack.
    129220
    130221        if( ret == _URC_END_OF_STACK ) {
    131                 // No proper handler was found
    132                 // This can be handled in several way
    133                 // C++ calls std::terminate
    134                 // Here we force unwind the stack, basically raising a cancellation
     222                // No proper handler was found.  This can be handled in several way.  C++ calls std::terminate Here we
     223                // force unwind the stack, basically raising a cancellation.
    135224                printf("Uncaught exception %p\n", &this_exception_storage);
    136225
     
    140229        }
    141230
    142         // We did not simply reach the end of the stack without finding a handler,
    143         // Something wen't wrong
     231        // We did not simply reach the end of the stack without finding a handler.  Something wen't wrong
    144232        printf("UNWIND ERROR %d after raise exception\n", ret);
    145233        abort();
    146234}
    147235
    148 // Nesting this the other way would probably be faster.
     236void __cfaehm__throw_terminate( exception * val ) {
     237        // DEBUG
     238        printf("Throwing termination exception\n");
     239
     240        __cfaehm__allocate_exception( val );
     241        __cfaehm__begin_unwind();
     242}
     243
    149244void __cfaehm__rethrow_terminate(void) {
    150245        // DEBUG
    151246        printf("Rethrowing termination exception\n");
    152247
    153         __cfaehm__throw_terminate(&shared_stack.current_exception);
    154 }
    155 
    156 // This is our personality routine
    157 // For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0"
    158 // This function will be called twice when unwinding
    159 // Once in the search phased and once in the cleanup phase
     248        __cfaehm__begin_unwind();
     249}
     250
     251// This is our personality routine.  For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0".
     252// This function will be called twice when unwinding.  Once in the search phased and once in the cleanup phase.
    160253_Unwind_Reason_Code __gcfa_personality_v0 (
    161254                int version, _Unwind_Action actions, unsigned long long exceptionClass,
     
    263356                                        _Unwind_Reason_Code (*matcher)(exception *) =
    264357                                                MATCHER_FROM_CONTEXT(context);
    265                                         int index = matcher(&shared_stack.current_exception);
     358                                        int index = matcher(shared_stack.current_exception);
    266359                                        _Unwind_Reason_Code ret = (0 == index)
    267360                                                ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
     
    293386                                // I assume this sets the instruction pointer to the adress of the landing pad
    294387                                // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
    295                                 _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad );
     388                                _Unwind_SetIP( context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
    296389
    297390                                // DEBUG
     
    317410}
    318411
    319 // Try statements are hoisted out see comments for details
    320 // With this could probably be unique and simply linked from
    321 // libcfa but there is one problem left, see the exception table
    322 // for details
     412// Try statements are hoisted out see comments for details.  With this could probably be unique and simply linked from
     413// libcfa but there is one problem left, see the exception table for details
    323414__attribute__((noinline))
    324415void __cfaehm__try_terminate(void (*try_block)(),
     
    328419        //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy);
    329420
    330         // Setup statments
    331         // These 2 statments won't actually result in any code,
    332         // they only setup global tables.
    333         // However, they clobber gcc cancellation support from gcc.
    334         // We can replace the personality routine but replacing the exception
    335         // table gcc generates is not really doable, it generates labels based
    336         // on how the assembly works.
     421        // Setup statments: These 2 statments won't actually result in any code, they only setup global tables.
     422        // However, they clobber gcc cancellation support from gcc.  We can replace the personality routine but
     423        // replacing the exception table gcc generates is not really doable, it generates labels based on how the
     424        // assembly works.
     425
    337426        // Setup the personality routine
    338427        asm volatile (".cfi_personality 0x3,__gcfa_personality_v0");
     
    340429        asm volatile (".cfi_lsda 0x3, .LLSDACFA2");
    341430
    342         // Label which defines the start of the area for which the handler is setup
     431        // Label which defines the start of the area for which the handler is setup.
    343432        asm volatile (".TRYSTART:");
    344433
     
    354443        // Exceptionnal path
    355444        CATCH : __attribute__(( unused ));
    356         // Label which defines the end of the area for which the handler is setup
     445        // Label which defines the end of the area for which the handler is setup.
    357446        asm volatile (".TRYEND:");
    358         // Label which defines the start of the exception landing pad
    359         // basically what will be called when the exception is caught
    360         // Note, if multiple handlers are given, the multiplexing should be done
    361         // by the generated code, not the exception runtime
     447        // Label which defines the start of the exception landing pad.  Basically what is called when the exception is
     448        // caught.  Note, if multiple handlers are given, the multiplexing should be done by the generated code, not the
     449        // exception runtime.
    362450        asm volatile (".CATCH:");
    363451
    364452        // Exception handler
    365         catch_block(shared_stack.current_handler_index,
    366                     &shared_stack.current_exception);
    367 }
    368 
    369 // Exception table data we need to generate
    370 // While this is almost generic, the custom data refers to
    371 // foo_try_match try match, which is no way generic
    372 // Some more works need to be done if we want to have a single
    373 // call to the try routine
     453        catch_block( shared_stack.current_handler_index,
     454                     shared_stack.current_exception );
     455}
     456
     457// Exception table data we need to generate.  While this is almost generic, the custom data refers to foo_try_match try
     458// match, which is no way generic.  Some more works need to be done if we want to have a single call to the try routine.
     459
     460#if defined( __x86_64__ ) || defined( __i386__ )
    374461asm (
    375462        //HEADER
     
    394481//      "       .section        .note.GNU-stack,\"x\",@progbits\n"
    395482);
     483#endif // __x86_64__ || __i386__
Note: See TracChangeset for help on using the changeset viewer.