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