Changeset 838ef08


Ignore:
Timestamp:
Jun 14, 2017, 3:16:46 PM (4 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
aaron-thesis, arm-eh, cleanup-dtors, deferred_resn, demangler, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, 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.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Location:
doc/working/exception
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • doc/working/exception/impl/exception.c

    rbf70aa9 r838ef08  
    2222
    2323void __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);
    2627
    2728        struct __try_resume_node * original_head = shared_stack.current_resume;
     
    4546}
    4647
    47 /* __try_resume_node functions:
    48  * Currently I was planning to generate this code inline, and even if I don't
    49  * 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 
    6348
    6449// TERMINATION ===============================================================
    6550
    6651// 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
     58struct _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
     62static _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
     76void __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}
    67273
    68274// Try statements are hoisted out see comments for details
     
    141347        "       .size   __try_terminate, .-__try_terminate\n"
    142348        "       .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"
    144350);
    145 
    146 // Global which defines the current exception
    147 // Currently an int just to make matching easier
    148 int this_exception;
    149 
    150 // We need a piece of storage to raise the exception
    151 struct _Unwind_Exception this_exception_storage;
    152 
    153 // Function needed by force unwind
    154 // It basically says to unwind the whole stack and then exit when we reach the end of the stack
    155 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 routine
    169 void __throw_terminate( int val ) {
    170         // Store the current exception
    171         this_exception = val;
    172 
    173         // DEBUG
    174         printf("Throwing exception %d\n", this_exception);
    175 
    176         // Call stdlibc to raise the exception
    177         _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
    178 
    179         // If we reach here it means something happened
    180         // For resumption to work we need to find a way to return back to here
    181         // 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 always
    184         // search the whole stack
    185 
    186         if( ret == _URC_END_OF_STACK ) {
    187                 // No proper handler was found
    188                 // This can be handled in several way
    189                 // C++ calls std::terminate
    190                 // Here we force unwind the stack, basically raising a cancellation
    191                 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 wrong
    200         printf("UNWIND ERROR %d after raise exception\n", ret);
    201         abort();
    202 }
    203 
    204 // This is our personality routine
    205 // For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0"
    206 // This function will be called twice when unwinding
    207 // Once in the search phased and once in the cleanup phase
    208 _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         // DEBUG
    216         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         // DEBUG
    222         if (actions & _UA_SEARCH_PHASE) {
    223                 printf(" lookup phase");
    224         }
    225         // DEBUG
    226         else if (actions & _UA_CLEANUP_PHASE) {
    227                 printf(" cleanup phase");
    228         }
    229         // Just in case, probably can't actually happen
    230         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 need
    236         const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
    237 
    238         if( !lsd ) {    //Nothing to do, keep unwinding
    239                 printf(" no LSD");
    240                 goto UNWIND;
    241         }
    242 
    243         // Get the instuction pointer and a reading pointer into the exception table
    244         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 do
    249         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 here
    256                 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 BEGIN
    264                         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 END
    272                         continue;
    273                 }
    274 
    275                 // Have we gone too far
    276                 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 in
    284                         if (actions & _UA_SEARCH_PHASE) {
    285                                 // Search phase, this means we probably found a potential handler and must check if it is a match
    286 
    287                                 // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler
    288                                 // This doesn't seem to conflict the gcc default behavior
    289                                 if (callsite_action != 0) {
    290                                         // Now we want to run some code to see if the handler matches
    291                                         // This is the tricky part where we want to the power to run arbitrary code
    292                                         // However, generating a new exception table entry and try routine every time
    293                                         // is way more expansive than we might like
    294                                         // The information we have is :
    295                                         //  - The GR (Series of registers)
    296                                         //    GR1=GP Global Pointer of frame ref by context
    297                                         //  - The instruction pointer
    298                                         //  - 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 block
    304                                         _uleb128_t imatcher;
    305                                         // Get the relative offset to the
    306                                         cur_ptr = read_uleb128 (cur_ptr, &imatcher);
    307 
    308                                         // Get a function pointer from the relative offset and call it
    309                                         // _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 exception
    320                                         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 it
    326                                 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 handler
    332                                         // but not the one that matched the exception in the seach phase,
    333                                         // just ignore it
    334                                         goto UNWIND;
    335                                 }
    336 
    337                                 // We need to run some clean-up or a handler
    338                                 // These statment do the right thing but I don't know any specifics at all
    339                                 _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 pad
    343                                 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
    344                                 _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad );
    345 
    346                                 // DEBUG
    347                                 printf(" action\n");
    348 
    349                                 // Return have some action to run
    350                                 return _URC_INSTALL_CONTEXT;
    351                         }
    352                 }
    353 
    354                 // Nothing to do, move along
    355                 printf(" no landing pad");
    356         }
    357         // No handling found
    358         printf(" table end reached\n");
    359 
    360         // DEBUG
    361         UNWIND:
    362         printf(" unwind\n");
    363 
    364         // Keep unwinding the stack
    365         return _URC_CONTINUE_UNWIND;
    366 }
  • doc/working/exception/impl/exception.h

    rbf70aa9 r838ef08  
    3232};
    3333
    34 extern struct shared_stack_t stared_stack;
     34extern struct shared_stack_t shared_stack;
  • doc/working/exception/impl/test-main.c

    rbf70aa9 r838ef08  
    11#include "exception.h"
    22
     3// Use: gcc -fexceptions -Wall -Werror -g exception.c test-main.c
     4
    35#include <stdio.h>
     6#include <stdbool.h>
    47
    58// Translation Helpers:
     
    710        struct __cleanup_hook __hidden_hook __attribute__((cleanup(function)))
    811
     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
     17void __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
     24void __try_resume_node_delete(struct __try_resume_node * node) {
     25    shared_stack.top_resume = node->next;
     26}
    927
    1028// Local Print On Exit:
     
    1937#define raii_t __attribute__((cleanup(raii_dtor))) struct raii_base_type
    2038
     39// ===========================================================================
    2140// Runtime code (post-translation).
    2241void terminate(int except_value) {
     
    3453// Termination Test: Two handlers: no catch, catch
    3554void 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        }
    5678}
    5779
    5880void 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.
     112void 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}
     131void 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:
     155void 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:
     169void 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:
     195void 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
     222void 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:
     250void 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
     270void 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:
     293void 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:
     326void 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
     352void 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
     372void 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
     399void 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
    86421int main(int argc, char * argv[]) {
    87422        raii_t a = {"main function"};
    88423
    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  
    237237                }
    238238                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.
    240241                        __try_resume_cleanup();
    241242
Note: See TracChangeset for help on using the changeset viewer.