source: doc/working/exception/impl/main.c@ c5ac6d5

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since c5ac6d5 was 6b72040, checked in by Andrew Beach <ajbeach@…>, 8 years ago

The try exception handler function is now generic.

  • Property mode set to 100644
File size: 5.0 KB
Line 
1#include <stdio.h>
2#include "except.h"
3
4// Requires -fexceptions to work.
5
6#define EXCEPTION 2
7
8struct type_raii_t {
9 char * msg;
10};
11
12//Dtor function to test clean up routines
13void dtor( struct type_raii_t * this ) {
14 printf("%s\n", this->msg);
15}
16
17//Type macro use to make scope unwinding easier to see.
18#define raii_t __attribute__(( cleanup(dtor) )) struct type_raii_t
19
20//Leaf functions that raises exception
21void bar() {
22 raii_t a = { "Bar dtor" };
23
24 throw( EXCEPTION );
25}
26
27//Matcher function which will check if the exception was correctly caught
28extern int this_exception;
29_Unwind_Reason_Code foo_try_match() {
30 printf(" (foo_try_match called)");
31 return this_exception == EXCEPTION ? _URC_HANDLER_FOUND : _URC_CONTINUE_UNWIND;
32}
33
34//Try statements are hoisted out see comments for details
35//With this could probably be unique and simply linked from
36//libcfa but there is one problem left, see the exception table
37//for details
38__attribute__((noinline))
39void try( void (*try_block)(), void (*catch_block)(),
40 _Unwind_Reason_Code (*match_block)() )
41{
42 volatile int xy = 0;
43 printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy);
44
45 //Setup statments
46 //These 2 statments won't actually result in any code,
47 //they only setup global tables.
48 //However, they clobber gcc cancellation support from gcc.
49 //We can replace the personality routine but replacing the exception
50 //table gcc generates is not really doable, it generates labels based
51 //on how the assembly works.
52 //Setup the personality routine
53 asm volatile (".cfi_personality 0x3,__gcfa_personality_v0");
54 //Setup the exception table
55 asm volatile (".cfi_lsda 0x3, .LLSDACFA2");
56
57 //Label which defines the start of the area for which the handler is setup
58 asm volatile (".TRYSTART:");
59
60 //The actual statements of the try blocks
61 try_block();
62
63 //asm statement to prevent deadcode removal
64 asm volatile goto ("" : : : : CATCH );
65
66 //Normal return
67 return;
68
69 //Exceptionnal path
70 CATCH : __attribute__(( unused ));
71 //Label which defines the end of the area for which the handler is setup
72 asm volatile (".TRYEND:");
73 //Label which defines the start of the exception landing pad
74 //basically what will be called when the exception is caught
75 //Note, if multiple handlers are given, the multiplexing should be done
76 //by the generated code, not the exception runtime
77 asm volatile (".CATCH:");
78
79 //Exception handler
80 catch_block();
81}
82
83//Exception table data we need to generate
84//While this is almost generic, the custom data refers to
85//foo_try_match try match, which is no way generic
86//Some more works need to be done if we want to have a single
87//call to the try routine
88asm (
89 //HEADER
90 ".LFECFA1:\n"
91 " .globl __gcfa_personality_v0\n"
92 " .section .gcc_except_table,\"a\",@progbits\n"
93 ".LLSDACFA2:\n" //TABLE header
94 " .byte 0xff\n"
95 " .byte 0xff\n"
96 " .byte 0x1\n"
97 " .uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n" //BODY length
98 //Body uses language specific data and therefore could be modified arbitrarily
99 ".LLSDACSBCFA2:\n" //BODY start
100 " .uleb128 .TRYSTART-try\n" //Handled area start (relative to start of function)
101 " .uleb128 .TRYEND-.TRYSTART\n" //Handled area length
102 " .uleb128 .CATCH-try\n" //Hanlder landing pad adress (relative to start of function)
103 " .uleb128 1\n" //Action code, gcc seems to use always 0
104 ".LLSDACSECFA2:\n" //BODY end
105 " .text\n" //TABLE footer
106 " .size try, .-try\n"
107 " .ident \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
108 " .section .note.GNU-stack,\"x\",@progbits\n"
109);
110
111void foo() {
112 raii_t a = { "Foo dtor" };
113
114 //Since try will clobber the gcc exception table assembly,
115 //We need to nest this to have gcc regenerate the data
116 void foo_try_block() {
117 raii_t b = { "Foo try dtor" };
118
119 bar();
120
121 printf("Called bar successfully\n");
122 }
123
124 void foo_catch_block() {
125 printf("Exception caught\n");
126 }
127
128 //Actual call to the try block
129 try( foo_try_block, foo_catch_block, foo_try_match );
130
131 printf( "Foo exited normally\n" );
132}
133
134// Not in main.cfa
135void fy() {
136 // Currently not destroyed if the exception is caught in fee.
137 raii_t a = { "Fy dtor" };
138
139 void fy_try_block() {
140 raii_t b = { "Fy try dtor" };
141
142 throw( 3 );
143 }
144
145 void fy_catch_block() {
146 printf("Fy caught exception\n");
147 }
148
149 _Unwind_Reason_Code fy_match_block() {
150 return this_exception == 2 ? _URC_HANDLER_FOUND : _URC_CONTINUE_UNWIND;
151 }
152
153 try(fy_try_block, fy_catch_block, fy_match_block);
154
155 printf( "Fy exited normally\n" );
156}
157
158void fee() {
159 raii_t a = { "Fee dtor" };
160
161 void fee_try_block() {
162 raii_t b = { "Fee try dtor" };
163
164 fy();
165
166 printf("fy returned\n");
167 }
168
169 void fee_catch_block() {
170 printf("Fee caught exception\n");
171 }
172
173 _Unwind_Reason_Code fee_match_block() {
174 return this_exception == 3 ? _URC_HANDLER_FOUND : _URC_CONTINUE_UNWIND;
175 }
176
177 try(fee_try_block, fee_catch_block, fee_match_block);
178
179 printf( "Fee exited normally\n" );
180}
181// End not in main.cfa
182
183int main() {
184 raii_t a = { "Main dtor" };
185
186 //for (unsigned int i = 0 ; i < 100000000 ; ++i)
187 foo();
188 fee();
189
190 printf("End of program reached\n");
191}
Note: See TracBrowser for help on using the repository browser.