- Timestamp:
- Jun 14, 2017, 3:16:46 PM (6 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:
- f146716
- Parents:
- bf70aa9 (diff), 6a48cc9 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- doc/working/exception
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/working/exception/impl/exception.c
rbf70aa9 r838ef08 22 22 23 23 void __throw_resume(exception except) { 24 void noop() { printf("do nothing\n");} 25 struct __cleanup_hook __blarg __attribute__((cleanup(noop))); 24 25 // DEBUG 26 printf("Throwing resumption exception %d\n", except); 26 27 27 28 struct __try_resume_node * original_head = shared_stack.current_resume; … … 45 46 } 46 47 47 /* __try_resume_node functions:48 * Currently I was planning to generate this code inline, and even if I don't49 * putting it in the header so it can be inlined might be worth while.50 * And if we put them in Cforall code we can use the operators.51 */52 void __try_resume_node_new(struct __try_resume_node * node,53 _Bool (*handler)(exception except)) {54 node->next = shared_stack.top_resume;55 shared_stack.top_resume = node;56 node->try_to_handle = handler;57 }58 59 void __try_resume_node_delete(struct __try_resume_node * node) {60 shared_stack.top_resume = node->next;61 }62 63 48 64 49 // TERMINATION =============================================================== 65 50 66 51 // Requires -fexceptions to work. 52 53 // Global which defines the current exception 54 // Currently an int just to make matching easier 55 //int this_exception; (became shared_stack.current_exception) 56 57 // We need a piece of storage to raise the exception 58 struct _Unwind_Exception this_exception_storage; 59 60 // Function needed by force unwind 61 // It basically says to unwind the whole stack and then exit when we reach the end of the stack 62 static _Unwind_Reason_Code _Stop_Fn( 63 int version, 64 _Unwind_Action actions, 65 _Unwind_Exception_Class exceptionClass, 66 struct _Unwind_Exception * unwind_exception, 67 struct _Unwind_Context * context, 68 void * some_param) { 69 if( actions & _UA_END_OF_STACK ) exit(1); 70 if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON; 71 72 return _URC_FATAL_PHASE2_ERROR; 73 } 74 75 // Example throw routine 76 void __throw_terminate( int val ) { 77 // Store the current exception 78 shared_stack.current_exception = val; 79 80 // DEBUG 81 printf("Throwing termination exception %d\n", val); 82 83 // Call stdlibc to raise the exception 84 _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage ); 85 86 // If we reach here it means something happened 87 // For resumption to work we need to find a way to return back to here 88 // Most of them will probably boil down to setting a global flag and making the phase 1 either stop or fail. 89 // Causing an error on purpose may help avoiding unnecessary work but it might have some weird side effects. 90 // If we just pretend no handler was found that would work but may be expensive for no reason since we will always 91 // search the whole stack 92 93 if( ret == _URC_END_OF_STACK ) { 94 // No proper handler was found 95 // This can be handled in several way 96 // C++ calls std::terminate 97 // Here we force unwind the stack, basically raising a cancellation 98 printf("Uncaught exception %p\n", &this_exception_storage); 99 100 ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 ); 101 printf("UNWIND ERROR %d after force unwind\n", ret); 102 abort(); 103 } 104 105 // We did not simply reach the end of the stack without finding a handler, 106 // Something wen't wrong 107 printf("UNWIND ERROR %d after raise exception\n", ret); 108 abort(); 109 } 110 111 // This is our personality routine 112 // For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0" 113 // This function will be called twice when unwinding 114 // Once in the search phased and once in the cleanup phase 115 _Unwind_Reason_Code __gcfa_personality_v0 ( 116 int version, _Unwind_Action actions, unsigned long long exceptionClass, 117 struct _Unwind_Exception* unwind_exception, 118 struct _Unwind_Context* context) 119 { 120 121 // DEBUG 122 //printf("CFA: 0x%lx\n", _Unwind_GetCFA(context)); 123 printf("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context); 124 125 // If we've reached the end of the stack then there is nothing much we can do... 126 if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK; 127 128 // DEBUG 129 if (actions & _UA_SEARCH_PHASE) { 130 printf(" lookup phase"); 131 } 132 // DEBUG 133 else if (actions & _UA_CLEANUP_PHASE) { 134 printf(" cleanup phase"); 135 } 136 // Just in case, probably can't actually happen 137 else { 138 printf(" error\n"); 139 return _URC_FATAL_PHASE1_ERROR; 140 } 141 142 // Get a pointer to the language specific data from which we will read what we need 143 const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context ); 144 145 if( !lsd ) { //Nothing to do, keep unwinding 146 printf(" no LSD"); 147 goto UNWIND; 148 } 149 150 // Get the instuction pointer and a reading pointer into the exception table 151 lsda_header_info lsd_info; 152 const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info); 153 _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context ); 154 155 // Linearly search the table for stuff to do 156 while( cur_ptr < lsd_info.action_table ) { 157 _Unwind_Ptr callsite_start; 158 _Unwind_Ptr callsite_len; 159 _Unwind_Ptr callsite_landing_pad; 160 _uleb128_t callsite_action; 161 162 // Decode the common stuff we have in here 163 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start); 164 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len); 165 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad); 166 cur_ptr = read_uleb128 (cur_ptr, &callsite_action); 167 168 // Have we reach the correct frame info yet? 169 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) { 170 //DEBUG BEGIN 171 void * ls = (void*)lsd_info.Start; 172 void * cs = (void*)callsite_start; 173 void * cl = (void*)callsite_len; 174 void * bp = (void*)lsd_info.Start + callsite_start; 175 void * ep = (void*)lsd_info.Start + callsite_start + callsite_len; 176 void * ip = (void*)instruction_ptr; 177 printf("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip); 178 //DEBUG END 179 continue; 180 } 181 182 // Have we gone too far 183 if( lsd_info.Start + callsite_start > instruction_ptr ) { 184 printf(" gone too far"); 185 break; 186 } 187 188 // Something to do? 189 if( callsite_landing_pad ) { 190 // Which phase are we in 191 if (actions & _UA_SEARCH_PHASE) { 192 // Search phase, this means we probably found a potential handler and must check if it is a match 193 194 // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler 195 // This doesn't seem to conflict the gcc default behavior 196 if (callsite_action != 0) { 197 // Now we want to run some code to see if the handler matches 198 // This is the tricky part where we want to the power to run arbitrary code 199 // However, generating a new exception table entry and try routine every time 200 // is way more expansive than we might like 201 // The information we have is : 202 // - The GR (Series of registers) 203 // GR1=GP Global Pointer of frame ref by context 204 // - The instruction pointer 205 // - The instruction pointer info (???) 206 // - The CFA (Canonical Frame Address) 207 // - The BSP (Probably the base stack pointer) 208 209 210 // The current apprach uses one exception table entry per try block 211 _uleb128_t imatcher; 212 // Get the relative offset to the 213 cur_ptr = read_uleb128 (cur_ptr, &imatcher); 214 215 // Get a function pointer from the relative offset and call it 216 // _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher; 217 218 _Unwind_Reason_Code (*matcher)() = 219 MATCHER_FROM_CONTEXT(context); 220 int index = matcher(shared_stack.current_exception); 221 _Unwind_Reason_Code ret = (0 == index) 222 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND; 223 shared_stack.current_handler_index = index; 224 225 // Based on the return value, check if we matched the exception 226 if( ret == _URC_HANDLER_FOUND) printf(" handler found\n"); 227 else printf(" no handler\n"); 228 return ret; 229 } 230 231 // This is only a cleanup handler, ignore it 232 printf(" no action"); 233 } 234 else if (actions & _UA_CLEANUP_PHASE) { 235 236 if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){ 237 // If this is a potential exception handler 238 // but not the one that matched the exception in the seach phase, 239 // just ignore it 240 goto UNWIND; 241 } 242 243 // We need to run some clean-up or a handler 244 // These statment do the right thing but I don't know any specifics at all 245 _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception ); 246 _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 ); 247 248 // I assume this sets the instruction pointer to the adress of the landing pad 249 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT 250 _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad ); 251 252 // DEBUG 253 printf(" action\n"); 254 255 // Return have some action to run 256 return _URC_INSTALL_CONTEXT; 257 } 258 } 259 260 // Nothing to do, move along 261 printf(" no landing pad"); 262 } 263 // No handling found 264 printf(" table end reached\n"); 265 266 // DEBUG 267 UNWIND: 268 printf(" unwind\n"); 269 270 // Keep unwinding the stack 271 return _URC_CONTINUE_UNWIND; 272 } 67 273 68 274 // Try statements are hoisted out see comments for details … … 141 347 " .size __try_terminate, .-__try_terminate\n" 142 348 " .ident \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n" 143 " .section .note.GNU-stack,\"x\",@progbits\n"349 // " .section .note.GNU-stack,\"x\",@progbits\n" 144 350 ); 145 146 // Global which defines the current exception147 // Currently an int just to make matching easier148 int this_exception;149 150 // We need a piece of storage to raise the exception151 struct _Unwind_Exception this_exception_storage;152 153 // Function needed by force unwind154 // It basically says to unwind the whole stack and then exit when we reach the end of the stack155 static _Unwind_Reason_Code _Stop_Fn(156 int version,157 _Unwind_Action actions,158 _Unwind_Exception_Class exceptionClass,159 struct _Unwind_Exception * unwind_exception,160 struct _Unwind_Context * context,161 void * some_param) {162 if( actions & _UA_END_OF_STACK ) exit(1);163 if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;164 165 return _URC_FATAL_PHASE2_ERROR;166 }167 168 // Example throw routine169 void __throw_terminate( int val ) {170 // Store the current exception171 this_exception = val;172 173 // DEBUG174 printf("Throwing exception %d\n", this_exception);175 176 // Call stdlibc to raise the exception177 _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );178 179 // If we reach here it means something happened180 // For resumption to work we need to find a way to return back to here181 // Most of them will probably boil down to setting a global flag and making the phase 1 either stop or fail.182 // Causing an error on purpose may help avoiding unnecessary work but it might have some weird side effects.183 // If we just pretend no handler was found that would work but may be expensive for no reason since we will always184 // search the whole stack185 186 if( ret == _URC_END_OF_STACK ) {187 // No proper handler was found188 // This can be handled in several way189 // C++ calls std::terminate190 // Here we force unwind the stack, basically raising a cancellation191 printf("Uncaught exception %p\n", &this_exception_storage);192 193 ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );194 printf("UNWIND ERROR %d after force unwind\n", ret);195 abort();196 }197 198 // We did not simply reach the end of the stack without finding a handler,199 // Something wen't wrong200 printf("UNWIND ERROR %d after raise exception\n", ret);201 abort();202 }203 204 // This is our personality routine205 // For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0"206 // This function will be called twice when unwinding207 // Once in the search phased and once in the cleanup phase208 _Unwind_Reason_Code __gcfa_personality_v0 (209 int version, _Unwind_Action actions, unsigned long long exceptionClass,210 struct _Unwind_Exception* unwind_exception,211 struct _Unwind_Context* context)212 {213 printf("CFA: 0x%lx\n", _Unwind_GetCFA(context));214 215 // DEBUG216 printf("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);217 218 // If we've reached the end of the stack then there is nothing much we can do...219 if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;220 221 // DEBUG222 if (actions & _UA_SEARCH_PHASE) {223 printf(" lookup phase");224 }225 // DEBUG226 else if (actions & _UA_CLEANUP_PHASE) {227 printf(" cleanup phase");228 }229 // Just in case, probably can't actually happen230 else {231 printf(" error\n");232 return _URC_FATAL_PHASE1_ERROR;233 }234 235 // Get a pointer to the language specific data from which we will read what we need236 const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );237 238 if( !lsd ) { //Nothing to do, keep unwinding239 printf(" no LSD");240 goto UNWIND;241 }242 243 // Get the instuction pointer and a reading pointer into the exception table244 lsda_header_info lsd_info;245 const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);246 _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );247 248 // Linearly search the table for stuff to do249 while( cur_ptr < lsd_info.action_table ) {250 _Unwind_Ptr callsite_start;251 _Unwind_Ptr callsite_len;252 _Unwind_Ptr callsite_landing_pad;253 _uleb128_t callsite_action;254 255 // Decode the common stuff we have in here256 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);257 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);258 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);259 cur_ptr = read_uleb128 (cur_ptr, &callsite_action);260 261 // Have we reach the correct frame info yet?262 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {263 //DEBUG BEGIN264 void * ls = (void*)lsd_info.Start;265 void * cs = (void*)callsite_start;266 void * cl = (void*)callsite_len;267 void * bp = (void*)lsd_info.Start + callsite_start;268 void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;269 void * ip = (void*)instruction_ptr;270 printf("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);271 //DEBUG END272 continue;273 }274 275 // Have we gone too far276 if( lsd_info.Start + callsite_start > instruction_ptr ) {277 printf(" gone too far");278 break;279 }280 281 // Something to do?282 if( callsite_landing_pad ) {283 // Which phase are we in284 if (actions & _UA_SEARCH_PHASE) {285 // Search phase, this means we probably found a potential handler and must check if it is a match286 287 // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler288 // This doesn't seem to conflict the gcc default behavior289 if (callsite_action != 0) {290 // Now we want to run some code to see if the handler matches291 // This is the tricky part where we want to the power to run arbitrary code292 // However, generating a new exception table entry and try routine every time293 // is way more expansive than we might like294 // The information we have is :295 // - The GR (Series of registers)296 // GR1=GP Global Pointer of frame ref by context297 // - The instruction pointer298 // - The instruction pointer info (???)299 // - The CFA (Canonical Frame Address)300 // - The BSP (Probably the base stack pointer)301 302 303 // The current apprach uses one exception table entry per try block304 _uleb128_t imatcher;305 // Get the relative offset to the306 cur_ptr = read_uleb128 (cur_ptr, &imatcher);307 308 // Get a function pointer from the relative offset and call it309 // _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher;310 311 _Unwind_Reason_Code (*matcher)() =312 MATCHER_FROM_CONTEXT(context);313 int index = matcher(shared_stack.current_exception);314 _Unwind_Reason_Code ret = (0 == index)315 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;316 shared_stack.current_handler_index = index;317 318 319 // Based on the return value, check if we matched the exception320 if( ret == _URC_HANDLER_FOUND) printf(" handler found\n");321 else printf(" no handler\n");322 return ret;323 }324 325 // This is only a cleanup handler, ignore it326 printf(" no action");327 }328 else if (actions & _UA_CLEANUP_PHASE) {329 330 if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){331 // If this is a potential exception handler332 // but not the one that matched the exception in the seach phase,333 // just ignore it334 goto UNWIND;335 }336 337 // We need to run some clean-up or a handler338 // These statment do the right thing but I don't know any specifics at all339 _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );340 _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );341 342 // I assume this sets the instruction pointer to the adress of the landing pad343 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT344 _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad );345 346 // DEBUG347 printf(" action\n");348 349 // Return have some action to run350 return _URC_INSTALL_CONTEXT;351 }352 }353 354 // Nothing to do, move along355 printf(" no landing pad");356 }357 // No handling found358 printf(" table end reached\n");359 360 // DEBUG361 UNWIND:362 printf(" unwind\n");363 364 // Keep unwinding the stack365 return _URC_CONTINUE_UNWIND;366 } -
doc/working/exception/impl/exception.h
rbf70aa9 r838ef08 32 32 }; 33 33 34 extern struct shared_stack_t s tared_stack;34 extern struct shared_stack_t shared_stack; -
doc/working/exception/impl/test-main.c
rbf70aa9 r838ef08 1 1 #include "exception.h" 2 2 3 // Use: gcc -fexceptions -Wall -Werror -g exception.c test-main.c 4 3 5 #include <stdio.h> 6 #include <stdbool.h> 4 7 5 8 // Translation Helpers: … … 7 10 struct __cleanup_hook __hidden_hook __attribute__((cleanup(function))) 8 11 12 #define SET_UP_RESUME_NODE(handler_function) \ 13 struct __try_resume_node node \ 14 __attribute__((cleanup(__try_resume_node_delete))); \ 15 __try_resume_node_new(&node, handler_function) 16 17 void __try_resume_node_new(struct __try_resume_node * node, 18 _Bool (*handler)(exception except)) { 19 node->next = shared_stack.top_resume; 20 shared_stack.top_resume = node; 21 node->try_to_handle = handler; 22 } 23 24 void __try_resume_node_delete(struct __try_resume_node * node) { 25 shared_stack.top_resume = node->next; 26 } 9 27 10 28 // Local Print On Exit: … … 19 37 #define raii_t __attribute__((cleanup(raii_dtor))) struct raii_base_type 20 38 39 // =========================================================================== 21 40 // Runtime code (post-translation). 22 41 void terminate(int except_value) { … … 34 53 // Termination Test: Two handlers: no catch, catch 35 54 void bar() { 36 void bar_try1() { 37 terminate(4); 38 } 39 void bar_catch1(int index, exception except) { 40 switch(except) { 41 case 1: 42 printf("bar caught exception.\n"); 43 break; 44 default: 45 printf("INVALID INDEX in bar: %d\n", except); 46 } 47 } 48 int bar_match1(exception except) { 49 if (3 == except) { 50 return 1; 51 } else { 52 return 0; 53 } 54 } 55 __try_terminate(bar_try1, bar_catch1, bar_match1); 55 raii_t a = {"bar function"}; 56 { 57 void bar_try1() { 58 terminate(4); 59 } 60 void bar_catch1(int index, exception except) { 61 switch(except) { 62 case 1: 63 printf("bar caught exception 3.\n"); 64 break; 65 default: 66 printf("INVALID INDEX in bar: %d (%d)\n", index, except); 67 } 68 } 69 int bar_match1(exception except) { 70 if (3 == except) { 71 return 1; 72 } else { 73 return 0; 74 } 75 } 76 __try_terminate(bar_try1, bar_catch1, bar_match1); 77 } 56 78 } 57 79 58 80 void foo() { 59 void foo_try1() { 60 bar(); 61 } 62 void foo_catch1(int index, exception except) { 63 switch(except) { 64 case 1: 65 printf("foo caught exception 4.\n"); 66 break; 67 case 2: 68 printf("foo caught exception 2.\n"); 69 break; 70 default: 71 printf("INVALID INDEX in foo: %d\n", except); 72 } 73 } 74 int foo_match1(exception except) { 75 if (4 == except) { 76 return 1; 77 } else if (2 == except) { 78 return 2; 79 } else { 80 return 0; 81 } 82 } 83 __try_terminate(foo_try1, foo_catch1, foo_match1); 84 } 85 81 raii_t a = {"foo function"}; 82 { 83 void foo_try1() { 84 bar(); 85 } 86 void foo_catch1(int index, exception except) { 87 switch(index) { 88 case 1: 89 printf("foo caught exception 4.\n"); 90 break; 91 case 2: 92 printf("foo caught exception 2.\n"); 93 break; 94 default: 95 printf("INVALID INDEX in foo: %d (%d)\n", index, except); 96 } 97 } 98 int foo_match1(exception except) { 99 if (4 == except) { 100 return 1; 101 } else if (2 == except) { 102 return 2; 103 } else { 104 return 0; 105 } 106 } 107 __try_terminate(foo_try1, foo_catch1, foo_match1); 108 } 109 } 110 111 // Resumption Two Handler Test: no catch, catch. 112 void beta() { 113 raii_t a = {"beta function"}; 114 { 115 bool beta_handle1(exception except) { 116 if (3 == except) { 117 printf("beta caught exception 3\n"); 118 return true; 119 } else { 120 return false; 121 } 122 } 123 struct __try_resume_node node 124 __attribute__((cleanup(__try_resume_node_delete))); 125 __try_resume_node_new(&node, beta_handle1); 126 { 127 resume(4); 128 } 129 } 130 } 131 void alpha() { 132 raii_t a = {"alpha function"}; 133 { 134 bool alpha_handle1(exception except) { 135 if (2 == except) { 136 printf("alpha caught exception 2\n"); 137 return true; 138 } else if (4 == except) { 139 printf("alpha caught exception 4\n"); 140 return true; 141 } else { 142 return false; 143 } 144 } 145 struct __try_resume_node node 146 __attribute__((cleanup(__try_resume_node_delete))); 147 __try_resume_node_new(&node, alpha_handle1); 148 { 149 beta(); 150 } 151 } 152 } 153 154 // Finally Test: 155 void farewell() { 156 { 157 void farewell_finally1() { 158 printf("See you next time\n"); 159 } 160 struct __cleanup_hook __hidden_hook 161 __attribute__((cleanup(farewell_finally1))); 162 { 163 printf("walk out of farewell\n"); 164 } 165 } 166 } 167 168 // Resume-to-Terminate Test: 169 void fallback() { 170 { 171 void fallback_try1() { 172 resume(1); 173 } 174 void fallback_catch1(int index, exception except) { 175 switch (index) { 176 case 1: 177 printf("fallback caught termination 1\n"); 178 break; 179 default: 180 printf("INVALID INDEX in fallback: %d (%d)\n", index, except); 181 } 182 } 183 int fallback_match1(exception except) { 184 if (1 == except) { 185 return 1; 186 } else { 187 return 0; 188 } 189 } 190 __try_terminate(fallback_try1, fallback_catch1, fallback_match1); 191 } 192 } 193 194 // Terminate Throw New Exception: 195 void terminate_swap() { 196 raii_t a = {"terminate_swap"}; 197 { 198 void fn_try1() { 199 terminate(2); 200 } 201 void fn_catch1(int index, exception except) { 202 switch (index) { 203 case 1: 204 terminate(1); 205 break; 206 default: 207 printf("INVALID INDEX in terminate_swap: %d (%d)\n", 208 index, except); 209 } 210 } 211 int fn_match1(exception except) { 212 if (2 == except) { 213 return 1; 214 } else { 215 return 0; 216 } 217 } 218 __try_terminate(fn_try1, fn_catch1, fn_match1); 219 } 220 } 221 222 void terminate_swapped() { 223 raii_t a = {"terminate_swapped"}; 224 { 225 void fn_try1() { 226 terminate_swap(); 227 } 228 void fn_catch1(int index, exception except) { 229 switch (index) { 230 case 1: 231 printf("terminate_swapped caught exception 1\n"); 232 break; 233 default: 234 printf("INVALID INDEX in terminate_swapped: %d (%d)\n", 235 index, except); 236 } 237 } 238 int fn_match1(exception except) { 239 if (1 == except) { 240 return 1; 241 } else { 242 return 0; 243 } 244 } 245 __try_terminate(fn_try1, fn_catch1, fn_match1); 246 } 247 } 248 249 // Resume Throw New Exception: 250 void resume_swap() { 251 raii_t a = {"terminate_swap"}; 252 { 253 bool fn_handle1(exception except) { 254 if (2 == except) { 255 resume(1); 256 return true; 257 } else { 258 return false; 259 } 260 } 261 struct __try_resume_node node 262 __attribute__((cleanup(__try_resume_node_delete))); 263 __try_resume_node_new(&node, fn_handle1); 264 { 265 resume(2); 266 } 267 } 268 } 269 270 void resume_swapped() { 271 { 272 bool fn_handle1(exception except) { 273 if (1 == except) { 274 printf("resume_swapped caught exception 1\n"); 275 return true; 276 } else { 277 return false; 278 } 279 } 280 struct __try_resume_node node 281 __attribute__((cleanup(__try_resume_node_delete))); 282 __try_resume_node_new(&node, fn_handle1); 283 { 284 resume_swap(); 285 } 286 } 287 } 288 289 // Terminate Rethrow: 290 // I don't have an implementation for this. 291 292 // Resume Rethrow: 293 void reresume() { 294 { 295 bool reresume_handle1(exception except) { 296 if (1 == except) { 297 printf("reresume 1 caught exception 1\n"); 298 return true; 299 } else { 300 return false; 301 } 302 } 303 struct __try_resume_node node 304 __attribute__((cleanup(__try_resume_node_delete))); 305 __try_resume_node_new(&node, reresume_handle1); 306 { 307 bool reresume_handle2(exception except) { 308 if (1 == except) { 309 printf("reresume 2 caught and rethrows exception 1\n"); 310 return false; 311 } else { 312 return false; 313 } 314 } 315 struct __try_resume_node node 316 __attribute__((cleanup(__try_resume_node_delete))); 317 __try_resume_node_new(&node, reresume_handle2); 318 { 319 resume(1); 320 } 321 } 322 } 323 } 324 325 // Terminate-Resume interaction: 326 void fum() { 327 // terminate block, call resume 328 { 329 void fum_try1() { 330 resume(3); 331 } 332 void fum_catch1(int index, exception except) { 333 switch (index) { 334 case 1: 335 printf("fum caught exception 3\n"); 336 break; 337 default: 338 printf("INVALID INDEX in fum: %d (%d)\n", index, except); 339 } 340 } 341 int fum_match1(exception except) { 342 if (3 == except) { 343 return 1; 344 } else { 345 return 0; 346 } 347 } 348 __try_terminate(fum_try1, fum_catch1, fum_match1); 349 } 350 } 351 352 void foe() { 353 // resume block, call terminate 354 { 355 bool foe_handle1(exception except) { 356 if (3 == except) { 357 printf("foe caught exception 3\n"); 358 return true; 359 } else { 360 return false; 361 } 362 } 363 struct __try_resume_node node 364 __attribute__((cleanup(__try_resume_node_delete))); 365 __try_resume_node_new(&node, foe_handle1); 366 { 367 terminate(3); 368 } 369 } 370 } 371 372 void fy() { 373 // terminate block calls fum, call foe 374 { 375 void fy_try1() { 376 foe(); 377 } 378 void fy_catch1(int index, exception except) { 379 switch (index) { 380 case 1: 381 printf("fy caught exception 3\n"); 382 fum(); 383 break; 384 default: 385 printf("INVALID INDEX in fy: %d (%d)\n", index, except); 386 } 387 } 388 int fy_match1(exception except) { 389 if (3 == except) { 390 return 1; 391 } else { 392 return 0; 393 } 394 } 395 __try_terminate(fy_try1, fy_catch1, fy_match1); 396 } 397 } 398 399 void fee() { 400 // resume block, call fy 401 { 402 bool fee_handle1(exception except) { 403 if (3 == except) { 404 printf("fee caught exception 3\n"); 405 return true; 406 } else { 407 return false; 408 } 409 } 410 struct __try_resume_node node 411 __attribute__((cleanup(__try_resume_node_delete))); 412 __try_resume_node_new(&node, fee_handle1); 413 { 414 fy(); 415 } 416 } 417 } 418 419 420 // main: choose which tests to run 86 421 int main(int argc, char * argv[]) { 87 422 raii_t a = {"main function"}; 88 423 89 foo(); 90 } 424 foo(); printf("\n"); 425 alpha(); printf("\n"); 426 farewell(); printf("\n"); 427 fallback(); printf("\n"); 428 terminate_swapped(); printf("\n"); 429 resume_swapped(); printf("\n"); 430 reresume(); printf("\n"); 431 fee(); printf("\n"); 432 // Uncaught termination test. 433 terminate(7); 434 } -
doc/working/exception/translate.c
rbf70aa9 r838ef08 237 237 } 238 238 void finally1() { 239 // (Finally, because of timing, also work for resume.) 239 // Finally, because of timing, also works for resume. 240 // However this might not actually be better in any way. 240 241 __try_resume_cleanup(); 241 242
Note: See TracChangeset
for help on using the changeset viewer.