]>
Commit | Line | Data |
---|---|---|
8d08fdba | 1 | /* Handle exceptional things in C++. |
8d2733ca MS |
2 | Copyright (C) 1989, 1992, 1993, 1994 Free Software Foundation, Inc. |
3 | Contributed by Michael Tiemann <tiemann@cygnus.com> | |
4 | Rewritten by Mike Stump <mrs@cygnus.com>, based upon an | |
5 | initial re-implementation courtesy Tad Hunt. | |
8d08fdba MS |
6 | |
7 | This file is part of GNU CC. | |
8 | ||
9 | GNU CC is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2, or (at your option) | |
12 | any later version. | |
13 | ||
14 | GNU CC is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with GNU CC; see the file COPYING. If not, write to | |
21 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
22 | ||
23 | ||
24 | /* High-level class interface. */ | |
25 | ||
26 | #include "config.h" | |
27 | #include "tree.h" | |
28 | #include "rtl.h" | |
29 | #include "cp-tree.h" | |
30 | #include "flags.h" | |
8d2733ca MS |
31 | #include "obstack.h" |
32 | #include "expr.h" | |
8d08fdba | 33 | |
a3b49ccd MS |
34 | extern void (*interim_eh_hook) PROTO((tree)); |
35 | ||
8d2733ca MS |
36 | /* holds the fndecl for __builtin_return_address () */ |
37 | tree builtin_return_address_fndecl; | |
8d08fdba | 38 | |
8d2733ca | 39 | /* Define at your own risk! */ |
a4443a08 | 40 | #ifndef CROSS_COMPILE |
8d2733ca MS |
41 | #ifdef sun |
42 | #ifdef sparc | |
43 | #define TRY_NEW_EH | |
44 | #endif | |
45 | #endif | |
a4443a08 | 46 | #endif |
8d08fdba | 47 | |
8d2733ca | 48 | #ifndef TRY_NEW_EH |
8d08fdba | 49 | |
8d2733ca MS |
50 | static void |
51 | sorry_no_eh () | |
52 | { | |
53 | static int warned = 0; | |
54 | if (! warned) | |
55 | { | |
56 | sorry ("exception handling not supported"); | |
57 | warned = 1; | |
58 | } | |
59 | } | |
8d08fdba | 60 | |
8d2733ca MS |
61 | void |
62 | expand_exception_blocks () | |
63 | { | |
64 | } | |
8d08fdba | 65 | |
8d2733ca MS |
66 | void |
67 | start_protect () | |
68 | { | |
69 | } | |
8d08fdba | 70 | |
8d2733ca MS |
71 | void |
72 | end_protect (finalization) | |
73 | tree finalization; | |
74 | { | |
75 | } | |
8d08fdba | 76 | |
8d2733ca MS |
77 | void |
78 | expand_start_try_stmts () | |
79 | { | |
80 | sorry_no_eh (); | |
81 | } | |
8d08fdba | 82 | |
8d2733ca MS |
83 | void |
84 | expand_end_try_stmts () | |
85 | { | |
86 | } | |
8d08fdba | 87 | |
8d2733ca MS |
88 | void |
89 | expand_start_all_catch () | |
90 | { | |
91 | } | |
8d08fdba | 92 | |
8d2733ca MS |
93 | void |
94 | expand_end_all_catch () | |
95 | { | |
96 | } | |
8d08fdba | 97 | |
8d2733ca | 98 | void |
a4443a08 MS |
99 | expand_start_catch_block (declspecs, declarator) |
100 | tree declspecs, declarator; | |
8d2733ca MS |
101 | { |
102 | } | |
8d08fdba | 103 | |
8d2733ca MS |
104 | void |
105 | expand_end_catch_block () | |
106 | { | |
107 | } | |
8d08fdba | 108 | |
8d2733ca MS |
109 | void |
110 | init_exception_processing () | |
8d08fdba | 111 | { |
8d2733ca | 112 | } |
8d08fdba | 113 | |
8d2733ca MS |
114 | void |
115 | expand_throw (exp) | |
116 | tree exp; | |
117 | { | |
118 | sorry_no_eh (); | |
119 | } | |
8d08fdba | 120 | |
8d08fdba | 121 | #else |
8d08fdba | 122 | |
8d2733ca MS |
123 | static int |
124 | doing_eh (do_warn) | |
125 | int do_warn; | |
8d08fdba | 126 | { |
8d2733ca | 127 | if (! flag_handle_exceptions) |
8d08fdba | 128 | { |
8d2733ca MS |
129 | static int warned = 0; |
130 | if (! warned && do_warn) | |
8d08fdba | 131 | { |
8d2733ca MS |
132 | error ("exception handling disabled, use -fhandle-exceptions to enable."); |
133 | warned = 1; | |
8d08fdba | 134 | } |
8d2733ca | 135 | return 0; |
8d08fdba | 136 | } |
8d2733ca | 137 | return 1; |
8d08fdba MS |
138 | } |
139 | ||
8d08fdba | 140 | |
8d2733ca MS |
141 | /* |
142 | NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer | |
143 | to supporting exception handling as per Stroustrup's 2nd edition. | |
144 | It is a complete rewrite of all the EH stuff that was here before | |
145 | Shortcomings: | |
146 | 1. The type of the throw and catch must still match | |
147 | exactly (no support yet for matching base classes) | |
148 | 2. Throw specifications of functions still doesnt't work. | |
149 | Cool Things: | |
150 | 1. Destructors are called properly :-) | |
151 | 2. No overhead for the non-exception thrown case. | |
152 | 3. Fixing shortcomings 1 and 2 is simple. | |
153 | -Tad Hunt (tad@mail.csh.rit.edu) | |
154 | ||
155 | */ | |
156 | ||
157 | /* A couple of backend routines from m88k.c */ | |
158 | ||
159 | /* used to cache a call to __builtin_return_address () */ | |
160 | static tree BuiltinReturnAddress; | |
161 | ||
162 | ||
163 | ||
164 | ||
165 | ||
166 | #include <stdio.h> | |
167 | ||
168 | /* XXX - Tad: for EH */ | |
169 | /* output an exception table entry */ | |
170 | ||
171 | static void | |
172 | output_exception_table_entry (file, start_label, end_label, eh_label) | |
173 | FILE *file; | |
174 | rtx start_label, end_label, eh_label; | |
8d08fdba | 175 | { |
8d2733ca | 176 | char label[100]; |
8d08fdba | 177 | |
f376e137 MS |
178 | assemble_integer (start_label, BITS_PER_WORD/BITS_PER_UNIT, 1); |
179 | assemble_integer (end_label, BITS_PER_WORD/BITS_PER_UNIT, 1); | |
180 | assemble_integer (eh_label, BITS_PER_WORD/BITS_PER_UNIT, 1); | |
8d2733ca MS |
181 | putc ('\n', file); /* blank line */ |
182 | } | |
183 | ||
184 | static void | |
185 | easy_expand_asm (str) | |
186 | char *str; | |
187 | { | |
188 | expand_asm (build_string (strlen (str)+1, str)); | |
8d08fdba MS |
189 | } |
190 | ||
8d2733ca MS |
191 | /* unwind the stack. */ |
192 | static void | |
193 | do_unwind (throw_label) | |
194 | rtx throw_label; | |
8d08fdba | 195 | { |
8d2733ca MS |
196 | #ifdef sparc |
197 | extern FILE *asm_out_file; | |
198 | tree fcall; | |
199 | tree params; | |
200 | rtx return_val_rtx; | |
201 | ||
202 | /* call to __builtin_return_address () */ | |
203 | params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); | |
204 | fcall = build_function_call (BuiltinReturnAddress, params); | |
205 | return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0); | |
206 | /* In the return, the new pc is pc+8, as the value comming in is | |
207 | really the address of the call insn, not the next insn. */ | |
208 | emit_move_insn (return_val_rtx, plus_constant(gen_rtx (LABEL_REF, | |
209 | Pmode, | |
210 | throw_label), -8)); | |
a3b49ccd | 211 | /* We use three values, PC, type, and value */ |
8d2733ca MS |
212 | easy_expand_asm ("st %l0,[%fp]"); |
213 | easy_expand_asm ("st %l1,[%fp+4]"); | |
a3b49ccd | 214 | easy_expand_asm ("st %l2,[%fp+8]"); |
8d2733ca MS |
215 | easy_expand_asm ("ret"); |
216 | easy_expand_asm ("restore"); | |
217 | emit_barrier (); | |
218 | #endif | |
219 | #if m88k | |
220 | rtx temp_frame = frame_pointer_rtx; | |
8d08fdba | 221 | |
8d2733ca MS |
222 | temp_frame = memory_address (Pmode, temp_frame); |
223 | temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame)); | |
8d08fdba | 224 | |
8d2733ca MS |
225 | /* hopefully this will successfully pop the frame! */ |
226 | emit_move_insn (frame_pointer_rtx, temp_frame); | |
227 | emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); | |
228 | emit_move_insn (arg_pointer_rtx, frame_pointer_rtx); | |
229 | emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, | |
230 | (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0)))); | |
8d08fdba | 231 | |
8d2733ca MS |
232 | #if 0 |
233 | emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, | |
234 | -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0)))); | |
235 | ||
236 | emit_move_insn (stack_pointer_rtx, arg_pointer_rtx); | |
8d08fdba | 237 | |
8d2733ca MS |
238 | emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, |
239 | (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0)))); | |
240 | #endif | |
241 | #endif | |
8d08fdba MS |
242 | } |
243 | ||
8d08fdba | 244 | |
8d08fdba | 245 | |
8d2733ca MS |
246 | #if 0 |
247 | /* This is the startup, and finish stuff per exception table. */ | |
8d08fdba | 248 | |
8d2733ca MS |
249 | /* XXX - Tad: exception handling section */ |
250 | #ifndef EXCEPT_SECTION_ASM_OP | |
251 | #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits" | |
252 | #endif | |
8d08fdba | 253 | |
8d2733ca MS |
254 | #ifdef EXCEPT_SECTION_ASM_OP |
255 | typedef struct { | |
256 | void *start_protect; | |
257 | void *end_protect; | |
258 | void *exception_handler; | |
259 | } exception_table; | |
260 | #endif /* EXCEPT_SECTION_ASM_OP */ | |
8d08fdba | 261 | |
8d2733ca | 262 | #ifdef EXCEPT_SECTION_ASM_OP |
8d08fdba | 263 | |
8d2733ca MS |
264 | /* on machines which support it, the exception table lives in another section, |
265 | but it needs a label so we can reference it... This sets up that | |
266 | label! */ | |
267 | asm (EXCEPT_SECTION_ASM_OP); | |
268 | exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 }; | |
269 | asm (TEXT_SECTION_ASM_OP); | |
8d08fdba | 270 | |
8d2733ca | 271 | #endif /* EXCEPT_SECTION_ASM_OP */ |
8d08fdba | 272 | |
8d2733ca MS |
273 | #ifdef EXCEPT_SECTION_ASM_OP |
274 | ||
275 | /* we need to know where the end of the exception table is... so this | |
276 | is how we do it! */ | |
277 | ||
278 | asm (EXCEPT_SECTION_ASM_OP); | |
279 | exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 }; | |
280 | asm (TEXT_SECTION_ASM_OP); | |
281 | ||
282 | #endif /* EXCEPT_SECTION_ASM_OP */ | |
283 | ||
284 | #endif | |
8d08fdba MS |
285 | |
286 | void | |
8d2733ca | 287 | exception_section () |
8d08fdba | 288 | { |
8d2733ca MS |
289 | #ifdef ASM_OUTPUT_SECTION_NAME |
290 | named_section (".gcc_except_table"); | |
291 | #else | |
292 | text_section (); | |
8d08fdba | 293 | #endif |
8d08fdba MS |
294 | } |
295 | ||
8d2733ca MS |
296 | |
297 | ||
298 | ||
299 | /* from: my-cp-except.c */ | |
300 | ||
301 | /* VI: ":set ts=4" */ | |
302 | #if 0 | |
303 | #include <stdio.h> */ | |
304 | #include "config.h" | |
305 | #include "tree.h" | |
306 | #include "rtl.h" | |
307 | #include "cp-tree.h" | |
308 | #endif | |
309 | #include "decl.h" | |
310 | #if 0 | |
311 | #include "flags.h" | |
312 | #endif | |
313 | #include "insn-flags.h" | |
314 | #include "obstack.h" | |
315 | #if 0 | |
316 | #include "expr.h" | |
317 | #endif | |
318 | ||
319 | /* ====================================================================== | |
320 | Briefly the algorithm works like this: | |
321 | ||
322 | When a constructor or start of a try block is encountered, | |
323 | push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a | |
324 | new entry in the unwind protection stack and returns a label to | |
325 | output to start the protection for that block. | |
326 | ||
327 | When a destructor or end try block is encountered, pop_eh_entry | |
328 | (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it | |
329 | created when push_eh_entry () was called. The ehEntry structure | |
330 | contains three things at this point. The start protect label, | |
331 | the end protect label, and the exception handler label. The end | |
332 | protect label should be output before the call to the destructor | |
333 | (if any). If it was a destructor, then its parse tree is stored | |
334 | in the finalization variable in the ehEntry structure. Otherwise | |
335 | the finalization variable is set to NULL to reflect the fact that | |
336 | is the the end of a try block. Next, this modified ehEntry node | |
337 | is enqueued in the finalizations queue by calling | |
338 | enqueue_eh_entry (&queue,entry). | |
339 | ||
340 | +---------------------------------------------------------------+ | |
341 | |XXX: Will need modification to deal with partially | | |
342 | | constructed arrays of objects | | |
343 | | | | |
344 | | Basically, this consists of keeping track of how many | | |
345 | | of the objects have been constructed already (this | | |
346 | | should be in a register though, so that shouldn't be a | | |
347 | | problem. | | |
348 | +---------------------------------------------------------------+ | |
349 | ||
350 | When a catch block is encountered, there is a lot of work to be | |
351 | done. | |
352 | ||
353 | Since we don't want to generate the catch block inline with the | |
354 | regular flow of the function, we need to have some way of doing | |
355 | so. Luckily, we have a couple of routines "get_last_insn ()" and | |
356 | "set_last_insn ()" provided. When the start of a catch block is | |
357 | encountered, we save a pointer to the last insn generated. After | |
358 | the catch block is generated, we save a pointer to the first | |
359 | catch block insn and the last catch block insn with the routines | |
360 | "NEXT_INSN ()" and "get_last_insn ()". We then set the last insn | |
361 | to be the last insn generated before the catch block, and set the | |
362 | NEXT_INSN (last_insn) to zero. | |
363 | ||
364 | Since catch blocks might be nested inside other catch blocks, and | |
365 | we munge the chain of generated insns after the catch block is | |
366 | generated, we need to store the pointers to the last insn | |
367 | generated in a stack, so that when the end of a catch block is | |
368 | encountered, the last insn before the current catch block can be | |
369 | popped and set to be the last insn, and the first and last insns | |
370 | of the catch block just generated can be enqueue'd for output at | |
371 | a later time. | |
372 | ||
373 | Next we must insure that when the catch block is executed, all | |
374 | finalizations for the matching try block have been completed. If | |
375 | any of those finalizations throw an exception, we must call | |
376 | terminate according to the ARM (section r.15.6.1). What this | |
377 | means is that we need to dequeue and emit finalizations for each | |
378 | entry in the ehQueue until we get to an entry with a NULL | |
379 | finalization field. For any of the finalization entries, if it | |
380 | is not a call to terminate (), we must protect it by giving it | |
381 | another start label, end label, and exception handler label, | |
382 | setting its finalization tree to be a call to terminate (), and | |
383 | enqueue'ing this new ehEntry to be output at an outer level. | |
384 | Finally, after all that is done, we can get around to outputting | |
385 | the catch block which basically wraps all the "catch (...) {...}" | |
386 | statements in a big if/then/else construct that matches the | |
387 | correct block to call. | |
388 | ||
389 | ===================================================================== */ | |
390 | ||
391 | extern rtx emit_insn PROTO((rtx)); | |
392 | extern rtx gen_nop PROTO(()); | |
8d2733ca MS |
393 | |
394 | /* local globals for function calls | |
395 | ====================================================================== */ | |
396 | ||
397 | /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and | |
398 | "set_unexpected ()" after default_conversion. (lib-except.c) */ | |
399 | static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch; | |
400 | ||
401 | /* used to cache __find_first_exception_table_match () | |
402 | for throw (lib-except.c) */ | |
403 | static tree FirstExceptionMatch; | |
404 | ||
405 | /* used to cache a call to __unwind_function () (lib-except.c) */ | |
406 | static tree Unwind; | |
407 | ||
408 | /* holds a ready to emit call to "terminate ()". */ | |
409 | static tree TerminateFunctionCall; | |
410 | ||
411 | /* ====================================================================== */ | |
412 | ||
413 | ||
414 | ||
415 | /* data structures for my various quick and dirty stacks and queues | |
416 | Eventually, most of this should go away, because I think it can be | |
417 | integrated with stuff already built into the compiler. */ | |
418 | ||
419 | /* =================================================================== */ | |
420 | ||
421 | struct labelNode { | |
422 | rtx label; | |
423 | struct labelNode *chain; | |
424 | }; | |
425 | ||
426 | ||
427 | /* this is the most important structure here. Basically this is how I store | |
428 | an exception table entry internally. */ | |
429 | struct ehEntry { | |
430 | rtx start_label; | |
431 | rtx end_label; | |
432 | rtx exception_handler_label; | |
433 | ||
434 | tree finalization; | |
435 | }; | |
436 | ||
437 | struct ehNode { | |
438 | struct ehEntry *entry; | |
439 | struct ehNode *chain; | |
440 | }; | |
441 | ||
442 | struct ehStack { | |
443 | struct ehNode *top; | |
444 | }; | |
445 | ||
446 | struct ehQueue { | |
447 | struct ehNode *head; | |
448 | struct ehNode *tail; | |
449 | }; | |
450 | ||
451 | struct exceptNode { | |
452 | rtx catchstart; | |
453 | rtx catchend; | |
454 | ||
455 | struct exceptNode *chain; | |
456 | }; | |
457 | ||
458 | struct exceptStack { | |
459 | struct exceptNode *top; | |
460 | }; | |
461 | /* ========================================================================= */ | |
462 | ||
463 | ||
464 | ||
465 | /* local globals - these local globals are for storing data necessary for | |
466 | generating the exception table and code in the correct order. | |
467 | ||
468 | ========================================================================= */ | |
469 | ||
a3b49ccd | 470 | /* Holds the pc for doing "throw" */ |
8d2733ca | 471 | rtx saved_pc; |
a3b49ccd | 472 | /* Holds the type of the thing being thrown. */ |
8d2733ca | 473 | rtx saved_throw_type; |
a3b49ccd MS |
474 | /* Holds the value being thrown. */ |
475 | rtx saved_throw_value; | |
8d2733ca MS |
476 | |
477 | rtx throw_label; | |
478 | ||
479 | static struct ehStack ehstack; | |
480 | static struct ehQueue ehqueue; | |
481 | static struct ehQueue eh_table_output_queue; | |
482 | static struct exceptStack exceptstack; | |
483 | static struct labelNode *false_label_stack = NULL; | |
484 | static struct labelNode *caught_return_label_stack = NULL; | |
485 | /* ========================================================================= */ | |
486 | ||
487 | /* function prototypes */ | |
488 | static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack)); | |
489 | static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry)); | |
490 | static void push_except_stmts PROTO((struct exceptStack *exceptstack, | |
491 | rtx catchstart, rtx catchend)); | |
492 | static int pop_except_stmts PROTO((struct exceptStack *exceptstack, | |
493 | rtx *catchstart, rtx *catchend)); | |
494 | static rtx push_eh_entry PROTO((struct ehStack *stack)); | |
495 | static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue)); | |
496 | static void new_eh_queue PROTO((struct ehQueue *queue)); | |
497 | static void new_eh_stack PROTO((struct ehStack *stack)); | |
498 | static void new_except_stack PROTO((struct exceptStack *queue)); | |
499 | static void push_last_insn PROTO(()); | |
500 | static rtx pop_last_insn PROTO(()); | |
501 | static void push_label_entry PROTO((struct labelNode **labelstack, rtx label)); | |
502 | static rtx pop_label_entry PROTO((struct labelNode **labelstack)); | |
503 | static rtx top_label_entry PROTO((struct labelNode **labelstack)); | |
504 | static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry)); | |
505 | ||
506 | ||
507 | ||
508 | /* All my cheesy stack/queue/misc data structure handling routines | |
509 | ||
510 | ========================================================================= */ | |
511 | ||
512 | static void | |
513 | push_label_entry (labelstack, label) | |
514 | struct labelNode **labelstack; | |
515 | rtx label; | |
8d08fdba | 516 | { |
8d2733ca MS |
517 | struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode)); |
518 | ||
519 | newnode->label = label; | |
520 | newnode->chain = *labelstack; | |
521 | *labelstack = newnode; | |
8d08fdba | 522 | } |
8d08fdba | 523 | |
8d2733ca MS |
524 | static rtx |
525 | pop_label_entry (labelstack) | |
526 | struct labelNode **labelstack; | |
8d08fdba | 527 | { |
8d2733ca MS |
528 | rtx label; |
529 | struct labelNode *tempnode; | |
8d08fdba | 530 | |
8d2733ca | 531 | if (! *labelstack) return NULL_RTX; |
8d08fdba | 532 | |
8d2733ca MS |
533 | tempnode = *labelstack; |
534 | label = tempnode->label; | |
535 | *labelstack = (*labelstack)->chain; | |
536 | free (tempnode); | |
8d08fdba | 537 | |
8d2733ca MS |
538 | return label; |
539 | } | |
8d08fdba | 540 | |
8d2733ca MS |
541 | static rtx |
542 | top_label_entry (labelstack) | |
543 | struct labelNode **labelstack; | |
544 | { | |
545 | if (! *labelstack) return NULL_RTX; | |
8d08fdba | 546 | |
8d2733ca | 547 | return (*labelstack)->label; |
8d08fdba MS |
548 | } |
549 | ||
8d2733ca MS |
550 | static void |
551 | push_except_stmts (exceptstack, catchstart, catchend) | |
552 | struct exceptStack *exceptstack; | |
553 | rtx catchstart, catchend; | |
8d08fdba | 554 | { |
8d2733ca MS |
555 | struct exceptNode *newnode = (struct exceptNode*) |
556 | xmalloc (sizeof (struct exceptNode)); | |
8d08fdba | 557 | |
8d2733ca MS |
558 | newnode->catchstart = catchstart; |
559 | newnode->catchend = catchend; | |
560 | newnode->chain = exceptstack->top; | |
8d08fdba | 561 | |
8d2733ca MS |
562 | exceptstack->top = newnode; |
563 | } | |
8d08fdba | 564 | |
8d2733ca MS |
565 | static int |
566 | pop_except_stmts (exceptstack, catchstart, catchend) | |
567 | struct exceptStack *exceptstack; | |
568 | rtx *catchstart, *catchend; | |
569 | { | |
570 | struct exceptNode *tempnode; | |
8d08fdba | 571 | |
8d2733ca MS |
572 | if (!exceptstack->top) { |
573 | *catchstart = *catchend = NULL_RTX; | |
574 | return 0; | |
575 | } | |
8d08fdba | 576 | |
8d2733ca MS |
577 | tempnode = exceptstack->top; |
578 | exceptstack->top = exceptstack->top->chain; | |
579 | ||
580 | *catchstart = tempnode->catchstart; | |
581 | *catchend = tempnode->catchend; | |
582 | free (tempnode); | |
8d08fdba | 583 | |
8d2733ca | 584 | return 1; |
8d08fdba MS |
585 | } |
586 | ||
8d2733ca MS |
587 | /* Push to permanent obstack for rtl generation. |
588 | One level only! */ | |
589 | static struct obstack *saved_rtl_obstack; | |
8d08fdba | 590 | void |
8d2733ca | 591 | push_rtl_perm () |
8d08fdba | 592 | { |
8d2733ca MS |
593 | extern struct obstack permanent_obstack; |
594 | extern struct obstack *rtl_obstack; | |
595 | ||
596 | saved_rtl_obstack = rtl_obstack; | |
597 | rtl_obstack = &permanent_obstack; | |
598 | } | |
8d08fdba | 599 | |
8d2733ca MS |
600 | /* Pop back to normal rtl handling. */ |
601 | static void | |
602 | pop_rtl_from_perm () | |
603 | { | |
604 | extern struct obstack permanent_obstack; | |
605 | extern struct obstack *rtl_obstack; | |
606 | ||
607 | rtl_obstack = saved_rtl_obstack; | |
608 | } | |
8d08fdba | 609 | |
8d2733ca MS |
610 | static rtx |
611 | push_eh_entry (stack) | |
612 | struct ehStack *stack; | |
613 | { | |
614 | struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode)); | |
615 | struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry)); | |
8d08fdba | 616 | |
8d2733ca MS |
617 | if (stack == NULL) { |
618 | free (node); | |
619 | free (entry); | |
620 | return NULL_RTX; | |
621 | } | |
622 | ||
623 | /* These are saved for the exception table. */ | |
624 | push_rtl_perm (); | |
625 | entry->start_label = gen_label_rtx (); | |
626 | entry->end_label = gen_label_rtx (); | |
627 | entry->exception_handler_label = gen_label_rtx (); | |
628 | pop_rtl_from_perm (); | |
629 | ||
630 | entry->finalization = NULL_TREE; | |
8d08fdba | 631 | |
8d2733ca MS |
632 | node->entry = entry; |
633 | node->chain = stack->top; | |
634 | stack->top = node; | |
635 | ||
636 | enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry)); | |
637 | ||
638 | return entry->start_label; | |
8d08fdba MS |
639 | } |
640 | ||
8d2733ca MS |
641 | static struct ehEntry * |
642 | pop_eh_entry (stack) | |
643 | struct ehStack *stack; | |
8d08fdba | 644 | { |
8d2733ca MS |
645 | struct ehNode *tempnode; |
646 | struct ehEntry *tempentry; | |
647 | ||
648 | if (stack && (tempnode = stack->top)) { | |
649 | tempentry = tempnode->entry; | |
650 | stack->top = stack->top->chain; | |
651 | free (tempnode); | |
652 | ||
653 | return tempentry; | |
654 | } | |
655 | ||
656 | return NULL; | |
8d08fdba MS |
657 | } |
658 | ||
8d2733ca MS |
659 | static struct ehEntry * |
660 | copy_eh_entry (entry) | |
661 | struct ehEntry *entry; | |
8d08fdba | 662 | { |
8d2733ca | 663 | struct ehEntry *newentry; |
8d08fdba | 664 | |
8d2733ca MS |
665 | newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry)); |
666 | memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry)); | |
8d08fdba | 667 | |
8d2733ca MS |
668 | return newentry; |
669 | } | |
8d08fdba | 670 | |
8d2733ca MS |
671 | static void |
672 | enqueue_eh_entry (queue, entry) | |
673 | struct ehQueue *queue; | |
674 | struct ehEntry *entry; | |
675 | { | |
676 | struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode)); | |
8d08fdba | 677 | |
8d2733ca MS |
678 | node->entry = entry; |
679 | node->chain = NULL; | |
8d08fdba | 680 | |
8d2733ca | 681 | if (queue->head == NULL) |
8d08fdba | 682 | { |
8d2733ca | 683 | queue->head = node; |
8d08fdba | 684 | } |
8d2733ca | 685 | else |
8d08fdba | 686 | { |
8d2733ca | 687 | queue->tail->chain = node; |
8d08fdba | 688 | } |
8d2733ca | 689 | queue->tail = node; |
8d08fdba MS |
690 | } |
691 | ||
8d2733ca MS |
692 | static struct ehEntry * |
693 | dequeue_eh_entry (queue) | |
694 | struct ehQueue *queue; | |
695 | { | |
696 | struct ehNode *tempnode; | |
697 | struct ehEntry *tempentry; | |
698 | ||
699 | if (queue->head == NULL) | |
700 | return NULL; | |
701 | ||
702 | tempnode = queue->head; | |
703 | queue->head = queue->head->chain; | |
704 | ||
705 | tempentry = tempnode->entry; | |
706 | free (tempnode); | |
707 | ||
708 | return tempentry; | |
709 | } | |
710 | ||
711 | static void | |
712 | new_eh_queue (queue) | |
713 | struct ehQueue *queue; | |
714 | { | |
715 | queue->head = queue->tail = NULL; | |
716 | } | |
717 | ||
718 | static void | |
719 | new_eh_stack (stack) | |
720 | struct ehStack *stack; | |
721 | { | |
722 | stack->top = NULL; | |
723 | } | |
724 | ||
725 | static void | |
726 | new_except_stack (stack) | |
727 | struct exceptStack *stack; | |
728 | { | |
729 | stack->top = NULL; | |
730 | } | |
731 | /* ========================================================================= */ | |
732 | ||
a3b49ccd MS |
733 | void |
734 | lang_interim_eh (finalization) | |
735 | tree finalization; | |
736 | { | |
737 | if (finalization) | |
738 | end_protect (finalization); | |
739 | else | |
740 | start_protect (); | |
741 | } | |
8d2733ca MS |
742 | |
743 | /* sets up all the global eh stuff that needs to be initialized at the | |
744 | start of compilation. | |
745 | ||
746 | This includes: | |
747 | - Setting up all the function call trees | |
748 | - Initializing the ehqueue | |
749 | - Initializing the eh_table_output_queue | |
750 | - Initializing the ehstack | |
751 | - Initializing the exceptstack | |
752 | */ | |
8d08fdba | 753 | |
8d08fdba | 754 | void |
8d2733ca | 755 | init_exception_processing () |
8d08fdba | 756 | { |
8d2733ca MS |
757 | extern tree define_function (); |
758 | tree unexpected_fndecl, terminate_fndecl; | |
759 | tree set_unexpected_fndecl, set_terminate_fndecl; | |
760 | tree catch_match_fndecl; | |
761 | tree find_first_exception_match_fndecl; | |
762 | tree unwind_fndecl; | |
763 | tree temp, PFV; | |
8d08fdba | 764 | |
a3b49ccd MS |
765 | interim_eh_hook = lang_interim_eh; |
766 | ||
8d2733ca MS |
767 | /* void (*)() */ |
768 | PFV = build_pointer_type (build_function_type (void_type_node, void_list_node)); | |
8d08fdba | 769 | |
8d2733ca MS |
770 | /* arg list for the build_function_type call for set_terminate () and |
771 | set_unexpected () */ | |
772 | temp = tree_cons (NULL_TREE, PFV, void_list_node); | |
8d08fdba | 773 | |
8d2733ca MS |
774 | push_lang_context (lang_name_c); |
775 | ||
776 | set_terminate_fndecl = | |
777 | define_function ("set_terminate", | |
778 | build_function_type (PFV, temp), | |
779 | NOT_BUILT_IN, | |
780 | pushdecl, | |
781 | 0); | |
782 | set_unexpected_fndecl = | |
783 | define_function ("set_unexpected", | |
784 | build_function_type (PFV, temp), | |
785 | NOT_BUILT_IN, | |
786 | pushdecl, | |
787 | 0); | |
788 | ||
789 | unexpected_fndecl = | |
790 | define_function ("unexpected", | |
791 | build_function_type (void_type_node, void_list_node), | |
792 | NOT_BUILT_IN, | |
793 | pushdecl, | |
794 | 0); | |
795 | terminate_fndecl = | |
796 | define_function ("terminate", | |
797 | build_function_type (void_type_node, void_list_node), | |
798 | NOT_BUILT_IN, | |
799 | pushdecl, | |
800 | 0); | |
801 | catch_match_fndecl = | |
802 | define_function ("__throw_type_match", | |
803 | build_function_type (integer_type_node, | |
a4443a08 | 804 | tree_cons (NULL_TREE, string_type_node, tree_cons (NULL_TREE, ptr_type_node, void_list_node))), |
8d2733ca MS |
805 | NOT_BUILT_IN, |
806 | pushdecl, | |
807 | 0); | |
808 | find_first_exception_match_fndecl = | |
809 | define_function ("__find_first_exception_table_match", | |
810 | build_function_type (ptr_type_node, | |
811 | tree_cons (NULL_TREE, ptr_type_node, | |
812 | void_list_node)), | |
813 | NOT_BUILT_IN, | |
814 | pushdecl, | |
815 | 0); | |
816 | unwind_fndecl = | |
817 | define_function ("__unwind_function", | |
818 | build_function_type (void_type_node, | |
819 | tree_cons (NULL_TREE, ptr_type_node, void_list_node)), | |
820 | NOT_BUILT_IN, | |
821 | pushdecl, | |
822 | 0); | |
823 | ||
824 | Unexpected = default_conversion (unexpected_fndecl); | |
825 | Terminate = default_conversion (terminate_fndecl); | |
826 | SetTerminate = default_conversion (set_terminate_fndecl); | |
827 | SetUnexpected = default_conversion (set_unexpected_fndecl); | |
828 | CatchMatch = default_conversion (catch_match_fndecl); | |
829 | FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl); | |
830 | Unwind = default_conversion (unwind_fndecl); | |
831 | BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl); | |
832 | ||
833 | TerminateFunctionCall = build_function_call (Terminate, NULL_TREE); | |
834 | ||
835 | pop_lang_context (); | |
836 | throw_label = gen_label_rtx (); | |
837 | saved_pc = gen_rtx (REG, Pmode, 16); | |
838 | saved_throw_type = gen_rtx (REG, Pmode, 17); | |
a3b49ccd | 839 | saved_throw_value = gen_rtx (REG, Pmode, 18); |
8d2733ca MS |
840 | |
841 | new_eh_queue (&ehqueue); | |
842 | new_eh_queue (&eh_table_output_queue); | |
843 | new_eh_stack (&ehstack); | |
844 | new_except_stack (&exceptstack); | |
845 | } | |
846 | ||
847 | /* call this to begin a block of unwind protection (ie: when an object is | |
848 | constructed) */ | |
849 | void | |
850 | start_protect () | |
851 | { | |
852 | if (doing_eh (0)) | |
8d08fdba | 853 | { |
8d2733ca | 854 | emit_label (push_eh_entry (&ehstack)); |
8d08fdba | 855 | } |
8d2733ca MS |
856 | } |
857 | ||
858 | /* call this to end a block of unwind protection. the finalization tree is | |
859 | the finalization which needs to be run in order to cleanly unwind through | |
860 | this level of protection. (ie: call this when a scope is exited)*/ | |
861 | void | |
862 | end_protect (finalization) | |
863 | tree finalization; | |
864 | { | |
865 | struct ehEntry *entry = pop_eh_entry (&ehstack); | |
8d08fdba | 866 | |
8d2733ca MS |
867 | if (! doing_eh (0)) |
868 | return; | |
8d08fdba | 869 | |
8d2733ca | 870 | emit_label (entry->end_label); |
8d08fdba | 871 | |
8d2733ca MS |
872 | entry->finalization = finalization; |
873 | ||
874 | enqueue_eh_entry (&ehqueue, entry); | |
875 | } | |
8d08fdba | 876 | |
8d2733ca MS |
877 | /* call this on start of a try block. */ |
878 | void | |
879 | expand_start_try_stmts () | |
880 | { | |
881 | if (doing_eh (1)) | |
8d08fdba | 882 | { |
8d2733ca | 883 | start_protect (); |
8d08fdba | 884 | } |
8d2733ca | 885 | } |
8d08fdba | 886 | |
8d2733ca MS |
887 | void |
888 | expand_end_try_stmts () | |
889 | { | |
890 | end_protect (integer_zero_node); | |
8d08fdba MS |
891 | } |
892 | ||
8d2733ca MS |
893 | struct insn_save_node { |
894 | rtx last; | |
895 | struct insn_save_node *chain; | |
896 | }; | |
8d08fdba | 897 | |
8d2733ca MS |
898 | static struct insn_save_node *InsnSave = NULL; |
899 | ||
900 | ||
901 | /* Used to keep track of where the catch blocks start. */ | |
902 | static void | |
903 | push_last_insn () | |
8d08fdba | 904 | { |
8d2733ca MS |
905 | struct insn_save_node *newnode = (struct insn_save_node*) |
906 | xmalloc (sizeof (struct insn_save_node)); | |
8d08fdba | 907 | |
8d2733ca MS |
908 | newnode->last = get_last_insn (); |
909 | newnode->chain = InsnSave; | |
910 | InsnSave = newnode; | |
8d08fdba MS |
911 | } |
912 | ||
8d2733ca MS |
913 | /* Use to keep track of where the catch blocks start. */ |
914 | static rtx | |
915 | pop_last_insn () | |
916 | { | |
917 | struct insn_save_node *tempnode; | |
918 | rtx temprtx; | |
919 | ||
920 | if (!InsnSave) return NULL_RTX; | |
921 | ||
922 | tempnode = InsnSave; | |
923 | temprtx = tempnode->last; | |
924 | InsnSave = InsnSave->chain; | |
925 | ||
926 | free (tempnode); | |
927 | ||
928 | return temprtx; | |
929 | } | |
8d08fdba | 930 | |
8d2733ca | 931 | /* call this to start processing of all the catch blocks. */ |
8d08fdba | 932 | void |
8d2733ca | 933 | expand_start_all_catch () |
8d08fdba | 934 | { |
8d2733ca MS |
935 | struct ehEntry *entry; |
936 | rtx label; | |
937 | ||
938 | if (! doing_eh (1)) | |
939 | return; | |
940 | ||
941 | emit_line_note (input_filename, lineno); | |
942 | label = gen_label_rtx (); | |
943 | /* The label for the exception handling block we will save. */ | |
944 | emit_label (label); | |
a3b49ccd | 945 | |
8d2733ca MS |
946 | push_label_entry (&caught_return_label_stack, label); |
947 | ||
948 | /* Remember where we started. */ | |
949 | push_last_insn (); | |
950 | ||
a3b49ccd MS |
951 | emit_insn (gen_nop ()); |
952 | ||
8d2733ca MS |
953 | /* Will this help us not stomp on it? */ |
954 | emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type)); | |
a3b49ccd | 955 | emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value)); |
8d2733ca MS |
956 | |
957 | while (1) | |
8d08fdba | 958 | { |
8d2733ca MS |
959 | entry = dequeue_eh_entry (&ehqueue); |
960 | emit_label (entry->exception_handler_label); | |
961 | ||
962 | expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); | |
963 | ||
964 | /* When we get down to the matching entry, stop. */ | |
965 | if (entry->finalization == integer_zero_node) | |
966 | break; | |
967 | ||
968 | free (entry); | |
969 | } | |
970 | ||
971 | /* This goes when the below moves out of our way. */ | |
8d08fdba | 972 | #if 1 |
8d2733ca MS |
973 | label = gen_label_rtx (); |
974 | emit_jump (label); | |
8d08fdba | 975 | #endif |
8d2733ca MS |
976 | |
977 | /* All this should be out of line, and saved back in the exception handler | |
978 | block area. */ | |
979 | #if 1 | |
980 | entry->start_label = entry->exception_handler_label; | |
981 | /* These are saved for the exception table. */ | |
982 | push_rtl_perm (); | |
983 | entry->end_label = gen_label_rtx (); | |
984 | entry->exception_handler_label = gen_label_rtx (); | |
985 | entry->finalization = TerminateFunctionCall; | |
986 | pop_rtl_from_perm (); | |
987 | emit_label (entry->end_label); | |
988 | ||
8d2733ca MS |
989 | enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry)); |
990 | ||
991 | /* After running the finalization, continue on out to the next | |
992 | cleanup, if we have nothing better to do. */ | |
993 | emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry->end_label)); | |
994 | /* Will this help us not stomp on it? */ | |
995 | emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type)); | |
a3b49ccd | 996 | emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value)); |
8d2733ca MS |
997 | emit_jump (throw_label); |
998 | emit_label (entry->exception_handler_label); | |
999 | expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); | |
1000 | emit_barrier (); | |
8d08fdba | 1001 | #endif |
8d2733ca MS |
1002 | emit_label (label); |
1003 | } | |
8d08fdba | 1004 | |
8d2733ca MS |
1005 | /* call this to end processing of all the catch blocks. */ |
1006 | void | |
1007 | expand_end_all_catch () | |
1008 | { | |
1009 | rtx catchstart, catchend, last; | |
1010 | rtx label; | |
8d08fdba | 1011 | |
8d2733ca MS |
1012 | if (! doing_eh (1)) |
1013 | return; | |
8d08fdba | 1014 | |
8d2733ca MS |
1015 | /* Find the start of the catch block. */ |
1016 | last = pop_last_insn (); | |
1017 | catchstart = NEXT_INSN (last); | |
1018 | catchend = get_last_insn (); | |
8d08fdba | 1019 | |
8d2733ca MS |
1020 | NEXT_INSN (last) = 0; |
1021 | set_last_insn (last); | |
8d08fdba | 1022 | |
8d2733ca MS |
1023 | /* this level of catch blocks is done, so set up the successful catch jump |
1024 | label for the next layer of catch blocks. */ | |
1025 | pop_label_entry (&caught_return_label_stack); | |
8d08fdba | 1026 | |
8d2733ca MS |
1027 | push_except_stmts (&exceptstack, catchstart, catchend); |
1028 | ||
a3b49ccd | 1029 | /* Here we fall through into the continuation code. */ |
8d08fdba MS |
1030 | } |
1031 | ||
8d2733ca MS |
1032 | |
1033 | /* this is called from expand_exception_blocks () to expand the toplevel | |
1034 | finalizations for a function. */ | |
1035 | void | |
1036 | expand_leftover_cleanups () | |
8d08fdba | 1037 | { |
8d2733ca MS |
1038 | struct ehEntry *entry; |
1039 | rtx first_label = NULL_RTX; | |
8d08fdba | 1040 | |
8d2733ca MS |
1041 | if (! doing_eh (0)) |
1042 | return; | |
1043 | ||
1044 | /* Will this help us not stomp on it? */ | |
1045 | emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type)); | |
a3b49ccd | 1046 | emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value)); |
8d2733ca MS |
1047 | |
1048 | while ((entry = dequeue_eh_entry (&ehqueue)) != 0) | |
8d08fdba | 1049 | { |
8d2733ca MS |
1050 | if (! first_label) |
1051 | first_label = entry->exception_handler_label; | |
1052 | emit_label (entry->exception_handler_label); | |
1053 | ||
1054 | expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); | |
8d08fdba | 1055 | |
8d2733ca MS |
1056 | /* leftover try block, opps. */ |
1057 | if (entry->finalization == integer_zero_node) | |
1058 | abort (); | |
1059 | ||
1060 | free (entry); | |
1061 | } | |
1062 | if (first_label) | |
8d08fdba | 1063 | { |
8d2733ca MS |
1064 | rtx label; |
1065 | struct ehEntry entry; | |
1066 | /* These are saved for the exception table. */ | |
1067 | push_rtl_perm (); | |
1068 | label = gen_label_rtx (); | |
1069 | entry.start_label = first_label; | |
1070 | entry.end_label = label; | |
1071 | entry.exception_handler_label = gen_label_rtx (); | |
1072 | entry.finalization = TerminateFunctionCall; | |
1073 | pop_rtl_from_perm (); | |
1074 | emit_label (label); | |
1075 | ||
1076 | enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry)); | |
1077 | ||
1078 | /* After running the finalization, continue on out to the next | |
1079 | cleanup, if we have nothing better to do. */ | |
1080 | emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry.end_label)); | |
1081 | /* Will this help us not stomp on it? */ | |
1082 | emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type)); | |
a3b49ccd | 1083 | emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value)); |
8d2733ca MS |
1084 | emit_jump (throw_label); |
1085 | emit_label (entry.exception_handler_label); | |
1086 | expand_expr (entry.finalization, const0_rtx, VOIDmode, 0); | |
1087 | emit_barrier (); | |
8d08fdba | 1088 | } |
8d08fdba | 1089 | } |
8d08fdba | 1090 | |
8d2733ca MS |
1091 | /* call this to start a catch block. Typename is the typename, and identifier |
1092 | is the variable to place the object in or NULL if the variable doesn't | |
1093 | matter. If typename is NULL, that means its a "catch (...)" or catch | |
1094 | everything. In that case we don't need to do any type checking. | |
1095 | (ie: it ends up as the "else" clause rather than an "else if" clause) */ | |
8d08fdba | 1096 | void |
a4443a08 MS |
1097 | expand_start_catch_block (declspecs, declarator) |
1098 | tree declspecs, declarator; | |
8d08fdba | 1099 | { |
8d2733ca | 1100 | rtx false_label_rtx; |
a3b49ccd | 1101 | rtx protect_label_rtx; |
8d2733ca | 1102 | tree type; |
a4443a08 | 1103 | tree decl; |
a3b49ccd | 1104 | tree init; |
8d2733ca MS |
1105 | |
1106 | if (! doing_eh (1)) | |
1107 | return; | |
1108 | ||
a3b49ccd MS |
1109 | /* Create a binding level for the parm. */ |
1110 | expand_start_bindings (0); | |
1111 | ||
a4443a08 MS |
1112 | if (declspecs) |
1113 | { | |
a3b49ccd MS |
1114 | tree init_type; |
1115 | decl = grokdeclarator (declarator, declspecs, NORMAL, 1, NULL_TREE); | |
1116 | ||
1117 | /* Figure out the type that the initializer is. */ | |
1118 | init_type = TREE_TYPE (decl); | |
1119 | if (TREE_CODE (init_type) != REFERENCE_TYPE) | |
1120 | init_type = build_reference_type (init_type); | |
1121 | ||
1122 | init = convert_from_reference (save_expr (make_tree (init_type, saved_throw_value))); | |
1123 | ||
1124 | /* Do we need the below two lines? */ | |
1125 | /* Let `finish_decl' know that this initializer is ok. */ | |
1126 | DECL_INITIAL (decl) = init; | |
1127 | /* This needs to be preallocated under the try block, | |
1128 | in a union of all catch variables. */ | |
1129 | pushdecl (decl); | |
a4443a08 | 1130 | type = TREE_TYPE (decl); |
a3b49ccd MS |
1131 | |
1132 | /* peel back references, so they match. */ | |
1133 | if (TREE_CODE (type) == REFERENCE_TYPE) | |
1134 | type = TREE_TYPE (type); | |
a4443a08 | 1135 | } |
8d2733ca MS |
1136 | else |
1137 | type = NULL_TREE; | |
1138 | ||
1139 | false_label_rtx = gen_label_rtx (); | |
1140 | push_label_entry (&false_label_stack, false_label_rtx); | |
1141 | ||
a3b49ccd MS |
1142 | /* This is saved for the exception table. */ |
1143 | push_rtl_perm (); | |
1144 | protect_label_rtx = gen_label_rtx (); | |
1145 | pop_rtl_from_perm (); | |
1146 | push_label_entry (&false_label_stack, protect_label_rtx); | |
1147 | ||
8d2733ca | 1148 | if (type) |
8d08fdba | 1149 | { |
8d2733ca MS |
1150 | tree params; |
1151 | char *typestring; | |
1152 | rtx call_rtx, return_value_rtx; | |
1153 | tree catch_match_fcall; | |
1154 | tree catchmatch_arg, argval; | |
1155 | ||
1156 | typestring = build_overload_name (type, 1, 1); | |
1157 | ||
1158 | params = tree_cons (NULL_TREE, | |
1159 | combine_strings (build_string (strlen (typestring)+1, typestring)), | |
1160 | tree_cons (NULL_TREE, | |
1161 | make_tree (ptr_type_node, saved_throw_type), | |
1162 | NULL_TREE)); | |
1163 | catch_match_fcall = build_function_call (CatchMatch, params); | |
1164 | call_rtx = expand_call (catch_match_fcall, NULL_RTX, 0); | |
1165 | ||
1166 | return_value_rtx = | |
1167 | hard_function_value (integer_type_node, catch_match_fcall); | |
1168 | ||
1169 | /* did the throw type match function return TRUE? */ | |
1170 | emit_cmp_insn (return_value_rtx, const0_rtx, NE, NULL_RTX, | |
1171 | GET_MODE (return_value_rtx), 0, 0); | |
1172 | ||
1173 | /* if it returned FALSE, jump over the catch block, else fall into it */ | |
1174 | emit_jump_insn (gen_bne (false_label_rtx)); | |
a3b49ccd | 1175 | finish_decl (decl, init, NULL_TREE, 0); |
8d08fdba MS |
1176 | } |
1177 | else | |
1178 | { | |
8d2733ca | 1179 | /* Fall into the catch all section. */ |
8d08fdba | 1180 | } |
a3b49ccd MS |
1181 | |
1182 | /* This is the starting of something to protect. */ | |
1183 | emit_label (protect_label_rtx); | |
1184 | ||
8d2733ca | 1185 | emit_line_note (input_filename, lineno); |
8d08fdba MS |
1186 | } |
1187 | ||
8d08fdba | 1188 | |
8d2733ca MS |
1189 | /* Call this to end a catch block. Its responsible for emitting the |
1190 | code to handle jumping back to the correct place, and for emitting | |
1191 | the label to jump to if this catch block didn't match. */ | |
1192 | void expand_end_catch_block () | |
8d08fdba | 1193 | { |
8d2733ca | 1194 | if (doing_eh (1)) |
8d08fdba | 1195 | { |
a3b49ccd MS |
1196 | rtx start_protect_label_rtx; |
1197 | rtx end_protect_label_rtx; | |
1198 | tree decls; | |
1199 | struct ehEntry entry; | |
1200 | ||
8d2733ca MS |
1201 | /* label we jump to if we caught the exception */ |
1202 | emit_jump (top_label_entry (&caught_return_label_stack)); | |
1203 | ||
a3b49ccd MS |
1204 | /* Code to throw out to outer context, if we get an throw from within |
1205 | our catch handler. */ | |
1206 | /* These are saved for the exception table. */ | |
1207 | push_rtl_perm (); | |
1208 | entry.exception_handler_label = gen_label_rtx (); | |
1209 | pop_rtl_from_perm (); | |
1210 | emit_label (entry.exception_handler_label); | |
1211 | emit_move_insn (saved_pc, gen_rtx (LABEL_REF, | |
1212 | Pmode, | |
1213 | top_label_entry (&caught_return_label_stack))); | |
1214 | emit_jump (throw_label); | |
1215 | /* No associated finalization. */ | |
1216 | entry.finalization = NULL_TREE; | |
1217 | ||
1218 | /* Because we are reordered out of line, we have to protect this. */ | |
1219 | /* label for the start of the protection region. */ | |
1220 | start_protect_label_rtx = pop_label_entry (&false_label_stack); | |
1221 | ||
1222 | /* Cleanup the EH paramater. */ | |
1223 | expand_end_bindings (decls = getdecls (), decls != NULL_TREE, 0); | |
1224 | ||
8d2733ca | 1225 | /* label we emit to jump to if this catch block didn't match. */ |
a3b49ccd MS |
1226 | emit_label (end_protect_label_rtx = pop_label_entry (&false_label_stack)); |
1227 | ||
1228 | /* Because we are reordered out of line, we have to protect this. */ | |
1229 | entry.start_label = start_protect_label_rtx; | |
1230 | entry.end_label = end_protect_label_rtx; | |
1231 | ||
1232 | /* These set up a call to throw the caught exception into the outer | |
1233 | context. */ | |
1234 | enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry)); | |
8d08fdba | 1235 | } |
8d2733ca | 1236 | } |
8d08fdba | 1237 | |
8d2733ca MS |
1238 | /* cheesyness to save some typing. returns the return value rtx */ |
1239 | rtx | |
1240 | do_function_call (func, params, return_type) | |
1241 | tree func, params, return_type; | |
1242 | { | |
1243 | tree func_call; | |
1244 | func_call = build_function_call (func, params); | |
1245 | expand_call (func_call, NULL_RTX, 0); | |
1246 | if (return_type != NULL_TREE) | |
1247 | return hard_function_value (return_type, func_call); | |
1248 | return NULL_RTX; | |
1249 | } | |
8d08fdba | 1250 | |
8d08fdba | 1251 | |
8d2733ca MS |
1252 | /* is called from expand_excpetion_blocks () to generate the code in a function |
1253 | to "throw" if anything in the function needs to preform a throw. | |
8d08fdba | 1254 | |
8d2733ca MS |
1255 | expands "throw" as the following psuedo code: |
1256 | ||
1257 | throw: | |
1258 | eh = find_first_exception_match (saved_pc); | |
1259 | if (!eh) goto gotta_rethrow_it; | |
1260 | goto eh; | |
1261 | ||
1262 | gotta_rethrow_it: | |
1263 | saved_pc = __builtin_return_address (0); | |
1264 | pop_to_previous_level (); | |
1265 | goto throw; | |
1266 | ||
1267 | */ | |
1268 | static void | |
1269 | expand_builtin_throw () | |
1270 | { | |
1271 | tree fcall; | |
1272 | tree params; | |
1273 | rtx return_val_rtx; | |
1274 | rtx gotta_rethrow_it = gen_label_rtx (); | |
1275 | rtx gotta_call_terminate = gen_label_rtx (); | |
1276 | rtx unwind_and_throw = gen_label_rtx (); | |
1277 | rtx goto_unwind_and_throw = gen_label_rtx (); | |
1278 | ||
1279 | emit_label (throw_label); | |
1280 | ||
1281 | /* search for an exception handler for the saved_pc */ | |
1282 | return_val_rtx = do_function_call (FirstExceptionMatch, | |
1283 | tree_cons (NULL_TREE, make_tree (ptr_type_node, saved_pc), NULL_TREE), | |
1284 | ptr_type_node); | |
1285 | ||
1286 | /* did we find one? */ | |
1287 | emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX, | |
1288 | GET_MODE (return_val_rtx), 0, 0); | |
1289 | ||
1290 | /* if not, jump to gotta_rethrow_it */ | |
1291 | emit_jump_insn (gen_beq (gotta_rethrow_it)); | |
1292 | ||
1293 | /* we found it, so jump to it */ | |
1294 | emit_indirect_jump (return_val_rtx); | |
1295 | ||
1296 | /* code to deal with unwinding and looking for it again */ | |
1297 | emit_label (gotta_rethrow_it); | |
1298 | ||
1299 | /* call to __builtin_return_address () */ | |
1300 | params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); | |
1301 | fcall = build_function_call (BuiltinReturnAddress, params); | |
1302 | return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0); | |
1303 | ||
1304 | /* did __builtin_return_address () return a valid address? */ | |
1305 | emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX, | |
1306 | GET_MODE (return_val_rtx), 0, 0); | |
1307 | ||
1308 | emit_jump_insn (gen_beq (gotta_call_terminate)); | |
1309 | ||
1310 | /* yes it did */ | |
1311 | emit_move_insn (saved_pc, return_val_rtx); | |
1312 | do_unwind (throw_label); | |
1313 | emit_jump (throw_label); | |
1314 | ||
1315 | /* no it didn't --> therefore we need to call terminate */ | |
1316 | emit_label (gotta_call_terminate); | |
1317 | do_function_call (Terminate, NULL_TREE, NULL_TREE); | |
8d08fdba | 1318 | } |
8d2733ca MS |
1319 | |
1320 | ||
1321 | /* This is called to expand all the toplevel exception handling | |
1322 | finalization for a function. It should only be called once per | |
1323 | function. */ | |
8d08fdba | 1324 | void |
8d2733ca | 1325 | expand_exception_blocks () |
8d08fdba | 1326 | { |
8d2733ca MS |
1327 | rtx catchstart, catchend; |
1328 | rtx last; | |
1329 | static rtx funcend; | |
1330 | ||
1331 | funcend = gen_label_rtx (); | |
1332 | emit_jump (funcend); | |
1333 | /* expand_null_return (); */ | |
1334 | ||
1335 | while (pop_except_stmts (&exceptstack, &catchstart, &catchend)) { | |
1336 | last = get_last_insn (); | |
1337 | NEXT_INSN (last) = catchstart; | |
1338 | PREV_INSN (catchstart) = last; | |
1339 | NEXT_INSN (catchend) = 0; | |
1340 | set_last_insn (catchend); | |
1341 | } | |
1342 | ||
1343 | expand_leftover_cleanups (); | |
1344 | ||
1345 | { | |
1346 | static int have_done = 0; | |
1347 | if (! have_done && TREE_PUBLIC (current_function_decl) | |
1348 | && ! DECL_INLINE (current_function_decl)) | |
1349 | { | |
1350 | have_done = 1; | |
1351 | expand_builtin_throw (); | |
1352 | } | |
1353 | } | |
1354 | emit_label (funcend); | |
8d08fdba MS |
1355 | } |
1356 | ||
8d2733ca MS |
1357 | |
1358 | /* call this to expand a throw statement. This follows the following | |
1359 | algorithm: | |
1360 | ||
1361 | 1. Allocate space to save the current PC onto the stack. | |
1362 | 2. Generate and emit a label and save its address into the | |
1363 | newly allocate stack space since we can't save the pc directly. | |
1364 | 3. If this is the first call to throw in this function: | |
1365 | generate a label for the throw block | |
1366 | 4. jump to the throw block label. */ | |
8d08fdba | 1367 | void |
8d2733ca MS |
1368 | expand_throw (exp) |
1369 | tree exp; | |
8d08fdba | 1370 | { |
8d2733ca MS |
1371 | rtx label; |
1372 | tree type; | |
8d08fdba | 1373 | |
8d2733ca MS |
1374 | if (! doing_eh (1)) |
1375 | return; | |
8d08fdba | 1376 | |
a3b49ccd MS |
1377 | /* This is the label that represents where in the code we were, when |
1378 | we got an exception. This needs to be updated when we rethrow an | |
1379 | exception, so that the matching routine knows to search out. */ | |
8d2733ca MS |
1380 | label = gen_label_rtx (); |
1381 | emit_label (label); | |
1382 | emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, label)); | |
1383 | ||
1384 | if (exp) | |
1385 | { | |
a3b49ccd | 1386 | /* throw expression */ |
8d2733ca MS |
1387 | /* First, decay it. */ |
1388 | exp = default_conversion (exp); | |
1389 | type = TREE_TYPE (exp); | |
a3b49ccd MS |
1390 | |
1391 | { | |
1392 | char *typestring = build_overload_name (type, 1, 1); | |
1393 | tree throw_type = build1 (ADDR_EXPR, ptr_type_node, combine_strings (build_string (strlen (typestring)+1, typestring))); | |
1394 | rtx throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0); | |
1395 | rtx throw_value_rtx; | |
1396 | ||
1397 | emit_move_insn (saved_throw_type, throw_type_rtx); | |
1398 | exp = convert_to_reference (build_reference_type (build_type_variant (TREE_TYPE (exp), 1, 0)), exp, CONV_STATIC, LOOKUP_COMPLAIN, NULL_TREE); | |
1399 | if (exp == error_mark_node) | |
1400 | error (" in thrown expression"); | |
1401 | throw_value_rtx = expand_expr (build_unary_op (ADDR_EXPR, exp, 0), NULL_RTX, VOIDmode, 0); | |
1402 | emit_move_insn (saved_throw_value, throw_value_rtx); | |
1403 | } | |
8d2733ca MS |
1404 | } |
1405 | else | |
a3b49ccd MS |
1406 | { |
1407 | /* rethrow current exception */ | |
1408 | /* This part is easy, as we dont' have to do anything else. */ | |
1409 | } | |
8d2733ca MS |
1410 | |
1411 | emit_jump (throw_label); | |
8d08fdba MS |
1412 | } |
1413 | ||
f376e137 MS |
1414 | /* end of: my-cp-except.c */ |
1415 | #endif | |
8d2733ca | 1416 | |
f376e137 MS |
1417 | |
1418 | /* Output the exception table. | |
1419 | Return the number of handlers. */ | |
1420 | int | |
8d2733ca | 1421 | build_exception_table () |
8d08fdba | 1422 | { |
f376e137 MS |
1423 | int count = 0; |
1424 | #ifdef TRY_NEW_EH | |
8d2733ca MS |
1425 | extern FILE *asm_out_file; |
1426 | struct ehEntry *entry; | |
f376e137 | 1427 | tree eh_node_decl; |
8d08fdba | 1428 | |
8d2733ca | 1429 | if (! doing_eh (0)) |
f376e137 | 1430 | return 0; |
8d2733ca | 1431 | |
f376e137 MS |
1432 | while (entry = dequeue_eh_entry (&eh_table_output_queue)) |
1433 | { | |
1434 | if (count == 0) | |
1435 | { | |
1436 | exception_section (); | |
1437 | ||
1438 | /* Beginning marker for table. */ | |
1439 | ASM_OUTPUT_ALIGN (asm_out_file, 2); | |
1440 | ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_TABLE__"); | |
1441 | fprintf (asm_out_file, " .word 0, 0, 0\n"); | |
1442 | } | |
1443 | count++; | |
8d2733ca | 1444 | output_exception_table_entry (asm_out_file, |
f376e137 MS |
1445 | entry->start_label, entry->end_label, |
1446 | entry->exception_handler_label); | |
8d2733ca MS |
1447 | } |
1448 | ||
f376e137 MS |
1449 | if (count) |
1450 | { | |
1451 | /* Ending marker for table. */ | |
1452 | ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_END__"); | |
1453 | fprintf (asm_out_file, " .word -1, -1, -1\n"); | |
1454 | } | |
8d2733ca | 1455 | |
f376e137 MS |
1456 | #endif /* TRY_NEW_EH */ |
1457 | return count; | |
1458 | } | |
8d2733ca | 1459 | |
f376e137 MS |
1460 | void |
1461 | register_exception_table () | |
1462 | { | |
1463 | #ifdef TRY_NEW_EH | |
1464 | emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0, | |
1465 | VOIDmode, 1, | |
81613e43 | 1466 | gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"), |
f376e137 MS |
1467 | Pmode); |
1468 | #endif /* TRY_NEW_EH */ | |
1469 | } | |
8d2733ca MS |
1470 | |
1471 | /* Build a throw expression. */ | |
1472 | tree | |
1473 | build_throw (e) | |
1474 | tree e; | |
1475 | { | |
1476 | e = build1 (THROW_EXPR, void_type_node, e); | |
1477 | TREE_SIDE_EFFECTS (e) = 1; | |
1478 | return e; | |
8d08fdba | 1479 | } |