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! */
53 static int warned = 0;
56 sorry ("exception handling not supported");
62 expand_exception_blocks ()
72 end_protect (finalization)
78 expand_start_try_stmts ()
84 expand_end_try_stmts ()
89 expand_start_all_catch ()
94 expand_end_all_catch ()
99 expand_start_catch_block (declspecs, declarator)
100 tree declspecs, declarator;
105 expand_end_catch_block ()
110 init_exception_processing ()
127 if (! flag_handle_exceptions)
129 static int warned = 0;
130 if (! warned && do_warn)
132 error ("exception handling disabled, use -fhandle-exceptions to enable.");
142 NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
143 to supporting exception handling as per Stroustrup's 2nd edition.
144 It is a complete rewrite of all the EH stuff that was here before
146 1. The type of the throw and catch must still match
147 exactly (no support yet for matching base classes)
148 2. Throw specifications of functions still doesnt't work.
150 1. Destructors are called properly :-)
151 2. No overhead for the non-exception thrown case.
152 3. Fixing shortcomings 1 and 2 is simple.
153 -Tad Hunt (tad@mail.csh.rit.edu)
157 /* A couple of backend routines from m88k.c */
159 /* used to cache a call to __builtin_return_address () */
160 static tree BuiltinReturnAddress;
168 /* XXX - Tad: for EH */
169 /* output an exception table entry */
172 output_exception_table_entry (file, start_label, end_label, eh_label)
174 rtx start_label, end_label, eh_label;
178 assemble_integer (start_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
179 assemble_integer (end_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
180 assemble_integer (eh_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
181 putc ('\n', file); /* blank line */
185 easy_expand_asm (str)
188 expand_asm (build_string (strlen (str)+1, str));
191 /* unwind the stack. */
193 do_unwind (throw_label)
197 extern FILE *asm_out_file;
202 /* call to __builtin_return_address () */
203 params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
204 fcall = build_function_call (BuiltinReturnAddress, params);
205 return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
206 /* In the return, the new pc is pc+8, as the value comming in is
207 really the address of the call insn, not the next insn. */
208 emit_move_insn (return_val_rtx, plus_constant(gen_rtx (LABEL_REF,
211 /* We use three values, PC, type, and value */
212 easy_expand_asm ("st %l0,[%fp]");
213 easy_expand_asm ("st %l1,[%fp+4]");
214 easy_expand_asm ("st %l2,[%fp+8]");
215 easy_expand_asm ("ret");
216 easy_expand_asm ("restore");
220 rtx temp_frame = frame_pointer_rtx;
222 temp_frame = memory_address (Pmode, temp_frame);
223 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
225 /* hopefully this will successfully pop the frame! */
226 emit_move_insn (frame_pointer_rtx, temp_frame);
227 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
228 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
229 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
230 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
233 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
234 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
236 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
238 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
239 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
247 /* This is the startup, and finish stuff per exception table. */
249 /* XXX - Tad: exception handling section */
250 #ifndef EXCEPT_SECTION_ASM_OP
251 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
254 #ifdef EXCEPT_SECTION_ASM_OP
258 void *exception_handler;
260 #endif /* EXCEPT_SECTION_ASM_OP */
262 #ifdef EXCEPT_SECTION_ASM_OP
264 /* on machines which support it, the exception table lives in another section,
265 but it needs a label so we can reference it... This sets up that
267 asm (EXCEPT_SECTION_ASM_OP);
268 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
269 asm (TEXT_SECTION_ASM_OP);
271 #endif /* EXCEPT_SECTION_ASM_OP */
273 #ifdef EXCEPT_SECTION_ASM_OP
275 /* we need to know where the end of the exception table is... so this
278 asm (EXCEPT_SECTION_ASM_OP);
279 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
280 asm (TEXT_SECTION_ASM_OP);
282 #endif /* EXCEPT_SECTION_ASM_OP */
289 #ifdef ASM_OUTPUT_SECTION_NAME
290 named_section (".gcc_except_table");
299 /* from: my-cp-except.c */
301 /* VI: ":set ts=4" */
303 #include <stdio.h> */
313 #include "insn-flags.h"
319 /* ======================================================================
320 Briefly the algorithm works like this:
322 When a constructor or start of a try block is encountered,
323 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
324 new entry in the unwind protection stack and returns a label to
325 output to start the protection for that block.
327 When a destructor or end try block is encountered, pop_eh_entry
328 (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
329 created when push_eh_entry () was called. The ehEntry structure
330 contains three things at this point. The start protect label,
331 the end protect label, and the exception handler label. The end
332 protect label should be output before the call to the destructor
333 (if any). If it was a destructor, then its parse tree is stored
334 in the finalization variable in the ehEntry structure. Otherwise
335 the finalization variable is set to NULL to reflect the fact that
336 is the the end of a try block. Next, this modified ehEntry node
337 is enqueued in the finalizations queue by calling
338 enqueue_eh_entry (&queue,entry).
340 +---------------------------------------------------------------+
341 |XXX: Will need modification to deal with partially |
342 | constructed arrays of objects |
344 | Basically, this consists of keeping track of how many |
345 | of the objects have been constructed already (this |
346 | should be in a register though, so that shouldn't be a |
348 +---------------------------------------------------------------+
350 When a catch block is encountered, there is a lot of work to be
353 Since we don't want to generate the catch block inline with the
354 regular flow of the function, we need to have some way of doing
355 so. Luckily, we have a couple of routines "get_last_insn ()" and
356 "set_last_insn ()" provided. When the start of a catch block is
357 encountered, we save a pointer to the last insn generated. After
358 the catch block is generated, we save a pointer to the first
359 catch block insn and the last catch block insn with the routines
360 "NEXT_INSN ()" and "get_last_insn ()". We then set the last insn
361 to be the last insn generated before the catch block, and set the
362 NEXT_INSN (last_insn) to zero.
364 Since catch blocks might be nested inside other catch blocks, and
365 we munge the chain of generated insns after the catch block is
366 generated, we need to store the pointers to the last insn
367 generated in a stack, so that when the end of a catch block is
368 encountered, the last insn before the current catch block can be
369 popped and set to be the last insn, and the first and last insns
370 of the catch block just generated can be enqueue'd for output at
373 Next we must insure that when the catch block is executed, all
374 finalizations for the matching try block have been completed. If
375 any of those finalizations throw an exception, we must call
376 terminate according to the ARM (section r.15.6.1). What this
377 means is that we need to dequeue and emit finalizations for each
378 entry in the ehQueue until we get to an entry with a NULL
379 finalization field. For any of the finalization entries, if it
380 is not a call to terminate (), we must protect it by giving it
381 another start label, end label, and exception handler label,
382 setting its finalization tree to be a call to terminate (), and
383 enqueue'ing this new ehEntry to be output at an outer level.
384 Finally, after all that is done, we can get around to outputting
385 the catch block which basically wraps all the "catch (...) {...}"
386 statements in a big if/then/else construct that matches the
387 correct block to call.
389 ===================================================================== */
391 extern rtx emit_insn PROTO((rtx));
392 extern rtx gen_nop PROTO(());
394 /* local globals for function calls
395 ====================================================================== */
397 /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
398 "set_unexpected ()" after default_conversion. (lib-except.c) */
399 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
401 /* used to cache __find_first_exception_table_match ()
402 for throw (lib-except.c) */
403 static tree FirstExceptionMatch;
405 /* used to cache a call to __unwind_function () (lib-except.c) */
408 /* holds a ready to emit call to "terminate ()". */
409 static tree TerminateFunctionCall;
411 /* ====================================================================== */
415 /* data structures for my various quick and dirty stacks and queues
416 Eventually, most of this should go away, because I think it can be
417 integrated with stuff already built into the compiler. */
419 /* =================================================================== */
423 struct labelNode *chain;
427 /* this is the most important structure here. Basically this is how I store
428 an exception table entry internally. */
432 rtx exception_handler_label;
438 struct ehEntry *entry;
439 struct ehNode *chain;
455 struct exceptNode *chain;
459 struct exceptNode *top;
461 /* ========================================================================= */
465 /* local globals - these local globals are for storing data necessary for
466 generating the exception table and code in the correct order.
468 ========================================================================= */
470 /* Holds the pc for doing "throw" */
472 /* Holds the type of the thing being thrown. */
473 rtx saved_throw_type;
474 /* Holds the value being thrown. */
475 rtx saved_throw_value;
479 static struct ehStack ehstack;
480 static struct ehQueue ehqueue;
481 static struct ehQueue eh_table_output_queue;
482 static struct exceptStack exceptstack;
483 static struct labelNode *false_label_stack = NULL;
484 static struct labelNode *caught_return_label_stack = NULL;
485 /* ========================================================================= */
487 /* function prototypes */
488 static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
489 static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
490 static void push_except_stmts PROTO((struct exceptStack *exceptstack,
491 rtx catchstart, rtx catchend));
492 static int pop_except_stmts PROTO((struct exceptStack *exceptstack,
493 rtx *catchstart, rtx *catchend));
494 static rtx push_eh_entry PROTO((struct ehStack *stack));
495 static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
496 static void new_eh_queue PROTO((struct ehQueue *queue));
497 static void new_eh_stack PROTO((struct ehStack *stack));
498 static void new_except_stack PROTO((struct exceptStack *queue));
499 static void push_last_insn PROTO(());
500 static rtx pop_last_insn PROTO(());
501 static void push_label_entry PROTO((struct labelNode **labelstack, rtx label));
502 static rtx pop_label_entry PROTO((struct labelNode **labelstack));
503 static rtx top_label_entry PROTO((struct labelNode **labelstack));
504 static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
508 /* All my cheesy stack/queue/misc data structure handling routines
510 ========================================================================= */
513 push_label_entry (labelstack, label)
514 struct labelNode **labelstack;
517 struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
519 newnode->label = label;
520 newnode->chain = *labelstack;
521 *labelstack = newnode;
525 pop_label_entry (labelstack)
526 struct labelNode **labelstack;
529 struct labelNode *tempnode;
531 if (! *labelstack) return NULL_RTX;
533 tempnode = *labelstack;
534 label = tempnode->label;
535 *labelstack = (*labelstack)->chain;
542 top_label_entry (labelstack)
543 struct labelNode **labelstack;
545 if (! *labelstack) return NULL_RTX;
547 return (*labelstack)->label;
551 push_except_stmts (exceptstack, catchstart, catchend)
552 struct exceptStack *exceptstack;
553 rtx catchstart, catchend;
555 struct exceptNode *newnode = (struct exceptNode*)
556 xmalloc (sizeof (struct exceptNode));
558 newnode->catchstart = catchstart;
559 newnode->catchend = catchend;
560 newnode->chain = exceptstack->top;
562 exceptstack->top = newnode;
566 pop_except_stmts (exceptstack, catchstart, catchend)
567 struct exceptStack *exceptstack;
568 rtx *catchstart, *catchend;
570 struct exceptNode *tempnode;
572 if (!exceptstack->top) {
573 *catchstart = *catchend = NULL_RTX;
577 tempnode = exceptstack->top;
578 exceptstack->top = exceptstack->top->chain;
580 *catchstart = tempnode->catchstart;
581 *catchend = tempnode->catchend;
587 /* Push to permanent obstack for rtl generation.
589 static struct obstack *saved_rtl_obstack;
593 extern struct obstack permanent_obstack;
594 extern struct obstack *rtl_obstack;
596 saved_rtl_obstack = rtl_obstack;
597 rtl_obstack = &permanent_obstack;
600 /* Pop back to normal rtl handling. */
604 extern struct obstack permanent_obstack;
605 extern struct obstack *rtl_obstack;
607 rtl_obstack = saved_rtl_obstack;
611 push_eh_entry (stack)
612 struct ehStack *stack;
614 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
615 struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
623 /* These are saved for the exception table. */
625 entry->start_label = gen_label_rtx ();
626 entry->end_label = gen_label_rtx ();
627 entry->exception_handler_label = gen_label_rtx ();
628 pop_rtl_from_perm ();
630 entry->finalization = NULL_TREE;
633 node->chain = stack->top;
636 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
638 return entry->start_label;
641 static struct ehEntry *
643 struct ehStack *stack;
645 struct ehNode *tempnode;
646 struct ehEntry *tempentry;
648 if (stack && (tempnode = stack->top)) {
649 tempentry = tempnode->entry;
650 stack->top = stack->top->chain;
659 static struct ehEntry *
660 copy_eh_entry (entry)
661 struct ehEntry *entry;
663 struct ehEntry *newentry;
665 newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
666 memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
672 enqueue_eh_entry (queue, entry)
673 struct ehQueue *queue;
674 struct ehEntry *entry;
676 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
681 if (queue->head == NULL)
687 queue->tail->chain = node;
692 static struct ehEntry *
693 dequeue_eh_entry (queue)
694 struct ehQueue *queue;
696 struct ehNode *tempnode;
697 struct ehEntry *tempentry;
699 if (queue->head == NULL)
702 tempnode = queue->head;
703 queue->head = queue->head->chain;
705 tempentry = tempnode->entry;
713 struct ehQueue *queue;
715 queue->head = queue->tail = NULL;
720 struct ehStack *stack;
726 new_except_stack (stack)
727 struct exceptStack *stack;
731 /* ========================================================================= */
734 lang_interim_eh (finalization)
738 end_protect (finalization);
743 /* sets up all the global eh stuff that needs to be initialized at the
744 start of compilation.
747 - Setting up all the function call trees
748 - Initializing the ehqueue
749 - Initializing the eh_table_output_queue
750 - Initializing the ehstack
751 - Initializing the exceptstack
755 init_exception_processing ()
757 extern tree define_function ();
758 tree unexpected_fndecl, terminate_fndecl;
759 tree set_unexpected_fndecl, set_terminate_fndecl;
760 tree catch_match_fndecl;
761 tree find_first_exception_match_fndecl;
765 interim_eh_hook = lang_interim_eh;
768 PFV = build_pointer_type (build_function_type (void_type_node, void_list_node));
770 /* arg list for the build_function_type call for set_terminate () and
772 temp = tree_cons (NULL_TREE, PFV, void_list_node);
774 push_lang_context (lang_name_c);
776 set_terminate_fndecl =
777 define_function ("set_terminate",
778 build_function_type (PFV, temp),
782 set_unexpected_fndecl =
783 define_function ("set_unexpected",
784 build_function_type (PFV, temp),
790 define_function ("unexpected",
791 build_function_type (void_type_node, void_list_node),
796 define_function ("terminate",
797 build_function_type (void_type_node, void_list_node),
802 define_function ("__throw_type_match",
803 build_function_type (integer_type_node,
804 tree_cons (NULL_TREE, string_type_node, tree_cons (NULL_TREE, ptr_type_node, void_list_node))),
808 find_first_exception_match_fndecl =
809 define_function ("__find_first_exception_table_match",
810 build_function_type (ptr_type_node,
811 tree_cons (NULL_TREE, ptr_type_node,
817 define_function ("__unwind_function",
818 build_function_type (void_type_node,
819 tree_cons (NULL_TREE, ptr_type_node, void_list_node)),
824 Unexpected = default_conversion (unexpected_fndecl);
825 Terminate = default_conversion (terminate_fndecl);
826 SetTerminate = default_conversion (set_terminate_fndecl);
827 SetUnexpected = default_conversion (set_unexpected_fndecl);
828 CatchMatch = default_conversion (catch_match_fndecl);
829 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
830 Unwind = default_conversion (unwind_fndecl);
831 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
833 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
836 throw_label = gen_label_rtx ();
837 saved_pc = gen_rtx (REG, Pmode, 16);
838 saved_throw_type = gen_rtx (REG, Pmode, 17);
839 saved_throw_value = gen_rtx (REG, Pmode, 18);
841 new_eh_queue (&ehqueue);
842 new_eh_queue (&eh_table_output_queue);
843 new_eh_stack (&ehstack);
844 new_except_stack (&exceptstack);
847 /* call this to begin a block of unwind protection (ie: when an object is
854 emit_label (push_eh_entry (&ehstack));
858 /* call this to end a block of unwind protection. the finalization tree is
859 the finalization which needs to be run in order to cleanly unwind through
860 this level of protection. (ie: call this when a scope is exited)*/
862 end_protect (finalization)
865 struct ehEntry *entry = pop_eh_entry (&ehstack);
870 emit_label (entry->end_label);
872 entry->finalization = finalization;
874 enqueue_eh_entry (&ehqueue, entry);
877 /* call this on start of a try block. */
879 expand_start_try_stmts ()
888 expand_end_try_stmts ()
890 end_protect (integer_zero_node);
893 struct insn_save_node {
895 struct insn_save_node *chain;
898 static struct insn_save_node *InsnSave = NULL;
901 /* Used to keep track of where the catch blocks start. */
905 struct insn_save_node *newnode = (struct insn_save_node*)
906 xmalloc (sizeof (struct insn_save_node));
908 newnode->last = get_last_insn ();
909 newnode->chain = InsnSave;
913 /* Use to keep track of where the catch blocks start. */
917 struct insn_save_node *tempnode;
920 if (!InsnSave) return NULL_RTX;
923 temprtx = tempnode->last;
924 InsnSave = InsnSave->chain;
931 /* call this to start processing of all the catch blocks. */
933 expand_start_all_catch ()
935 struct ehEntry *entry;
941 emit_line_note (input_filename, lineno);
942 label = gen_label_rtx ();
943 /* The label for the exception handling block we will save. */
946 push_label_entry (&caught_return_label_stack, label);
948 /* Remember where we started. */
951 emit_insn (gen_nop ());
953 /* Will this help us not stomp on it? */
954 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
955 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
959 entry = dequeue_eh_entry (&ehqueue);
960 emit_label (entry->exception_handler_label);
962 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
964 /* When we get down to the matching entry, stop. */
965 if (entry->finalization == integer_zero_node)
971 /* This goes when the below moves out of our way. */
973 label = gen_label_rtx ();
977 /* All this should be out of line, and saved back in the exception handler
980 entry->start_label = entry->exception_handler_label;
981 /* These are saved for the exception table. */
983 entry->end_label = gen_label_rtx ();
984 entry->exception_handler_label = gen_label_rtx ();
985 entry->finalization = TerminateFunctionCall;
986 pop_rtl_from_perm ();
987 emit_label (entry->end_label);
989 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
991 /* After running the finalization, continue on out to the next
992 cleanup, if we have nothing better to do. */
993 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry->end_label));
994 /* Will this help us not stomp on it? */
995 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
996 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
997 emit_jump (throw_label);
998 emit_label (entry->exception_handler_label);
999 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1005 /* call this to end processing of all the catch blocks. */
1007 expand_end_all_catch ()
1009 rtx catchstart, catchend, last;
1015 /* Find the start of the catch block. */
1016 last = pop_last_insn ();
1017 catchstart = NEXT_INSN (last);
1018 catchend = get_last_insn ();
1020 NEXT_INSN (last) = 0;
1021 set_last_insn (last);
1023 /* this level of catch blocks is done, so set up the successful catch jump
1024 label for the next layer of catch blocks. */
1025 pop_label_entry (&caught_return_label_stack);
1027 push_except_stmts (&exceptstack, catchstart, catchend);
1029 /* Here we fall through into the continuation code. */
1033 /* this is called from expand_exception_blocks () to expand the toplevel
1034 finalizations for a function. */
1036 expand_leftover_cleanups ()
1038 struct ehEntry *entry;
1039 rtx first_label = NULL_RTX;
1044 /* Will this help us not stomp on it? */
1045 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
1046 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
1048 while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
1051 first_label = entry->exception_handler_label;
1052 emit_label (entry->exception_handler_label);
1054 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1056 /* leftover try block, opps. */
1057 if (entry->finalization == integer_zero_node)
1065 struct ehEntry entry;
1066 /* These are saved for the exception table. */
1068 label = gen_label_rtx ();
1069 entry.start_label = first_label;
1070 entry.end_label = label;
1071 entry.exception_handler_label = gen_label_rtx ();
1072 entry.finalization = TerminateFunctionCall;
1073 pop_rtl_from_perm ();
1076 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1078 /* After running the finalization, continue on out to the next
1079 cleanup, if we have nothing better to do. */
1080 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry.end_label));
1081 /* Will this help us not stomp on it? */
1082 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
1083 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
1084 emit_jump (throw_label);
1085 emit_label (entry.exception_handler_label);
1086 expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
1091 /* call this to start a catch block. Typename is the typename, and identifier
1092 is the variable to place the object in or NULL if the variable doesn't
1093 matter. If typename is NULL, that means its a "catch (...)" or catch
1094 everything. In that case we don't need to do any type checking.
1095 (ie: it ends up as the "else" clause rather than an "else if" clause) */
1097 expand_start_catch_block (declspecs, declarator)
1098 tree declspecs, declarator;
1100 rtx false_label_rtx;
1101 rtx protect_label_rtx;
1109 /* Create a binding level for the parm. */
1110 expand_start_bindings (0);
1115 decl = grokdeclarator (declarator, declspecs, NORMAL, 1, NULL_TREE);
1117 /* Figure out the type that the initializer is. */
1118 init_type = TREE_TYPE (decl);
1119 if (TREE_CODE (init_type) != REFERENCE_TYPE)
1120 init_type = build_reference_type (init_type);
1122 init = convert_from_reference (save_expr (make_tree (init_type, saved_throw_value)));
1124 /* Do we need the below two lines? */
1125 /* Let `finish_decl' know that this initializer is ok. */
1126 DECL_INITIAL (decl) = init;
1127 /* This needs to be preallocated under the try block,
1128 in a union of all catch variables. */
1130 type = TREE_TYPE (decl);
1132 /* peel back references, so they match. */
1133 if (TREE_CODE (type) == REFERENCE_TYPE)
1134 type = TREE_TYPE (type);
1139 false_label_rtx = gen_label_rtx ();
1140 push_label_entry (&false_label_stack, false_label_rtx);
1142 /* This is saved for the exception table. */
1144 protect_label_rtx = gen_label_rtx ();
1145 pop_rtl_from_perm ();
1146 push_label_entry (&false_label_stack, protect_label_rtx);
1152 rtx call_rtx, return_value_rtx;
1153 tree catch_match_fcall;
1154 tree catchmatch_arg, argval;
1156 typestring = build_overload_name (type, 1, 1);
1158 params = tree_cons (NULL_TREE,
1159 combine_strings (build_string (strlen (typestring)+1, typestring)),
1160 tree_cons (NULL_TREE,
1161 make_tree (ptr_type_node, saved_throw_type),
1163 catch_match_fcall = build_function_call (CatchMatch, params);
1164 call_rtx = expand_call (catch_match_fcall, NULL_RTX, 0);
1167 hard_function_value (integer_type_node, catch_match_fcall);
1169 /* did the throw type match function return TRUE? */
1170 emit_cmp_insn (return_value_rtx, const0_rtx, NE, NULL_RTX,
1171 GET_MODE (return_value_rtx), 0, 0);
1173 /* if it returned FALSE, jump over the catch block, else fall into it */
1174 emit_jump_insn (gen_bne (false_label_rtx));
1175 finish_decl (decl, init, NULL_TREE, 0);
1179 /* Fall into the catch all section. */
1182 /* This is the starting of something to protect. */
1183 emit_label (protect_label_rtx);
1185 emit_line_note (input_filename, lineno);
1189 /* Call this to end a catch block. Its responsible for emitting the
1190 code to handle jumping back to the correct place, and for emitting
1191 the label to jump to if this catch block didn't match. */
1192 void expand_end_catch_block ()
1196 rtx start_protect_label_rtx;
1197 rtx end_protect_label_rtx;
1199 struct ehEntry entry;
1201 /* label we jump to if we caught the exception */
1202 emit_jump (top_label_entry (&caught_return_label_stack));
1204 /* Code to throw out to outer context, if we get an throw from within
1205 our catch handler. */
1206 /* These are saved for the exception table. */
1208 entry.exception_handler_label = gen_label_rtx ();
1209 pop_rtl_from_perm ();
1210 emit_label (entry.exception_handler_label);
1211 emit_move_insn (saved_pc, gen_rtx (LABEL_REF,
1213 top_label_entry (&caught_return_label_stack)));
1214 emit_jump (throw_label);
1215 /* No associated finalization. */
1216 entry.finalization = NULL_TREE;
1218 /* Because we are reordered out of line, we have to protect this. */
1219 /* label for the start of the protection region. */
1220 start_protect_label_rtx = pop_label_entry (&false_label_stack);
1222 /* Cleanup the EH paramater. */
1223 expand_end_bindings (decls = getdecls (), decls != NULL_TREE, 0);
1225 /* label we emit to jump to if this catch block didn't match. */
1226 emit_label (end_protect_label_rtx = pop_label_entry (&false_label_stack));
1228 /* Because we are reordered out of line, we have to protect this. */
1229 entry.start_label = start_protect_label_rtx;
1230 entry.end_label = end_protect_label_rtx;
1232 /* These set up a call to throw the caught exception into the outer
1234 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1238 /* cheesyness to save some typing. returns the return value rtx */
1240 do_function_call (func, params, return_type)
1241 tree func, params, return_type;
1244 func_call = build_function_call (func, params);
1245 expand_call (func_call, NULL_RTX, 0);
1246 if (return_type != NULL_TREE)
1247 return hard_function_value (return_type, func_call);
1252 /* is called from expand_excpetion_blocks () to generate the code in a function
1253 to "throw" if anything in the function needs to preform a throw.
1255 expands "throw" as the following psuedo code:
1258 eh = find_first_exception_match (saved_pc);
1259 if (!eh) goto gotta_rethrow_it;
1263 saved_pc = __builtin_return_address (0);
1264 pop_to_previous_level ();
1269 expand_builtin_throw ()
1274 rtx gotta_rethrow_it = gen_label_rtx ();
1275 rtx gotta_call_terminate = gen_label_rtx ();
1276 rtx unwind_and_throw = gen_label_rtx ();
1277 rtx goto_unwind_and_throw = gen_label_rtx ();
1279 emit_label (throw_label);
1281 /* search for an exception handler for the saved_pc */
1282 return_val_rtx = do_function_call (FirstExceptionMatch,
1283 tree_cons (NULL_TREE, make_tree (ptr_type_node, saved_pc), NULL_TREE),
1286 /* did we find one? */
1287 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1288 GET_MODE (return_val_rtx), 0, 0);
1290 /* if not, jump to gotta_rethrow_it */
1291 emit_jump_insn (gen_beq (gotta_rethrow_it));
1293 /* we found it, so jump to it */
1294 emit_indirect_jump (return_val_rtx);
1296 /* code to deal with unwinding and looking for it again */
1297 emit_label (gotta_rethrow_it);
1299 /* call to __builtin_return_address () */
1300 params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1301 fcall = build_function_call (BuiltinReturnAddress, params);
1302 return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
1304 /* did __builtin_return_address () return a valid address? */
1305 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1306 GET_MODE (return_val_rtx), 0, 0);
1308 emit_jump_insn (gen_beq (gotta_call_terminate));
1311 emit_move_insn (saved_pc, return_val_rtx);
1312 do_unwind (throw_label);
1313 emit_jump (throw_label);
1315 /* no it didn't --> therefore we need to call terminate */
1316 emit_label (gotta_call_terminate);
1317 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1321 /* This is called to expand all the toplevel exception handling
1322 finalization for a function. It should only be called once per
1325 expand_exception_blocks ()
1327 rtx catchstart, catchend;
1331 funcend = gen_label_rtx ();
1332 emit_jump (funcend);
1333 /* expand_null_return (); */
1335 while (pop_except_stmts (&exceptstack, &catchstart, &catchend)) {
1336 last = get_last_insn ();
1337 NEXT_INSN (last) = catchstart;
1338 PREV_INSN (catchstart) = last;
1339 NEXT_INSN (catchend) = 0;
1340 set_last_insn (catchend);
1343 expand_leftover_cleanups ();
1346 static int have_done = 0;
1347 if (! have_done && TREE_PUBLIC (current_function_decl)
1348 && ! DECL_INLINE (current_function_decl))
1351 expand_builtin_throw ();
1354 emit_label (funcend);
1358 /* call this to expand a throw statement. This follows the following
1361 1. Allocate space to save the current PC onto the stack.
1362 2. Generate and emit a label and save its address into the
1363 newly allocate stack space since we can't save the pc directly.
1364 3. If this is the first call to throw in this function:
1365 generate a label for the throw block
1366 4. jump to the throw block label. */
1377 /* This is the label that represents where in the code we were, when
1378 we got an exception. This needs to be updated when we rethrow an
1379 exception, so that the matching routine knows to search out. */
1380 label = gen_label_rtx ();
1382 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, label));
1386 /* throw expression */
1387 /* First, decay it. */
1388 exp = default_conversion (exp);
1389 type = TREE_TYPE (exp);
1392 char *typestring = build_overload_name (type, 1, 1);
1393 tree throw_type = build1 (ADDR_EXPR, ptr_type_node, combine_strings (build_string (strlen (typestring)+1, typestring)));
1394 rtx throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0);
1395 rtx throw_value_rtx;
1397 emit_move_insn (saved_throw_type, throw_type_rtx);
1398 exp = convert_to_reference (build_reference_type (build_type_variant (TREE_TYPE (exp), 1, 0)), exp, CONV_STATIC, LOOKUP_COMPLAIN, NULL_TREE);
1399 if (exp == error_mark_node)
1400 error (" in thrown expression");
1401 throw_value_rtx = expand_expr (build_unary_op (ADDR_EXPR, exp, 0), NULL_RTX, VOIDmode, 0);
1402 emit_move_insn (saved_throw_value, throw_value_rtx);
1407 /* rethrow current exception */
1408 /* This part is easy, as we dont' have to do anything else. */
1411 emit_jump (throw_label);
1414 /* end of: my-cp-except.c */
1418 /* Output the exception table.
1419 Return the number of handlers. */
1421 build_exception_table ()
1425 extern FILE *asm_out_file;
1426 struct ehEntry *entry;
1432 while (entry = dequeue_eh_entry (&eh_table_output_queue))
1436 exception_section ();
1438 /* Beginning marker for table. */
1439 ASM_OUTPUT_ALIGN (asm_out_file, 2);
1440 ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_TABLE__");
1441 fprintf (asm_out_file, " .word 0, 0, 0\n");
1444 output_exception_table_entry (asm_out_file,
1445 entry->start_label, entry->end_label,
1446 entry->exception_handler_label);
1451 /* Ending marker for table. */
1452 ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_END__");
1453 fprintf (asm_out_file, " .word -1, -1, -1\n");
1456 #endif /* TRY_NEW_EH */
1461 register_exception_table ()
1464 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
1466 gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
1468 #endif /* TRY_NEW_EH */
1471 /* Build a throw expression. */
1476 e = build1 (THROW_EXPR, void_type_node, e);
1477 TREE_SIDE_EFFECTS (e) = 1;