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