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