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