Changeset 9236060 for src/libcfa/exception.c
- Timestamp:
- Aug 14, 2017, 2:03:39 PM (8 years ago)
- 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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/exception.c
rfd344aa r9236060 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tus Jul 11 16:36:00 201713 // Update Count : 112 // Last Modified On : Fri Aug 4 15:20:00 2017 13 // Update Count : 6 14 14 // 15 16 #include <stddef.h> // for size_t 15 17 16 18 #include "exception.h" … … 22 24 #include <unwind.h> 23 25 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 24 34 #include "lsda.h" 25 35 36 37 // Base exception vtable is abstract, you should not have base exceptions. 38 struct __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 26 48 // Temperary global exception context. Does not work with concurency. 27 struct shared_stack_t {49 struct exception_context_t { 28 50 struct __cfaehm__try_resume_node * top_resume; 29 51 struct __cfaehm__try_resume_node * current_resume; 30 52 31 exception current_exception;53 exception * current_exception; 32 54 int current_handler_index; 33 55 } shared_stack = {NULL, NULL, 0, 0}; 34 56 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. 60 struct 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. 39 72 // struct _Unwind_Context * -> _Unwind_Reason_Code(*)(exception *) 40 73 #define MATCHER_FROM_CONTEXT(ptr_to_context) \ … … 47 80 48 81 // DEBUG 49 printf("Throwing resumption exception %d\n", *except);82 printf("Throwing resumption exception\n"); 50 83 51 84 struct __cfaehm__try_resume_node * original_head = shared_stack.current_resume; … … 61 94 } 62 95 63 printf("Unhandled exception %d\n", *except);96 printf("Unhandled exception\n"); 64 97 shared_stack.current_resume = original_head; 65 98 … … 69 102 } 70 103 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 75 107 void __cfaehm__try_resume_setup(struct __cfaehm__try_resume_node * node, 76 108 int (*handler)(exception * except)) { … … 87 119 // TERMINATION =============================================================== 88 120 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 124 struct __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. 132 static 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. 153 static 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. 181 void __cfaehm__cleanup_terminate( void * except ) { 182 if ( *(void**)except ) __cfaehm__delete_exception( *(exception**)except ); 183 } 184 94 185 95 186 // We need a piece of storage to raise the exception … … 111 202 } 112 203 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 119 211 120 212 // Call stdlibc to raise the exception 121 213 _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage ); 122 214 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. 129 220 130 221 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. 135 224 printf("Uncaught exception %p\n", &this_exception_storage); 136 225 … … 140 229 } 141 230 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 144 232 printf("UNWIND ERROR %d after raise exception\n", ret); 145 233 abort(); 146 234 } 147 235 148 // Nesting this the other way would probably be faster. 236 void __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 149 244 void __cfaehm__rethrow_terminate(void) { 150 245 // DEBUG 151 246 printf("Rethrowing termination exception\n"); 152 247 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. 160 253 _Unwind_Reason_Code __gcfa_personality_v0 ( 161 254 int version, _Unwind_Action actions, unsigned long long exceptionClass, … … 263 356 _Unwind_Reason_Code (*matcher)(exception *) = 264 357 MATCHER_FROM_CONTEXT(context); 265 int index = matcher( &shared_stack.current_exception);358 int index = matcher(shared_stack.current_exception); 266 359 _Unwind_Reason_Code ret = (0 == index) 267 360 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND; … … 293 386 // I assume this sets the instruction pointer to the adress of the landing pad 294 387 // 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)) ); 296 389 297 390 // DEBUG … … 317 410 } 318 411 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 323 414 __attribute__((noinline)) 324 415 void __cfaehm__try_terminate(void (*try_block)(), … … 328 419 //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy); 329 420 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 337 426 // Setup the personality routine 338 427 asm volatile (".cfi_personality 0x3,__gcfa_personality_v0"); … … 340 429 asm volatile (".cfi_lsda 0x3, .LLSDACFA2"); 341 430 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. 343 432 asm volatile (".TRYSTART:"); 344 433 … … 354 443 // Exceptionnal path 355 444 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. 357 446 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. 362 450 asm volatile (".CATCH:"); 363 451 364 452 // 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__ ) 374 461 asm ( 375 462 //HEADER … … 394 481 // " .section .note.GNU-stack,\"x\",@progbits\n" 395 482 ); 483 #endif // __x86_64__ || __i386__
Note:
See TracChangeset
for help on using the changeset viewer.