(distribute_notes, case REG_DEAD): If a call uses a
[official-gcc.git] / gcc / cp / except.c
blob160a10b19b344d2d0637828d8c1273c8d84747d9
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.
7 This file is part of GNU CC.
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.
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.
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. */
24 /* High-level class interface. */
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"
34 /* holds the fndecl for __builtin_return_address () */
35 tree builtin_return_address_fndecl;
37 /* Define at your own risk! */
38 #ifndef CROSS_COMPILE
39 #ifdef sun
40 #ifdef sparc
41 #define TRY_NEW_EH
42 #endif
43 #endif
44 #endif
46 #ifndef TRY_NEW_EH
48 static void
49 sorry_no_eh ()
51 static int warned = 0;
52 if (! warned)
54 sorry ("exception handling not supported");
55 warned = 1;
59 void
60 build_exception_table ()
64 void
65 expand_exception_blocks ()
69 void
70 start_protect ()
74 void
75 end_protect (finalization)
76 tree finalization;
80 void
81 expand_start_try_stmts ()
83 sorry_no_eh ();
86 void
87 expand_end_try_stmts ()
91 void
92 expand_start_all_catch ()
96 void
97 expand_end_all_catch ()
101 void
102 expand_start_catch_block (declspecs, declarator)
103 tree declspecs, declarator;
107 void
108 expand_end_catch_block ()
112 void
113 init_exception_processing ()
117 void
118 expand_throw (exp)
119 tree exp;
121 sorry_no_eh ();
124 #else
126 static int
127 doing_eh (do_warn)
128 int do_warn;
130 if (! flag_handle_exceptions)
132 static int warned = 0;
133 if (! warned && do_warn)
135 error ("exception handling disabled, use -fhandle-exceptions to enable.");
136 warned = 1;
138 return 0;
140 return 1;
145 NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
146 to supporting exception handling as per Stroustrup's 2nd edition.
147 It is a complete rewrite of all the EH stuff that was here before
148 Shortcomings:
149 1. The type of the throw and catch must still match
150 exactly (no support yet for matching base classes)
151 2. Throw specifications of functions still doesnt't work.
152 Cool Things:
153 1. Destructors are called properly :-)
154 2. No overhead for the non-exception thrown case.
155 3. Fixing shortcomings 1 and 2 is simple.
156 -Tad Hunt (tad@mail.csh.rit.edu)
160 /* A couple of backend routines from m88k.c */
162 /* used to cache a call to __builtin_return_address () */
163 static tree BuiltinReturnAddress;
169 #include <stdio.h>
171 /* XXX - Tad: for EH */
172 /* output an exception table entry */
174 static void
175 output_exception_table_entry (file, start_label, end_label, eh_label)
176 FILE *file;
177 rtx start_label, end_label, eh_label;
179 char label[100];
181 fprintf (file, "\t%s\t ", ASM_LONG);
182 if (GET_CODE (start_label) == CODE_LABEL)
184 ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (start_label));
185 assemble_name (file, label);
187 else if (GET_CODE (start_label) == SYMBOL_REF)
189 fprintf (stderr, "YYYYYYYYYEEEEEEEESSSSSSSSSSSS!!!!!!!!!!\n");
190 assemble_name (file, XSTR (start_label, 0));
192 putc ('\n', file);
194 fprintf (file, "\t%s\t ", ASM_LONG);
195 ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (end_label));
196 assemble_name (file, label);
197 putc ('\n', file);
199 fprintf (file, "\t%s\t ", ASM_LONG);
200 ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (eh_label));
201 assemble_name (file, label);
202 putc ('\n', file);
204 putc ('\n', file); /* blank line */
207 static void
208 easy_expand_asm (str)
209 char *str;
211 expand_asm (build_string (strlen (str)+1, str));
214 /* unwind the stack. */
215 static void
216 do_unwind (throw_label)
217 rtx throw_label;
219 #ifdef sparc
220 extern FILE *asm_out_file;
221 tree fcall;
222 tree params;
223 rtx return_val_rtx;
225 /* call to __builtin_return_address () */
226 params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
227 fcall = build_function_call (BuiltinReturnAddress, params);
228 return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
229 /* In the return, the new pc is pc+8, as the value comming in is
230 really the address of the call insn, not the next insn. */
231 emit_move_insn (return_val_rtx, plus_constant(gen_rtx (LABEL_REF,
232 Pmode,
233 throw_label), -8));
234 easy_expand_asm ("st %l0,[%fp]");
235 easy_expand_asm ("st %l1,[%fp+4]");
236 easy_expand_asm ("ret");
237 easy_expand_asm ("restore");
238 emit_barrier ();
239 #endif
240 #if m88k
241 rtx temp_frame = frame_pointer_rtx;
243 temp_frame = memory_address (Pmode, temp_frame);
244 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
246 /* hopefully this will successfully pop the frame! */
247 emit_move_insn (frame_pointer_rtx, temp_frame);
248 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
249 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
250 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
251 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
253 #if 0
254 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
255 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
257 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
259 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
260 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
261 #endif
262 #endif
267 #if 0
268 /* This is the startup, and finish stuff per exception table. */
270 /* XXX - Tad: exception handling section */
271 #ifndef EXCEPT_SECTION_ASM_OP
272 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
273 #endif
275 #ifdef EXCEPT_SECTION_ASM_OP
276 typedef struct {
277 void *start_protect;
278 void *end_protect;
279 void *exception_handler;
280 } exception_table;
281 #endif /* EXCEPT_SECTION_ASM_OP */
283 #ifdef EXCEPT_SECTION_ASM_OP
285 /* on machines which support it, the exception table lives in another section,
286 but it needs a label so we can reference it... This sets up that
287 label! */
288 asm (EXCEPT_SECTION_ASM_OP);
289 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
290 asm (TEXT_SECTION_ASM_OP);
292 #endif /* EXCEPT_SECTION_ASM_OP */
294 #ifdef EXCEPT_SECTION_ASM_OP
296 /* we need to know where the end of the exception table is... so this
297 is how we do it! */
299 asm (EXCEPT_SECTION_ASM_OP);
300 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
301 asm (TEXT_SECTION_ASM_OP);
303 #endif /* EXCEPT_SECTION_ASM_OP */
305 #endif
307 void
308 exception_section ()
310 #ifdef ASM_OUTPUT_SECTION_NAME
311 named_section (".gcc_except_table");
312 #else
313 text_section ();
314 #endif
320 /* from: my-cp-except.c */
322 /* VI: ":set ts=4" */
323 #if 0
324 #include <stdio.h> */
325 #include "config.h"
326 #include "tree.h"
327 #include "rtl.h"
328 #include "cp-tree.h"
329 #endif
330 #include "decl.h"
331 #if 0
332 #include "flags.h"
333 #endif
334 #include "insn-flags.h"
335 #include "obstack.h"
336 #if 0
337 #include "expr.h"
338 #endif
340 /* ======================================================================
341 Briefly the algorithm works like this:
343 When a constructor or start of a try block is encountered,
344 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
345 new entry in the unwind protection stack and returns a label to
346 output to start the protection for that block.
348 When a destructor or end try block is encountered, pop_eh_entry
349 (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
350 created when push_eh_entry () was called. The ehEntry structure
351 contains three things at this point. The start protect label,
352 the end protect label, and the exception handler label. The end
353 protect label should be output before the call to the destructor
354 (if any). If it was a destructor, then its parse tree is stored
355 in the finalization variable in the ehEntry structure. Otherwise
356 the finalization variable is set to NULL to reflect the fact that
357 is the the end of a try block. Next, this modified ehEntry node
358 is enqueued in the finalizations queue by calling
359 enqueue_eh_entry (&queue,entry).
361 +---------------------------------------------------------------+
362 |XXX: Will need modification to deal with partially |
363 | constructed arrays of objects |
365 | Basically, this consists of keeping track of how many |
366 | of the objects have been constructed already (this |
367 | should be in a register though, so that shouldn't be a |
368 | problem. |
369 +---------------------------------------------------------------+
371 When a catch block is encountered, there is a lot of work to be
372 done.
374 Since we don't want to generate the catch block inline with the
375 regular flow of the function, we need to have some way of doing
376 so. Luckily, we have a couple of routines "get_last_insn ()" and
377 "set_last_insn ()" provided. When the start of a catch block is
378 encountered, we save a pointer to the last insn generated. After
379 the catch block is generated, we save a pointer to the first
380 catch block insn and the last catch block insn with the routines
381 "NEXT_INSN ()" and "get_last_insn ()". We then set the last insn
382 to be the last insn generated before the catch block, and set the
383 NEXT_INSN (last_insn) to zero.
385 Since catch blocks might be nested inside other catch blocks, and
386 we munge the chain of generated insns after the catch block is
387 generated, we need to store the pointers to the last insn
388 generated in a stack, so that when the end of a catch block is
389 encountered, the last insn before the current catch block can be
390 popped and set to be the last insn, and the first and last insns
391 of the catch block just generated can be enqueue'd for output at
392 a later time.
394 Next we must insure that when the catch block is executed, all
395 finalizations for the matching try block have been completed. If
396 any of those finalizations throw an exception, we must call
397 terminate according to the ARM (section r.15.6.1). What this
398 means is that we need to dequeue and emit finalizations for each
399 entry in the ehQueue until we get to an entry with a NULL
400 finalization field. For any of the finalization entries, if it
401 is not a call to terminate (), we must protect it by giving it
402 another start label, end label, and exception handler label,
403 setting its finalization tree to be a call to terminate (), and
404 enqueue'ing this new ehEntry to be output at an outer level.
405 Finally, after all that is done, we can get around to outputting
406 the catch block which basically wraps all the "catch (...) {...}"
407 statements in a big if/then/else construct that matches the
408 correct block to call.
410 ===================================================================== */
412 extern rtx emit_insn PROTO((rtx));
413 extern rtx gen_nop PROTO(());
415 /* local globals for function calls
416 ====================================================================== */
418 /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
419 "set_unexpected ()" after default_conversion. (lib-except.c) */
420 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
422 /* used to cache __find_first_exception_table_match ()
423 for throw (lib-except.c) */
424 static tree FirstExceptionMatch;
426 /* used to cache a call to __unwind_function () (lib-except.c) */
427 static tree Unwind;
429 /* holds a ready to emit call to "terminate ()". */
430 static tree TerminateFunctionCall;
432 /* ====================================================================== */
436 /* data structures for my various quick and dirty stacks and queues
437 Eventually, most of this should go away, because I think it can be
438 integrated with stuff already built into the compiler. */
440 /* =================================================================== */
442 struct labelNode {
443 rtx label;
444 struct labelNode *chain;
448 /* this is the most important structure here. Basically this is how I store
449 an exception table entry internally. */
450 struct ehEntry {
451 rtx start_label;
452 rtx end_label;
453 rtx exception_handler_label;
455 tree finalization;
458 struct ehNode {
459 struct ehEntry *entry;
460 struct ehNode *chain;
463 struct ehStack {
464 struct ehNode *top;
467 struct ehQueue {
468 struct ehNode *head;
469 struct ehNode *tail;
472 struct exceptNode {
473 rtx catchstart;
474 rtx catchend;
476 struct exceptNode *chain;
479 struct exceptStack {
480 struct exceptNode *top;
482 /* ========================================================================= */
486 /* local globals - these local globals are for storing data necessary for
487 generating the exception table and code in the correct order.
489 ========================================================================= */
491 /* holds the pc for doing "throw" */
492 rtx saved_pc;
493 /* holds the type of the thing being thrown. */
494 rtx saved_throw_type;
496 rtx throw_label;
498 static struct ehStack ehstack;
499 static struct ehQueue ehqueue;
500 static struct ehQueue eh_table_output_queue;
501 static struct exceptStack exceptstack;
502 static struct labelNode *false_label_stack = NULL;
503 static struct labelNode *caught_return_label_stack = NULL;
504 /* ========================================================================= */
506 /* function prototypes */
507 static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
508 static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
509 static void push_except_stmts PROTO((struct exceptStack *exceptstack,
510 rtx catchstart, rtx catchend));
511 static int pop_except_stmts PROTO((struct exceptStack *exceptstack,
512 rtx *catchstart, rtx *catchend));
513 static rtx push_eh_entry PROTO((struct ehStack *stack));
514 static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
515 static void new_eh_queue PROTO((struct ehQueue *queue));
516 static void new_eh_stack PROTO((struct ehStack *stack));
517 static void new_except_stack PROTO((struct exceptStack *queue));
518 static void push_last_insn PROTO(());
519 static rtx pop_last_insn PROTO(());
520 static void push_label_entry PROTO((struct labelNode **labelstack, rtx label));
521 static rtx pop_label_entry PROTO((struct labelNode **labelstack));
522 static rtx top_label_entry PROTO((struct labelNode **labelstack));
523 static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
527 /* All my cheesy stack/queue/misc data structure handling routines
529 ========================================================================= */
531 static void
532 push_label_entry (labelstack, label)
533 struct labelNode **labelstack;
534 rtx label;
536 struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
538 newnode->label = label;
539 newnode->chain = *labelstack;
540 *labelstack = newnode;
543 static rtx
544 pop_label_entry (labelstack)
545 struct labelNode **labelstack;
547 rtx label;
548 struct labelNode *tempnode;
550 if (! *labelstack) return NULL_RTX;
552 tempnode = *labelstack;
553 label = tempnode->label;
554 *labelstack = (*labelstack)->chain;
555 free (tempnode);
557 return label;
560 static rtx
561 top_label_entry (labelstack)
562 struct labelNode **labelstack;
564 if (! *labelstack) return NULL_RTX;
566 return (*labelstack)->label;
569 static void
570 push_except_stmts (exceptstack, catchstart, catchend)
571 struct exceptStack *exceptstack;
572 rtx catchstart, catchend;
574 struct exceptNode *newnode = (struct exceptNode*)
575 xmalloc (sizeof (struct exceptNode));
577 newnode->catchstart = catchstart;
578 newnode->catchend = catchend;
579 newnode->chain = exceptstack->top;
581 exceptstack->top = newnode;
584 static int
585 pop_except_stmts (exceptstack, catchstart, catchend)
586 struct exceptStack *exceptstack;
587 rtx *catchstart, *catchend;
589 struct exceptNode *tempnode;
591 if (!exceptstack->top) {
592 *catchstart = *catchend = NULL_RTX;
593 return 0;
596 tempnode = exceptstack->top;
597 exceptstack->top = exceptstack->top->chain;
599 *catchstart = tempnode->catchstart;
600 *catchend = tempnode->catchend;
601 free (tempnode);
603 return 1;
606 /* Push to permanent obstack for rtl generation.
607 One level only! */
608 static struct obstack *saved_rtl_obstack;
609 void
610 push_rtl_perm ()
612 extern struct obstack permanent_obstack;
613 extern struct obstack *rtl_obstack;
615 saved_rtl_obstack = rtl_obstack;
616 rtl_obstack = &permanent_obstack;
619 /* Pop back to normal rtl handling. */
620 static void
621 pop_rtl_from_perm ()
623 extern struct obstack permanent_obstack;
624 extern struct obstack *rtl_obstack;
626 rtl_obstack = saved_rtl_obstack;
629 static rtx
630 push_eh_entry (stack)
631 struct ehStack *stack;
633 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
634 struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
636 if (stack == NULL) {
637 free (node);
638 free (entry);
639 return NULL_RTX;
642 /* These are saved for the exception table. */
643 push_rtl_perm ();
644 entry->start_label = gen_label_rtx ();
645 entry->end_label = gen_label_rtx ();
646 entry->exception_handler_label = gen_label_rtx ();
647 pop_rtl_from_perm ();
649 entry->finalization = NULL_TREE;
651 node->entry = entry;
652 node->chain = stack->top;
653 stack->top = node;
655 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
657 return entry->start_label;
660 static struct ehEntry *
661 pop_eh_entry (stack)
662 struct ehStack *stack;
664 struct ehNode *tempnode;
665 struct ehEntry *tempentry;
667 if (stack && (tempnode = stack->top)) {
668 tempentry = tempnode->entry;
669 stack->top = stack->top->chain;
670 free (tempnode);
672 return tempentry;
675 return NULL;
678 static struct ehEntry *
679 copy_eh_entry (entry)
680 struct ehEntry *entry;
682 struct ehEntry *newentry;
684 newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
685 memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
687 return newentry;
690 static void
691 enqueue_eh_entry (queue, entry)
692 struct ehQueue *queue;
693 struct ehEntry *entry;
695 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
697 node->entry = entry;
698 node->chain = NULL;
700 if (queue->head == NULL)
702 queue->head = node;
704 else
706 queue->tail->chain = node;
708 queue->tail = node;
711 static struct ehEntry *
712 dequeue_eh_entry (queue)
713 struct ehQueue *queue;
715 struct ehNode *tempnode;
716 struct ehEntry *tempentry;
718 if (queue->head == NULL)
719 return NULL;
721 tempnode = queue->head;
722 queue->head = queue->head->chain;
724 tempentry = tempnode->entry;
725 free (tempnode);
727 return tempentry;
730 static void
731 new_eh_queue (queue)
732 struct ehQueue *queue;
734 queue->head = queue->tail = NULL;
737 static void
738 new_eh_stack (stack)
739 struct ehStack *stack;
741 stack->top = NULL;
744 static void
745 new_except_stack (stack)
746 struct exceptStack *stack;
748 stack->top = NULL;
750 /* ========================================================================= */
753 /* sets up all the global eh stuff that needs to be initialized at the
754 start of compilation.
756 This includes:
757 - Setting up all the function call trees
758 - Initializing the ehqueue
759 - Initializing the eh_table_output_queue
760 - Initializing the ehstack
761 - Initializing the exceptstack
764 void
765 init_exception_processing ()
767 extern tree define_function ();
768 tree unexpected_fndecl, terminate_fndecl;
769 tree set_unexpected_fndecl, set_terminate_fndecl;
770 tree catch_match_fndecl;
771 tree find_first_exception_match_fndecl;
772 tree unwind_fndecl;
773 tree temp, PFV;
775 /* void (*)() */
776 PFV = build_pointer_type (build_function_type (void_type_node, void_list_node));
778 /* arg list for the build_function_type call for set_terminate () and
779 set_unexpected () */
780 temp = tree_cons (NULL_TREE, PFV, void_list_node);
782 push_lang_context (lang_name_c);
784 set_terminate_fndecl =
785 define_function ("set_terminate",
786 build_function_type (PFV, temp),
787 NOT_BUILT_IN,
788 pushdecl,
790 set_unexpected_fndecl =
791 define_function ("set_unexpected",
792 build_function_type (PFV, temp),
793 NOT_BUILT_IN,
794 pushdecl,
797 unexpected_fndecl =
798 define_function ("unexpected",
799 build_function_type (void_type_node, void_list_node),
800 NOT_BUILT_IN,
801 pushdecl,
803 terminate_fndecl =
804 define_function ("terminate",
805 build_function_type (void_type_node, void_list_node),
806 NOT_BUILT_IN,
807 pushdecl,
809 catch_match_fndecl =
810 define_function ("__throw_type_match",
811 build_function_type (integer_type_node,
812 tree_cons (NULL_TREE, string_type_node, tree_cons (NULL_TREE, ptr_type_node, void_list_node))),
813 NOT_BUILT_IN,
814 pushdecl,
816 find_first_exception_match_fndecl =
817 define_function ("__find_first_exception_table_match",
818 build_function_type (ptr_type_node,
819 tree_cons (NULL_TREE, ptr_type_node,
820 void_list_node)),
821 NOT_BUILT_IN,
822 pushdecl,
824 unwind_fndecl =
825 define_function ("__unwind_function",
826 build_function_type (void_type_node,
827 tree_cons (NULL_TREE, ptr_type_node, void_list_node)),
828 NOT_BUILT_IN,
829 pushdecl,
832 Unexpected = default_conversion (unexpected_fndecl);
833 Terminate = default_conversion (terminate_fndecl);
834 SetTerminate = default_conversion (set_terminate_fndecl);
835 SetUnexpected = default_conversion (set_unexpected_fndecl);
836 CatchMatch = default_conversion (catch_match_fndecl);
837 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
838 Unwind = default_conversion (unwind_fndecl);
839 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
841 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
843 pop_lang_context ();
844 throw_label = gen_label_rtx ();
845 saved_pc = gen_rtx (REG, Pmode, 16);
846 saved_throw_type = gen_rtx (REG, Pmode, 17);
848 new_eh_queue (&ehqueue);
849 new_eh_queue (&eh_table_output_queue);
850 new_eh_stack (&ehstack);
851 new_except_stack (&exceptstack);
854 /* call this to begin a block of unwind protection (ie: when an object is
855 constructed) */
856 void
857 start_protect ()
859 if (doing_eh (0))
861 emit_label (push_eh_entry (&ehstack));
865 /* call this to end a block of unwind protection. the finalization tree is
866 the finalization which needs to be run in order to cleanly unwind through
867 this level of protection. (ie: call this when a scope is exited)*/
868 void
869 end_protect (finalization)
870 tree finalization;
872 struct ehEntry *entry = pop_eh_entry (&ehstack);
874 if (! doing_eh (0))
875 return;
877 emit_label (entry->end_label);
879 entry->finalization = finalization;
881 enqueue_eh_entry (&ehqueue, entry);
884 /* call this on start of a try block. */
885 void
886 expand_start_try_stmts ()
888 if (doing_eh (1))
890 start_protect ();
894 void
895 expand_end_try_stmts ()
897 end_protect (integer_zero_node);
900 struct insn_save_node {
901 rtx last;
902 struct insn_save_node *chain;
905 static struct insn_save_node *InsnSave = NULL;
908 /* Used to keep track of where the catch blocks start. */
909 static void
910 push_last_insn ()
912 struct insn_save_node *newnode = (struct insn_save_node*)
913 xmalloc (sizeof (struct insn_save_node));
915 newnode->last = get_last_insn ();
916 newnode->chain = InsnSave;
917 InsnSave = newnode;
920 /* Use to keep track of where the catch blocks start. */
921 static rtx
922 pop_last_insn ()
924 struct insn_save_node *tempnode;
925 rtx temprtx;
927 if (!InsnSave) return NULL_RTX;
929 tempnode = InsnSave;
930 temprtx = tempnode->last;
931 InsnSave = InsnSave->chain;
933 free (tempnode);
935 return temprtx;
938 /* call this to start processing of all the catch blocks. */
939 void
940 expand_start_all_catch ()
942 struct ehEntry *entry;
943 rtx label;
945 if (! doing_eh (1))
946 return;
948 emit_line_note (input_filename, lineno);
949 label = gen_label_rtx ();
950 /* The label for the exception handling block we will save. */
951 emit_label (label);
952 push_label_entry (&caught_return_label_stack, label);
954 /* Remember where we started. */
955 push_last_insn ();
957 /* Will this help us not stomp on it? */
958 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
960 while (1)
962 entry = dequeue_eh_entry (&ehqueue);
963 emit_label (entry->exception_handler_label);
965 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
967 /* When we get down to the matching entry, stop. */
968 if (entry->finalization == integer_zero_node)
969 break;
971 free (entry);
974 /* This goes when the below moves out of our way. */
975 #if 1
976 label = gen_label_rtx ();
977 emit_jump (label);
978 #endif
980 /* All this should be out of line, and saved back in the exception handler
981 block area. */
982 #if 1
983 entry->start_label = entry->exception_handler_label;
984 /* These are saved for the exception table. */
985 push_rtl_perm ();
986 entry->end_label = gen_label_rtx ();
987 entry->exception_handler_label = gen_label_rtx ();
988 entry->finalization = TerminateFunctionCall;
989 pop_rtl_from_perm ();
990 emit_label (entry->end_label);
993 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
995 /* After running the finalization, continue on out to the next
996 cleanup, if we have nothing better to do. */
997 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry->end_label));
998 /* Will this help us not stomp on it? */
999 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
1000 emit_jump (throw_label);
1001 emit_label (entry->exception_handler_label);
1002 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1003 emit_barrier ();
1004 #endif
1005 emit_label (label);
1008 /* call this to end processing of all the catch blocks. */
1009 void
1010 expand_end_all_catch ()
1012 rtx catchstart, catchend, last;
1013 rtx label;
1015 if (! doing_eh (1))
1016 return;
1018 /* Find the start of the catch block. */
1019 last = pop_last_insn ();
1020 catchstart = NEXT_INSN (last);
1021 catchend = get_last_insn ();
1023 NEXT_INSN (last) = 0;
1024 set_last_insn (last);
1026 /* this level of catch blocks is done, so set up the successful catch jump
1027 label for the next layer of catch blocks. */
1028 pop_label_entry (&caught_return_label_stack);
1030 push_except_stmts (&exceptstack, catchstart, catchend);
1032 /* Here was fall through into the continuation code. */
1036 /* this is called from expand_exception_blocks () to expand the toplevel
1037 finalizations for a function. */
1038 void
1039 expand_leftover_cleanups ()
1041 struct ehEntry *entry;
1042 rtx first_label = NULL_RTX;
1044 if (! doing_eh (0))
1045 return;
1047 /* Will this help us not stomp on it? */
1048 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
1050 while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
1052 if (! first_label)
1053 first_label = entry->exception_handler_label;
1054 emit_label (entry->exception_handler_label);
1056 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1058 /* leftover try block, opps. */
1059 if (entry->finalization == integer_zero_node)
1060 abort ();
1062 free (entry);
1064 if (first_label)
1066 rtx label;
1067 struct ehEntry entry;
1068 /* These are saved for the exception table. */
1069 push_rtl_perm ();
1070 label = gen_label_rtx ();
1071 entry.start_label = first_label;
1072 entry.end_label = label;
1073 entry.exception_handler_label = gen_label_rtx ();
1074 entry.finalization = TerminateFunctionCall;
1075 pop_rtl_from_perm ();
1076 emit_label (label);
1078 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1080 /* After running the finalization, continue on out to the next
1081 cleanup, if we have nothing better to do. */
1082 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry.end_label));
1083 /* Will this help us not stomp on it? */
1084 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
1085 emit_jump (throw_label);
1086 emit_label (entry.exception_handler_label);
1087 expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
1088 emit_barrier ();
1092 /* call this to start a catch block. Typename is the typename, and identifier
1093 is the variable to place the object in or NULL if the variable doesn't
1094 matter. If typename is NULL, that means its a "catch (...)" or catch
1095 everything. In that case we don't need to do any type checking.
1096 (ie: it ends up as the "else" clause rather than an "else if" clause) */
1097 void
1098 expand_start_catch_block (declspecs, declarator)
1099 tree declspecs, declarator;
1101 rtx false_label_rtx;
1102 tree type;
1103 tree decl;
1105 if (! doing_eh (1))
1106 return;
1108 if (declspecs)
1110 decl = grokdeclarator (declarator, declspecs, PARM, 0, NULL_TREE);
1111 type = TREE_TYPE (decl);
1113 else
1114 type = NULL_TREE;
1116 false_label_rtx = gen_label_rtx ();
1117 push_label_entry (&false_label_stack, false_label_rtx);
1119 if (type)
1121 tree params;
1122 char *typestring;
1123 rtx call_rtx, return_value_rtx;
1124 tree catch_match_fcall;
1125 tree catchmatch_arg, argval;
1127 typestring = build_overload_name (type, 1, 1);
1129 params = tree_cons (NULL_TREE,
1130 combine_strings (build_string (strlen (typestring)+1, typestring)),
1131 tree_cons (NULL_TREE,
1132 make_tree (ptr_type_node, saved_throw_type),
1133 NULL_TREE));
1134 catch_match_fcall = build_function_call (CatchMatch, params);
1135 call_rtx = expand_call (catch_match_fcall, NULL_RTX, 0);
1137 return_value_rtx =
1138 hard_function_value (integer_type_node, catch_match_fcall);
1140 /* did the throw type match function return TRUE? */
1141 emit_cmp_insn (return_value_rtx, const0_rtx, NE, NULL_RTX,
1142 GET_MODE (return_value_rtx), 0, 0);
1144 /* if it returned FALSE, jump over the catch block, else fall into it */
1145 emit_jump_insn (gen_bne (false_label_rtx));
1147 else
1149 /* Fall into the catch all section. */
1151 emit_line_note (input_filename, lineno);
1155 /* Call this to end a catch block. Its responsible for emitting the
1156 code to handle jumping back to the correct place, and for emitting
1157 the label to jump to if this catch block didn't match. */
1158 void expand_end_catch_block ()
1160 if (doing_eh (1))
1162 /* label we jump to if we caught the exception */
1163 emit_jump (top_label_entry (&caught_return_label_stack));
1165 /* label we emit to jump to if this catch block didn't match. */
1166 emit_label (pop_label_entry (&false_label_stack));
1170 /* cheesyness to save some typing. returns the return value rtx */
1172 do_function_call (func, params, return_type)
1173 tree func, params, return_type;
1175 tree func_call;
1176 func_call = build_function_call (func, params);
1177 expand_call (func_call, NULL_RTX, 0);
1178 if (return_type != NULL_TREE)
1179 return hard_function_value (return_type, func_call);
1180 return NULL_RTX;
1184 /* is called from expand_excpetion_blocks () to generate the code in a function
1185 to "throw" if anything in the function needs to preform a throw.
1187 expands "throw" as the following psuedo code:
1189 throw:
1190 eh = find_first_exception_match (saved_pc);
1191 if (!eh) goto gotta_rethrow_it;
1192 goto eh;
1194 gotta_rethrow_it:
1195 saved_pc = __builtin_return_address (0);
1196 pop_to_previous_level ();
1197 goto throw;
1200 static void
1201 expand_builtin_throw ()
1203 tree fcall;
1204 tree params;
1205 rtx return_val_rtx;
1206 rtx gotta_rethrow_it = gen_label_rtx ();
1207 rtx gotta_call_terminate = gen_label_rtx ();
1208 rtx unwind_and_throw = gen_label_rtx ();
1209 rtx goto_unwind_and_throw = gen_label_rtx ();
1211 emit_label (throw_label);
1213 /* search for an exception handler for the saved_pc */
1214 return_val_rtx = do_function_call (FirstExceptionMatch,
1215 tree_cons (NULL_TREE, make_tree (ptr_type_node, saved_pc), NULL_TREE),
1216 ptr_type_node);
1218 /* did we find one? */
1219 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1220 GET_MODE (return_val_rtx), 0, 0);
1222 /* if not, jump to gotta_rethrow_it */
1223 emit_jump_insn (gen_beq (gotta_rethrow_it));
1225 /* we found it, so jump to it */
1226 emit_indirect_jump (return_val_rtx);
1228 /* code to deal with unwinding and looking for it again */
1229 emit_label (gotta_rethrow_it);
1231 /* call to __builtin_return_address () */
1232 params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1233 fcall = build_function_call (BuiltinReturnAddress, params);
1234 return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
1236 /* did __builtin_return_address () return a valid address? */
1237 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1238 GET_MODE (return_val_rtx), 0, 0);
1240 emit_jump_insn (gen_beq (gotta_call_terminate));
1242 /* yes it did */
1243 emit_move_insn (saved_pc, return_val_rtx);
1244 do_unwind (throw_label);
1245 emit_jump (throw_label);
1247 /* no it didn't --> therefore we need to call terminate */
1248 emit_label (gotta_call_terminate);
1249 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1253 /* This is called to expand all the toplevel exception handling
1254 finalization for a function. It should only be called once per
1255 function. */
1256 void
1257 expand_exception_blocks ()
1259 rtx catchstart, catchend;
1260 rtx last;
1261 static rtx funcend;
1263 funcend = gen_label_rtx ();
1264 emit_jump (funcend);
1265 /* expand_null_return (); */
1267 while (pop_except_stmts (&exceptstack, &catchstart, &catchend)) {
1268 last = get_last_insn ();
1269 NEXT_INSN (last) = catchstart;
1270 PREV_INSN (catchstart) = last;
1271 NEXT_INSN (catchend) = 0;
1272 set_last_insn (catchend);
1275 expand_leftover_cleanups ();
1278 static int have_done = 0;
1279 if (! have_done && TREE_PUBLIC (current_function_decl)
1280 && ! DECL_INLINE (current_function_decl))
1282 have_done = 1;
1283 expand_builtin_throw ();
1286 emit_label (funcend);
1290 /* call this to expand a throw statement. This follows the following
1291 algorithm:
1293 1. Allocate space to save the current PC onto the stack.
1294 2. Generate and emit a label and save its address into the
1295 newly allocate stack space since we can't save the pc directly.
1296 3. If this is the first call to throw in this function:
1297 generate a label for the throw block
1298 4. jump to the throw block label. */
1299 void
1300 expand_throw (exp)
1301 tree exp;
1303 tree raiseid = NULL_TREE;
1304 rtx temp_size;
1305 rtx label;
1306 tree type;
1308 if (! doing_eh (1))
1309 return;
1311 label = gen_label_rtx ();
1312 emit_label (label);
1313 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, label));
1315 if (exp)
1317 /* throw variable */
1318 /* First, decay it. */
1319 exp = default_conversion (exp);
1320 type = TREE_TYPE (exp);
1322 else
1323 type = void_type_node;
1326 char *typestring = build_overload_name (type, 1, 1);
1327 tree throw_type = build1 (ADDR_EXPR, ptr_type_node, combine_strings (build_string (strlen (typestring)+1, typestring)));
1328 rtx throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0);
1329 emit_move_insn (saved_throw_type, throw_type_rtx);
1332 emit_jump (throw_label);
1336 /* output the exception table */
1337 void
1338 build_exception_table ()
1340 extern FILE *asm_out_file;
1341 struct ehEntry *entry;
1343 if (! doing_eh (0))
1344 return;
1346 exception_section ();
1348 /* Beginning marker for table. */
1349 fprintf (asm_out_file, " .global ___EXCEPTION_TABLE__\n");
1350 fprintf (asm_out_file, " .align 4\n");
1351 fprintf (asm_out_file, "___EXCEPTION_TABLE__:\n");
1352 fprintf (asm_out_file, " .word 0, 0, 0\n");
1354 while (entry = dequeue_eh_entry (&eh_table_output_queue)) {
1355 output_exception_table_entry (asm_out_file,
1356 entry->start_label, entry->end_label, entry->exception_handler_label);
1359 /* Ending marker for table. */
1360 fprintf (asm_out_file, " .global ___EXCEPTION_END__\n");
1361 fprintf (asm_out_file, "___EXCEPTION_END__:\n");
1362 fprintf (asm_out_file, " .word -1, -1, -1\n");
1365 /* end of: my-cp-except.c */
1366 #endif
1369 /* Build a throw expression. */
1370 tree
1371 build_throw (e)
1372 tree e;
1374 e = build1 (THROW_EXPR, void_type_node, e);
1375 TREE_SIDE_EFFECTS (e) = 1;
1376 return e;