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)
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. */
34 extern void (*interim_eh_hook) PROTO((tree));
36 /* holds the fndecl for __builtin_return_address () */
37 tree builtin_return_address_fndecl;
39 /* Define at your own risk! */
51 #if defined(__i386) || defined(__rs6000) || defined(__hppa) || defined(__mc68000) || defined (__mips) || defined (__arm)
61 static int warned = 0;
64 sorry ("exception handling not supported");
70 expand_exception_blocks ()
80 end_protect (finalization)
86 expand_start_try_stmts ()
92 expand_end_try_stmts ()
97 expand_start_all_catch ()
102 expand_end_all_catch ()
107 expand_start_catch_block (declspecs, declarator)
108 tree declspecs, declarator;
113 expand_end_catch_block ()
118 init_exception_processing ()
131 /* Make 'label' the first numbered label of the current function */
133 make_first_label(label)
136 if (CODE_LABEL_NUMBER(label) < get_first_label_num())
137 set_new_first_and_last_label_num (CODE_LABEL_NUMBER(label),
145 if (! flag_handle_exceptions)
147 static int warned = 0;
148 if (! warned && do_warn)
150 error ("exception handling disabled, use -fhandle-exceptions to enable.");
160 NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
161 to supporting exception handling as per Stroustrup's 2nd edition.
162 It is a complete rewrite of all the EH stuff that was here before
164 1. The type of the throw and catch must still match
165 exactly (no support yet for matching base classes)
166 2. Throw specifications of functions still doesnt't work.
168 1. Destructors are called properly :-)
169 2. No overhead for the non-exception thrown case.
170 3. Fixing shortcomings 1 and 2 is simple.
171 -Tad Hunt (tad@mail.csh.rit.edu)
175 /* A couple of backend routines from m88k.c */
177 /* used to cache a call to __builtin_return_address () */
178 static tree BuiltinReturnAddress;
186 /* XXX - Tad: for EH */
187 /* output an exception table entry */
190 output_exception_table_entry (file, start_label, end_label, eh_label)
192 rtx start_label, end_label, eh_label;
196 assemble_integer (start_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
197 assemble_integer (end_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
198 assemble_integer (eh_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
199 putc ('\n', file); /* blank line */
203 easy_expand_asm (str)
206 expand_asm (build_string (strlen (str)+1, str));
211 /* This is the startup, and finish stuff per exception table. */
213 /* XXX - Tad: exception handling section */
214 #ifndef EXCEPT_SECTION_ASM_OP
215 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
218 #ifdef EXCEPT_SECTION_ASM_OP
222 void *exception_handler;
224 #endif /* EXCEPT_SECTION_ASM_OP */
226 #ifdef EXCEPT_SECTION_ASM_OP
228 /* on machines which support it, the exception table lives in another section,
229 but it needs a label so we can reference it... This sets up that
231 asm (EXCEPT_SECTION_ASM_OP);
232 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
233 asm (TEXT_SECTION_ASM_OP);
235 #endif /* EXCEPT_SECTION_ASM_OP */
237 #ifdef EXCEPT_SECTION_ASM_OP
239 /* we need to know where the end of the exception table is... so this
242 asm (EXCEPT_SECTION_ASM_OP);
243 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
244 asm (TEXT_SECTION_ASM_OP);
246 #endif /* EXCEPT_SECTION_ASM_OP */
253 #ifdef ASM_OUTPUT_SECTION_NAME
254 named_section (NULL_TREE, ".gcc_except_table");
259 #if defined(__rs6000)
262 readonly_data_section ();
270 /* from: my-cp-except.c */
272 /* VI: ":set ts=4" */
274 #include <stdio.h> */
284 #include "insn-flags.h"
290 /* ======================================================================
291 Briefly the algorithm works like this:
293 When a constructor or start of a try block is encountered,
294 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
295 new entry in the unwind protection stack and returns a label to
296 output to start the protection for that block.
298 When a destructor or end try block is encountered, pop_eh_entry
299 (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
300 created when push_eh_entry () was called. The ehEntry structure
301 contains three things at this point. The start protect label,
302 the end protect label, and the exception handler label. The end
303 protect label should be output before the call to the destructor
304 (if any). If it was a destructor, then its parse tree is stored
305 in the finalization variable in the ehEntry structure. Otherwise
306 the finalization variable is set to NULL to reflect the fact that
307 is the the end of a try block. Next, this modified ehEntry node
308 is enqueued in the finalizations queue by calling
309 enqueue_eh_entry (&queue,entry).
311 +---------------------------------------------------------------+
312 |XXX: Will need modification to deal with partially |
313 | constructed arrays of objects |
315 | Basically, this consists of keeping track of how many |
316 | of the objects have been constructed already (this |
317 | should be in a register though, so that shouldn't be a |
319 +---------------------------------------------------------------+
321 When a catch block is encountered, there is a lot of work to be
324 Since we don't want to generate the catch block inline with the
325 regular flow of the function, we need to have some way of doing
326 so. Luckily, we have a couple of routines "get_last_insn ()" and
327 "set_last_insn ()" provided. When the start of a catch block is
328 encountered, we save a pointer to the last insn generated. After
329 the catch block is generated, we save a pointer to the first
330 catch block insn and the last catch block insn with the routines
331 "NEXT_INSN ()" and "get_last_insn ()". We then set the last insn
332 to be the last insn generated before the catch block, and set the
333 NEXT_INSN (last_insn) to zero.
335 Since catch blocks might be nested inside other catch blocks, and
336 we munge the chain of generated insns after the catch block is
337 generated, we need to store the pointers to the last insn
338 generated in a stack, so that when the end of a catch block is
339 encountered, the last insn before the current catch block can be
340 popped and set to be the last insn, and the first and last insns
341 of the catch block just generated can be enqueue'd for output at
344 Next we must insure that when the catch block is executed, all
345 finalizations for the matching try block have been completed. If
346 any of those finalizations throw an exception, we must call
347 terminate according to the ARM (section r.15.6.1). What this
348 means is that we need to dequeue and emit finalizations for each
349 entry in the ehQueue until we get to an entry with a NULL
350 finalization field. For any of the finalization entries, if it
351 is not a call to terminate (), we must protect it by giving it
352 another start label, end label, and exception handler label,
353 setting its finalization tree to be a call to terminate (), and
354 enqueue'ing this new ehEntry to be output at an outer level.
355 Finally, after all that is done, we can get around to outputting
356 the catch block which basically wraps all the "catch (...) {...}"
357 statements in a big if/then/else construct that matches the
358 correct block to call.
360 ===================================================================== */
362 extern rtx emit_insn PROTO((rtx));
363 extern rtx gen_nop PROTO(());
365 /* local globals for function calls
366 ====================================================================== */
368 /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
369 "set_unexpected ()" after default_conversion. (lib-except.c) */
370 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
372 /* used to cache __find_first_exception_table_match ()
373 for throw (lib-except.c) */
374 static tree FirstExceptionMatch;
376 /* used to cache a call to __unwind_function () (lib-except.c) */
379 /* holds a ready to emit call to "terminate ()". */
380 static tree TerminateFunctionCall;
382 /* ====================================================================== */
386 /* data structures for my various quick and dirty stacks and queues
387 Eventually, most of this should go away, because I think it can be
388 integrated with stuff already built into the compiler. */
390 /* =================================================================== */
394 struct labelNode *chain;
398 /* this is the most important structure here. Basically this is how I store
399 an exception table entry internally. */
403 rtx exception_handler_label;
409 struct ehEntry *entry;
410 struct ehNode *chain;
426 struct exceptNode *chain;
430 struct exceptNode *top;
432 /* ========================================================================= */
436 /* local globals - these local globals are for storing data necessary for
437 generating the exception table and code in the correct order.
439 ========================================================================= */
441 /* Holds the pc for doing "throw" */
443 /* Holds the type of the thing being thrown. */
444 rtx saved_throw_type;
445 /* Holds the value being thrown. */
446 rtx saved_throw_value;
450 static struct ehStack ehstack;
451 static struct ehQueue ehqueue;
452 static struct ehQueue eh_table_output_queue;
453 static struct exceptStack exceptstack;
454 static struct labelNode *false_label_stack = NULL;
455 static struct labelNode *caught_return_label_stack = NULL;
456 /* ========================================================================= */
458 /* function prototypes */
459 static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
460 static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
461 static void push_except_stmts PROTO((struct exceptStack *exceptstack,
462 rtx catchstart, rtx catchend));
463 static int pop_except_stmts PROTO((struct exceptStack *exceptstack,
464 rtx *catchstart, rtx *catchend));
465 static rtx push_eh_entry PROTO((struct ehStack *stack));
466 static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
467 static void new_eh_queue PROTO((struct ehQueue *queue));
468 static void new_eh_stack PROTO((struct ehStack *stack));
469 static void new_except_stack PROTO((struct exceptStack *queue));
470 static void push_last_insn PROTO(());
471 static rtx pop_last_insn PROTO(());
472 static void push_label_entry PROTO((struct labelNode **labelstack, rtx label));
473 static rtx pop_label_entry PROTO((struct labelNode **labelstack));
474 static rtx top_label_entry PROTO((struct labelNode **labelstack));
475 static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
479 /* All my cheesy stack/queue/misc data structure handling routines
481 ========================================================================= */
484 push_label_entry (labelstack, label)
485 struct labelNode **labelstack;
488 struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
490 newnode->label = label;
491 newnode->chain = *labelstack;
492 *labelstack = newnode;
496 pop_label_entry (labelstack)
497 struct labelNode **labelstack;
500 struct labelNode *tempnode;
502 if (! *labelstack) return NULL_RTX;
504 tempnode = *labelstack;
505 label = tempnode->label;
506 *labelstack = (*labelstack)->chain;
513 top_label_entry (labelstack)
514 struct labelNode **labelstack;
516 if (! *labelstack) return NULL_RTX;
518 return (*labelstack)->label;
522 push_except_stmts (exceptstack, catchstart, catchend)
523 struct exceptStack *exceptstack;
524 rtx catchstart, catchend;
526 struct exceptNode *newnode = (struct exceptNode*)
527 xmalloc (sizeof (struct exceptNode));
529 newnode->catchstart = catchstart;
530 newnode->catchend = catchend;
531 newnode->chain = exceptstack->top;
533 exceptstack->top = newnode;
537 pop_except_stmts (exceptstack, catchstart, catchend)
538 struct exceptStack *exceptstack;
539 rtx *catchstart, *catchend;
541 struct exceptNode *tempnode;
543 if (!exceptstack->top) {
544 *catchstart = *catchend = NULL_RTX;
548 tempnode = exceptstack->top;
549 exceptstack->top = exceptstack->top->chain;
551 *catchstart = tempnode->catchstart;
552 *catchend = tempnode->catchend;
558 /* Push to permanent obstack for rtl generation.
560 static struct obstack *saved_rtl_obstack;
564 extern struct obstack permanent_obstack;
565 extern struct obstack *rtl_obstack;
567 saved_rtl_obstack = rtl_obstack;
568 rtl_obstack = &permanent_obstack;
571 /* Pop back to normal rtl handling. */
575 extern struct obstack permanent_obstack;
576 extern struct obstack *rtl_obstack;
578 rtl_obstack = saved_rtl_obstack;
582 push_eh_entry (stack)
583 struct ehStack *stack;
585 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
586 struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
594 /* These are saved for the exception table. */
596 entry->start_label = gen_label_rtx ();
597 entry->end_label = gen_label_rtx ();
598 entry->exception_handler_label = gen_label_rtx ();
599 pop_rtl_from_perm ();
601 LABEL_PRESERVE_P (entry->start_label) = 1;
602 LABEL_PRESERVE_P (entry->end_label) = 1;
603 LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
605 entry->finalization = NULL_TREE;
608 node->chain = stack->top;
611 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
613 return entry->start_label;
616 static struct ehEntry *
618 struct ehStack *stack;
620 struct ehNode *tempnode;
621 struct ehEntry *tempentry;
623 if (stack && (tempnode = stack->top)) {
624 tempentry = tempnode->entry;
625 stack->top = stack->top->chain;
634 static struct ehEntry *
635 copy_eh_entry (entry)
636 struct ehEntry *entry;
638 struct ehEntry *newentry;
640 newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
641 memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
647 enqueue_eh_entry (queue, entry)
648 struct ehQueue *queue;
649 struct ehEntry *entry;
651 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
656 if (queue->head == NULL)
662 queue->tail->chain = node;
667 static struct ehEntry *
668 dequeue_eh_entry (queue)
669 struct ehQueue *queue;
671 struct ehNode *tempnode;
672 struct ehEntry *tempentry;
674 if (queue->head == NULL)
677 tempnode = queue->head;
678 queue->head = queue->head->chain;
680 tempentry = tempnode->entry;
688 struct ehQueue *queue;
690 queue->head = queue->tail = NULL;
695 struct ehStack *stack;
701 new_except_stack (stack)
702 struct exceptStack *stack;
706 /* ========================================================================= */
709 lang_interim_eh (finalization)
713 end_protect (finalization);
718 /* sets up all the global eh stuff that needs to be initialized at the
719 start of compilation.
722 - Setting up all the function call trees
723 - Initializing the ehqueue
724 - Initializing the eh_table_output_queue
725 - Initializing the ehstack
726 - Initializing the exceptstack
730 init_exception_processing ()
732 extern tree define_function ();
733 tree unexpected_fndecl, terminate_fndecl;
734 tree set_unexpected_fndecl, set_terminate_fndecl;
735 tree catch_match_fndecl;
736 tree find_first_exception_match_fndecl;
740 interim_eh_hook = lang_interim_eh;
743 PFV = build_pointer_type (build_function_type (void_type_node, void_list_node));
745 /* arg list for the build_function_type call for set_terminate () and
747 temp = tree_cons (NULL_TREE, PFV, void_list_node);
749 push_lang_context (lang_name_c);
751 set_terminate_fndecl =
752 define_function ("set_terminate",
753 build_function_type (PFV, temp),
757 set_unexpected_fndecl =
758 define_function ("set_unexpected",
759 build_function_type (PFV, temp),
765 define_function ("unexpected",
766 build_function_type (void_type_node, void_list_node),
771 define_function ("terminate",
772 build_function_type (void_type_node, void_list_node),
777 define_function ("__throw_type_match",
778 build_function_type (integer_type_node,
779 tree_cons (NULL_TREE, string_type_node, tree_cons (NULL_TREE, ptr_type_node, void_list_node))),
783 find_first_exception_match_fndecl =
784 define_function ("__find_first_exception_table_match",
785 build_function_type (ptr_type_node,
786 tree_cons (NULL_TREE, ptr_type_node,
792 define_function ("__unwind_function",
793 build_function_type (void_type_node,
794 tree_cons (NULL_TREE, ptr_type_node, void_list_node)),
799 Unexpected = default_conversion (unexpected_fndecl);
800 Terminate = default_conversion (terminate_fndecl);
801 SetTerminate = default_conversion (set_terminate_fndecl);
802 SetUnexpected = default_conversion (set_unexpected_fndecl);
803 CatchMatch = default_conversion (catch_match_fndecl);
804 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
805 Unwind = default_conversion (unwind_fndecl);
806 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
808 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
811 throw_label = gen_label_rtx ();
813 saved_pc = gen_rtx (REG, Pmode, 16);
814 saved_throw_type = gen_rtx (REG, Pmode, 17);
815 saved_throw_value = gen_rtx (REG, Pmode, 18);
818 saved_pc = gen_rtx (REG, Pmode, 3);
819 saved_throw_type = gen_rtx (REG, Pmode, 4);
820 saved_throw_value = gen_rtx (REG, Pmode, 5);
823 saved_pc = gen_rtx (REG, Pmode, 13);
824 saved_throw_type = gen_rtx (REG, Pmode, 14);
825 saved_throw_value = gen_rtx (REG, Pmode, 15);
828 saved_pc = gen_rtx (REG, Pmode, 5);
829 saved_throw_type = gen_rtx (REG, Pmode, 6);
830 saved_throw_value = gen_rtx (REG, Pmode, 7);
833 saved_pc = gen_rtx (REG, Pmode, 10);
834 saved_throw_type = gen_rtx (REG, Pmode, 11);
835 saved_throw_value = gen_rtx (REG, Pmode, 12);
838 saved_pc = gen_rtx (REG, Pmode, 16);
839 saved_throw_type = gen_rtx (REG, Pmode, 17);
840 saved_throw_value = gen_rtx (REG, Pmode, 18);
843 saved_pc = gen_rtx (REG, Pmode, 7);
844 saved_throw_type = gen_rtx (REG, Pmode, 8);
845 saved_throw_value = gen_rtx (REG, Pmode, 9);
847 new_eh_queue (&ehqueue);
848 new_eh_queue (&eh_table_output_queue);
849 new_eh_stack (&ehstack);
850 new_except_stack (&exceptstack);
853 /* call this to begin a block of unwind protection (ie: when an object is
860 emit_label (push_eh_entry (&ehstack));
864 /* call this to end a block of unwind protection. the finalization tree is
865 the finalization which needs to be run in order to cleanly unwind through
866 this level of protection. (ie: call this when a scope is exited)*/
868 end_protect (finalization)
871 struct ehEntry *entry = pop_eh_entry (&ehstack);
876 emit_label (entry->end_label);
878 entry->finalization = finalization;
880 enqueue_eh_entry (&ehqueue, entry);
883 /* call this on start of a try block. */
885 expand_start_try_stmts ()
894 expand_end_try_stmts ()
896 end_protect (integer_zero_node);
899 struct insn_save_node {
901 struct insn_save_node *chain;
904 static struct insn_save_node *InsnSave = NULL;
907 /* Used to keep track of where the catch blocks start. */
911 struct insn_save_node *newnode = (struct insn_save_node*)
912 xmalloc (sizeof (struct insn_save_node));
914 newnode->last = get_last_insn ();
915 newnode->chain = InsnSave;
919 /* Use to keep track of where the catch blocks start. */
923 struct insn_save_node *tempnode;
926 if (!InsnSave) return NULL_RTX;
929 temprtx = tempnode->last;
930 InsnSave = InsnSave->chain;
937 /* call this to start processing of all the catch blocks. */
939 expand_start_all_catch ()
941 struct ehEntry *entry;
947 emit_line_note (input_filename, lineno);
948 label = gen_label_rtx ();
949 /* The label for the exception handling block we will save. */
952 push_label_entry (&caught_return_label_stack, label);
954 /* Remember where we started. */
957 emit_insn (gen_nop ());
959 /* Will this help us not stomp on it? */
960 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
961 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
965 entry = dequeue_eh_entry (&ehqueue);
966 emit_label (entry->exception_handler_label);
968 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
970 /* When we get down to the matching entry, stop. */
971 if (entry->finalization == integer_zero_node)
977 /* This goes when the below moves out of our way. */
979 label = gen_label_rtx ();
983 /* All this should be out of line, and saved back in the exception handler
986 entry->start_label = entry->exception_handler_label;
987 /* These are saved for the exception table. */
989 entry->end_label = gen_label_rtx ();
990 entry->exception_handler_label = gen_label_rtx ();
991 entry->finalization = TerminateFunctionCall;
992 assemble_external (TREE_OPERAND (Terminate, 0));
993 pop_rtl_from_perm ();
995 LABEL_PRESERVE_P (entry->start_label) = 1;
996 LABEL_PRESERVE_P (entry->end_label) = 1;
997 LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
999 emit_label (entry->end_label);
1001 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
1003 /* After running the finalization, continue on out to the next
1004 cleanup, if we have nothing better to do. */
1005 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry->end_label));
1006 /* Will this help us not stomp on it? */
1007 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
1008 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
1009 make_first_label(throw_label);
1010 emit_jump (throw_label);
1011 emit_label (entry->exception_handler_label);
1012 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1018 /* call this to end processing of all the catch blocks. */
1020 expand_end_all_catch ()
1022 rtx catchstart, catchend, last;
1028 /* Code to throw out to outer context, if we fall off end of catch
1030 emit_move_insn (saved_pc, gen_rtx (LABEL_REF,
1032 top_label_entry (&caught_return_label_stack)));
1033 make_first_label(throw_label);
1034 emit_jump (throw_label);
1036 /* Find the start of the catch block. */
1037 last = pop_last_insn ();
1038 catchstart = NEXT_INSN (last);
1039 catchend = get_last_insn ();
1041 NEXT_INSN (last) = 0;
1042 set_last_insn (last);
1044 /* this level of catch blocks is done, so set up the successful catch jump
1045 label for the next layer of catch blocks. */
1046 pop_label_entry (&caught_return_label_stack);
1048 push_except_stmts (&exceptstack, catchstart, catchend);
1050 /* Here we fall through into the continuation code. */
1054 /* this is called from expand_exception_blocks () to expand the toplevel
1055 finalizations for a function. */
1057 expand_leftover_cleanups ()
1059 struct ehEntry *entry;
1060 rtx first_label = NULL_RTX;
1065 /* Will this help us not stomp on it? */
1066 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
1067 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
1069 while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
1072 first_label = entry->exception_handler_label;
1073 emit_label (entry->exception_handler_label);
1075 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1077 /* leftover try block, opps. */
1078 if (entry->finalization == integer_zero_node)
1086 struct ehEntry entry;
1087 /* These are saved for the exception table. */
1089 label = gen_label_rtx ();
1090 entry.start_label = first_label;
1091 entry.end_label = label;
1092 entry.exception_handler_label = gen_label_rtx ();
1093 entry.finalization = TerminateFunctionCall;
1094 assemble_external (TREE_OPERAND (Terminate, 0));
1095 pop_rtl_from_perm ();
1097 LABEL_PRESERVE_P (entry.start_label) = 1;
1098 LABEL_PRESERVE_P (entry.end_label) = 1;
1099 LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1103 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1105 /* After running the finalization, continue on out to the next
1106 cleanup, if we have nothing better to do. */
1107 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry.end_label));
1108 /* Will this help us not stomp on it? */
1109 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
1110 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
1111 make_first_label(throw_label);
1112 emit_jump (throw_label);
1113 emit_label (entry.exception_handler_label);
1114 expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
1119 /* call this to start a catch block. Typename is the typename, and identifier
1120 is the variable to place the object in or NULL if the variable doesn't
1121 matter. If typename is NULL, that means its a "catch (...)" or catch
1122 everything. In that case we don't need to do any type checking.
1123 (ie: it ends up as the "else" clause rather than an "else if" clause) */
1125 expand_start_catch_block (declspecs, declarator)
1126 tree declspecs, declarator;
1128 rtx false_label_rtx;
1129 rtx protect_label_rtx;
1137 /* Create a binding level for the parm. */
1138 expand_start_bindings (0);
1143 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
1145 /* Figure out the type that the initializer is. */
1146 init_type = TREE_TYPE (decl);
1147 if (TREE_CODE (init_type) != REFERENCE_TYPE)
1148 init_type = build_reference_type (init_type);
1150 init = convert_from_reference (save_expr (make_tree (init_type, saved_throw_value)));
1152 /* Do we need the below two lines? */
1153 /* Let `finish_decl' know that this initializer is ok. */
1154 DECL_INITIAL (decl) = init;
1155 /* This needs to be preallocated under the try block,
1156 in a union of all catch variables. */
1158 type = TREE_TYPE (decl);
1160 /* peel back references, so they match. */
1161 if (TREE_CODE (type) == REFERENCE_TYPE)
1162 type = TREE_TYPE (type);
1167 /* These are saved for the exception table. */
1169 false_label_rtx = gen_label_rtx ();
1170 protect_label_rtx = gen_label_rtx ();
1171 pop_rtl_from_perm ();
1172 push_label_entry (&false_label_stack, false_label_rtx);
1173 push_label_entry (&false_label_stack, protect_label_rtx);
1179 rtx call_rtx, return_value_rtx;
1180 tree catch_match_fcall;
1181 tree catchmatch_arg, argval;
1183 typestring = build_overload_name (type, 1, 1);
1185 params = tree_cons (NULL_TREE,
1186 combine_strings (build_string (strlen (typestring)+1, typestring)),
1187 tree_cons (NULL_TREE,
1188 make_tree (ptr_type_node, saved_throw_type),
1190 catch_match_fcall = build_function_call (CatchMatch, params);
1191 call_rtx = expand_call (catch_match_fcall, NULL_RTX, 0);
1192 assemble_external (TREE_OPERAND (CatchMatch, 0));
1195 hard_function_value (integer_type_node, catch_match_fcall);
1197 /* did the throw type match function return TRUE? */
1198 emit_cmp_insn (return_value_rtx, const0_rtx, NE, NULL_RTX,
1199 GET_MODE (return_value_rtx), 0, 0);
1201 /* if it returned FALSE, jump over the catch block, else fall into it */
1202 emit_jump_insn (gen_bne (false_label_rtx));
1203 finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1207 /* Fall into the catch all section. */
1210 /* This is the starting of something to protect. */
1211 emit_label (protect_label_rtx);
1213 emit_line_note (input_filename, lineno);
1217 /* Call this to end a catch block. Its responsible for emitting the
1218 code to handle jumping back to the correct place, and for emitting
1219 the label to jump to if this catch block didn't match. */
1220 void expand_end_catch_block ()
1224 rtx start_protect_label_rtx;
1225 rtx end_protect_label_rtx;
1227 struct ehEntry entry;
1229 /* label we jump to if we caught the exception */
1230 emit_jump (top_label_entry (&caught_return_label_stack));
1232 /* Code to throw out to outer context, if we get a throw from within
1233 our catch handler. */
1234 /* These are saved for the exception table. */
1236 entry.exception_handler_label = gen_label_rtx ();
1237 pop_rtl_from_perm ();
1238 emit_label (entry.exception_handler_label);
1239 emit_move_insn (saved_pc, gen_rtx (LABEL_REF,
1241 top_label_entry (&caught_return_label_stack)));
1242 make_first_label(throw_label);
1243 emit_jump (throw_label);
1244 /* No associated finalization. */
1245 entry.finalization = NULL_TREE;
1247 /* Because we are reordered out of line, we have to protect this. */
1248 /* label for the start of the protection region. */
1249 start_protect_label_rtx = pop_label_entry (&false_label_stack);
1251 /* Cleanup the EH paramater. */
1252 expand_end_bindings (decls = getdecls (), decls != NULL_TREE, 0);
1254 /* label we emit to jump to if this catch block didn't match. */
1255 emit_label (end_protect_label_rtx = pop_label_entry (&false_label_stack));
1257 /* Because we are reordered out of line, we have to protect this. */
1258 entry.start_label = start_protect_label_rtx;
1259 entry.end_label = end_protect_label_rtx;
1261 LABEL_PRESERVE_P (entry.start_label) = 1;
1262 LABEL_PRESERVE_P (entry.end_label) = 1;
1263 LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1265 /* These set up a call to throw the caught exception into the outer
1267 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1271 /* cheesyness to save some typing. returns the return value rtx */
1273 do_function_call (func, params, return_type)
1274 tree func, params, return_type;
1277 func_call = build_function_call (func, params);
1278 expand_call (func_call, NULL_RTX, 0);
1279 if (return_type != NULL_TREE)
1280 return hard_function_value (return_type, func_call);
1284 /* unwind the stack. */
1286 do_unwind (throw_label)
1290 extern FILE *asm_out_file;
1295 /* call to __builtin_return_address () */
1296 params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1297 fcall = build_function_call (BuiltinReturnAddress, params);
1298 return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
1299 /* In the return, the new pc is pc+8, as the value comming in is
1300 really the address of the call insn, not the next insn. */
1301 emit_move_insn (return_val_rtx, plus_constant(gen_rtx (LABEL_REF,
1304 /* We use three values, PC, type, and value */
1305 easy_expand_asm ("st %l0,[%fp]");
1306 easy_expand_asm ("st %l1,[%fp+4]");
1307 easy_expand_asm ("st %l2,[%fp+8]");
1308 easy_expand_asm ("ret");
1309 easy_expand_asm ("restore");
1312 #if defined(__i386) || defined(__rs6000) || defined(__hppa) || defined(__mc68000) || defined (__mips)
1313 extern FILE *asm_out_file;
1318 /* call to __builtin_return_address () */
1319 params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1320 fcall = build_function_call (BuiltinReturnAddress, params);
1321 return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
1323 /* I would like to do this here, but doesn't seem to work. */
1324 emit_move_insn (return_val_rtx, gen_rtx (LABEL_REF,
1327 /* So, for now, just pass throw label to stack unwinder. */
1329 /* We use three values, PC, type, and value */
1330 params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
1331 gen_rtx (LABEL_REF, Pmode, throw_label)), NULL_TREE);
1333 do_function_call (Unwind, params, NULL_TREE);
1334 assemble_external (TREE_OPERAND (Unwind, 0));
1338 rtx temp_frame = frame_pointer_rtx;
1340 temp_frame = memory_address (Pmode, temp_frame);
1341 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
1343 /* hopefully this will successfully pop the frame! */
1344 emit_move_insn (frame_pointer_rtx, temp_frame);
1345 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
1346 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
1347 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1348 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
1351 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1352 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1354 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
1356 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1357 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1361 if (flag_omit_frame_pointer)
1362 sorry ("this implementation of exception handling requires a frame pointer");
1364 emit_move_insn (stack_pointer_rtx,
1365 gen_rtx (MEM, SImode, plus_constant (hard_frame_pointer_rtx, -8)));
1366 emit_move_insn (hard_frame_pointer_rtx,
1367 gen_rtx (MEM, SImode, plus_constant (hard_frame_pointer_rtx, -12)));
1371 /* is called from expand_exception_blocks () to generate the code in a function
1372 to "throw" if anything in the function needs to preform a throw.
1374 expands "throw" as the following psuedo code:
1377 eh = find_first_exception_match (saved_pc);
1378 if (!eh) goto gotta_rethrow_it;
1382 saved_pc = __builtin_return_address (0);
1383 pop_to_previous_level ();
1388 expand_builtin_throw ()
1393 rtx gotta_rethrow_it = gen_label_rtx ();
1394 rtx gotta_call_terminate = gen_label_rtx ();
1395 rtx unwind_and_throw = gen_label_rtx ();
1396 rtx goto_unwind_and_throw = gen_label_rtx ();
1398 make_first_label(throw_label);
1399 emit_label (throw_label);
1401 /* search for an exception handler for the saved_pc */
1402 return_val_rtx = do_function_call (FirstExceptionMatch,
1403 tree_cons (NULL_TREE, make_tree (ptr_type_node, saved_pc), NULL_TREE),
1405 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
1407 /* did we find one? */
1408 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1409 GET_MODE (return_val_rtx), 0, 0);
1411 /* if not, jump to gotta_rethrow_it */
1412 emit_jump_insn (gen_beq (gotta_rethrow_it));
1414 /* we found it, so jump to it */
1415 emit_indirect_jump (return_val_rtx);
1417 /* code to deal with unwinding and looking for it again */
1418 emit_label (gotta_rethrow_it);
1420 /* call to __builtin_return_address () */
1422 /* This replaces a 'call' to __builtin_return_address */
1423 return_val_rtx = gen_reg_rtx (Pmode);
1424 emit_move_insn (return_val_rtx, gen_rtx (MEM, SImode, plus_constant (hard_frame_pointer_rtx, -4)));
1426 params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1427 fcall = build_function_call (BuiltinReturnAddress, params);
1428 return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
1431 /* did __builtin_return_address () return a valid address? */
1432 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1433 GET_MODE (return_val_rtx), 0, 0);
1435 emit_jump_insn (gen_beq (gotta_call_terminate));
1438 /* On the ARM, '__builtin_return_address', must have 4
1439 subtracted from it. */
1440 emit_insn (gen_add2_insn (return_val_rtx, GEN_INT (-4)));
1442 /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 in 26 bit
1443 mode, the condition codes must be masked out of the return value, or else
1444 they will confuse BuiltinReturnAddress. This does not apply to ARM6 and
1445 later processors when running in 32 bit mode. */
1447 emit_insn (gen_rtx (SET, SImode, return_val_rtx, gen_rtx (AND, SImode, return_val_rtx, GEN_INT (0x03fffffc))));
1450 /* On the SPARC, __builtin_return_address is already -8, no need to
1451 subtract any more from it. */
1452 emit_insn (gen_add2_insn (return_val_rtx, GEN_INT (-1)));
1457 emit_move_insn (saved_pc, return_val_rtx);
1458 do_unwind (throw_label);
1459 make_first_label(throw_label);
1460 emit_jump (throw_label);
1462 /* no it didn't --> therefore we need to call terminate */
1463 emit_label (gotta_call_terminate);
1464 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1465 assemble_external (TREE_OPERAND (Terminate, 0));
1469 /* This is called to expand all the toplevel exception handling
1470 finalization for a function. It should only be called once per
1473 expand_exception_blocks ()
1475 rtx catchstart, catchend;
1479 funcend = gen_label_rtx ();
1480 emit_jump (funcend);
1481 /* expand_null_return (); */
1483 while (pop_except_stmts (&exceptstack, &catchstart, &catchend)) {
1484 last = get_last_insn ();
1485 NEXT_INSN (last) = catchstart;
1486 PREV_INSN (catchstart) = last;
1487 NEXT_INSN (catchend) = 0;
1488 set_last_insn (catchend);
1491 expand_leftover_cleanups ();
1494 static int have_done = 0;
1495 if (! have_done && TREE_PUBLIC (current_function_decl)
1496 && DECL_INTERFACE_KNOWN (current_function_decl)
1497 && ! DECL_EXTERNAL (current_function_decl))
1500 expand_builtin_throw ();
1503 emit_label (funcend);
1507 /* call this to expand a throw statement. This follows the following
1510 1. Allocate space to save the current PC onto the stack.
1511 2. Generate and emit a label and save its address into the
1512 newly allocated stack space since we can't save the pc directly.
1513 3. If this is the first call to throw in this function:
1514 generate a label for the throw block
1515 4. jump to the throw block label. */
1526 /* This is the label that represents where in the code we were, when
1527 we got an exception. This needs to be updated when we rethrow an
1528 exception, so that the matching routine knows to search out. */
1529 label = gen_label_rtx ();
1531 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, label));
1535 /* throw expression */
1536 /* First, decay it. */
1537 exp = default_conversion (exp);
1538 type = TREE_TYPE (exp);
1541 char *typestring = build_overload_name (type, 1, 1);
1542 tree throw_type = build1 (ADDR_EXPR, ptr_type_node, combine_strings (build_string (strlen (typestring)+1, typestring)));
1543 rtx throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0);
1544 rtx throw_value_rtx;
1546 emit_move_insn (saved_throw_type, throw_type_rtx);
1547 exp = convert_to_reference (build_reference_type (build_type_variant (TREE_TYPE (exp), 1, 0)), exp, CONV_STATIC, LOOKUP_COMPLAIN, error_mark_node);
1549 /* Make a copy of the thrown object. WP 15.1.5 */
1550 exp = build_new (NULL_TREE, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (exp))), exp, 0);
1552 if (exp == error_mark_node)
1553 error (" in thrown expression");
1554 throw_value_rtx = expand_expr (exp, NULL_RTX, VOIDmode, 0);
1555 emit_move_insn (saved_throw_value, throw_value_rtx);
1560 /* rethrow current exception */
1561 /* This part is easy, as we dont' have to do anything else. */
1564 make_first_label(throw_label);
1565 emit_jump (throw_label);
1568 /* end of: my-cp-except.c */
1572 /* Output the exception table.
1573 Return the number of handlers. */
1575 build_exception_table ()
1579 extern FILE *asm_out_file;
1580 struct ehEntry *entry;
1586 while (entry = dequeue_eh_entry (&eh_table_output_queue))
1590 exception_section ();
1592 /* Beginning marker for table. */
1593 ASM_OUTPUT_ALIGN (asm_out_file, 2);
1594 ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_TABLE__");
1595 output_exception_table_entry (asm_out_file,
1596 const0_rtx, const0_rtx, const0_rtx);
1599 output_exception_table_entry (asm_out_file,
1600 entry->start_label, entry->end_label,
1601 entry->exception_handler_label);
1606 /* Ending marker for table. */
1607 ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_END__");
1608 output_exception_table_entry (asm_out_file,
1609 constm1_rtx, constm1_rtx, constm1_rtx);
1612 #endif /* TRY_NEW_EH */
1617 register_exception_table ()
1620 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
1622 gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
1624 #endif /* TRY_NEW_EH */
1627 /* Build a throw expression. */
1632 if (e != error_mark_node)
1634 e = build1 (THROW_EXPR, void_type_node, e);
1635 TREE_SIDE_EFFECTS (e) = 1;