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! */
46 #if defined(__i386) || defined(__rs6000) || defined(__hppa)
56 static int warned = 0;
59 sorry ("exception handling not supported");
65 expand_exception_blocks ()
75 end_protect (finalization)
81 expand_start_try_stmts ()
87 expand_end_try_stmts ()
92 expand_start_all_catch ()
97 expand_end_all_catch ()
102 expand_start_catch_block (declspecs, declarator)
103 tree declspecs, declarator;
108 expand_end_catch_block ()
113 init_exception_processing ()
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.");
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
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.
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;
171 /* XXX - Tad: for EH */
172 /* output an exception table entry */
175 output_exception_table_entry (file, start_label, end_label, eh_label)
177 rtx start_label, end_label, eh_label;
181 assemble_integer (start_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
182 assemble_integer (end_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
183 assemble_integer (eh_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
184 putc ('\n', file); /* blank line */
188 easy_expand_asm (str)
191 expand_asm (build_string (strlen (str)+1, str));
196 /* This is the startup, and finish stuff per exception table. */
198 /* XXX - Tad: exception handling section */
199 #ifndef EXCEPT_SECTION_ASM_OP
200 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
203 #ifdef EXCEPT_SECTION_ASM_OP
207 void *exception_handler;
209 #endif /* EXCEPT_SECTION_ASM_OP */
211 #ifdef EXCEPT_SECTION_ASM_OP
213 /* on machines which support it, the exception table lives in another section,
214 but it needs a label so we can reference it... This sets up that
216 asm (EXCEPT_SECTION_ASM_OP);
217 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
218 asm (TEXT_SECTION_ASM_OP);
220 #endif /* EXCEPT_SECTION_ASM_OP */
222 #ifdef EXCEPT_SECTION_ASM_OP
224 /* we need to know where the end of the exception table is... so this
227 asm (EXCEPT_SECTION_ASM_OP);
228 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
229 asm (TEXT_SECTION_ASM_OP);
231 #endif /* EXCEPT_SECTION_ASM_OP */
238 #ifdef ASM_OUTPUT_SECTION_NAME
239 named_section (".gcc_except_table");
248 /* from: my-cp-except.c */
250 /* VI: ":set ts=4" */
252 #include <stdio.h> */
262 #include "insn-flags.h"
268 /* ======================================================================
269 Briefly the algorithm works like this:
271 When a constructor or start of a try block is encountered,
272 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
273 new entry in the unwind protection stack and returns a label to
274 output to start the protection for that block.
276 When a destructor or end try block is encountered, pop_eh_entry
277 (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
278 created when push_eh_entry () was called. The ehEntry structure
279 contains three things at this point. The start protect label,
280 the end protect label, and the exception handler label. The end
281 protect label should be output before the call to the destructor
282 (if any). If it was a destructor, then its parse tree is stored
283 in the finalization variable in the ehEntry structure. Otherwise
284 the finalization variable is set to NULL to reflect the fact that
285 is the the end of a try block. Next, this modified ehEntry node
286 is enqueued in the finalizations queue by calling
287 enqueue_eh_entry (&queue,entry).
289 +---------------------------------------------------------------+
290 |XXX: Will need modification to deal with partially |
291 | constructed arrays of objects |
293 | Basically, this consists of keeping track of how many |
294 | of the objects have been constructed already (this |
295 | should be in a register though, so that shouldn't be a |
297 +---------------------------------------------------------------+
299 When a catch block is encountered, there is a lot of work to be
302 Since we don't want to generate the catch block inline with the
303 regular flow of the function, we need to have some way of doing
304 so. Luckily, we have a couple of routines "get_last_insn ()" and
305 "set_last_insn ()" provided. When the start of a catch block is
306 encountered, we save a pointer to the last insn generated. After
307 the catch block is generated, we save a pointer to the first
308 catch block insn and the last catch block insn with the routines
309 "NEXT_INSN ()" and "get_last_insn ()". We then set the last insn
310 to be the last insn generated before the catch block, and set the
311 NEXT_INSN (last_insn) to zero.
313 Since catch blocks might be nested inside other catch blocks, and
314 we munge the chain of generated insns after the catch block is
315 generated, we need to store the pointers to the last insn
316 generated in a stack, so that when the end of a catch block is
317 encountered, the last insn before the current catch block can be
318 popped and set to be the last insn, and the first and last insns
319 of the catch block just generated can be enqueue'd for output at
322 Next we must insure that when the catch block is executed, all
323 finalizations for the matching try block have been completed. If
324 any of those finalizations throw an exception, we must call
325 terminate according to the ARM (section r.15.6.1). What this
326 means is that we need to dequeue and emit finalizations for each
327 entry in the ehQueue until we get to an entry with a NULL
328 finalization field. For any of the finalization entries, if it
329 is not a call to terminate (), we must protect it by giving it
330 another start label, end label, and exception handler label,
331 setting its finalization tree to be a call to terminate (), and
332 enqueue'ing this new ehEntry to be output at an outer level.
333 Finally, after all that is done, we can get around to outputting
334 the catch block which basically wraps all the "catch (...) {...}"
335 statements in a big if/then/else construct that matches the
336 correct block to call.
338 ===================================================================== */
340 extern rtx emit_insn PROTO((rtx));
341 extern rtx gen_nop PROTO(());
343 /* local globals for function calls
344 ====================================================================== */
346 /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
347 "set_unexpected ()" after default_conversion. (lib-except.c) */
348 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
350 /* used to cache __find_first_exception_table_match ()
351 for throw (lib-except.c) */
352 static tree FirstExceptionMatch;
354 /* used to cache a call to __unwind_function () (lib-except.c) */
357 /* holds a ready to emit call to "terminate ()". */
358 static tree TerminateFunctionCall;
360 /* ====================================================================== */
364 /* data structures for my various quick and dirty stacks and queues
365 Eventually, most of this should go away, because I think it can be
366 integrated with stuff already built into the compiler. */
368 /* =================================================================== */
372 struct labelNode *chain;
376 /* this is the most important structure here. Basically this is how I store
377 an exception table entry internally. */
381 rtx exception_handler_label;
387 struct ehEntry *entry;
388 struct ehNode *chain;
404 struct exceptNode *chain;
408 struct exceptNode *top;
410 /* ========================================================================= */
414 /* local globals - these local globals are for storing data necessary for
415 generating the exception table and code in the correct order.
417 ========================================================================= */
419 /* Holds the pc for doing "throw" */
421 /* Holds the type of the thing being thrown. */
422 rtx saved_throw_type;
423 /* Holds the value being thrown. */
424 rtx saved_throw_value;
428 static struct ehStack ehstack;
429 static struct ehQueue ehqueue;
430 static struct ehQueue eh_table_output_queue;
431 static struct exceptStack exceptstack;
432 static struct labelNode *false_label_stack = NULL;
433 static struct labelNode *caught_return_label_stack = NULL;
434 /* ========================================================================= */
436 /* function prototypes */
437 static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
438 static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
439 static void push_except_stmts PROTO((struct exceptStack *exceptstack,
440 rtx catchstart, rtx catchend));
441 static int pop_except_stmts PROTO((struct exceptStack *exceptstack,
442 rtx *catchstart, rtx *catchend));
443 static rtx push_eh_entry PROTO((struct ehStack *stack));
444 static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
445 static void new_eh_queue PROTO((struct ehQueue *queue));
446 static void new_eh_stack PROTO((struct ehStack *stack));
447 static void new_except_stack PROTO((struct exceptStack *queue));
448 static void push_last_insn PROTO(());
449 static rtx pop_last_insn PROTO(());
450 static void push_label_entry PROTO((struct labelNode **labelstack, rtx label));
451 static rtx pop_label_entry PROTO((struct labelNode **labelstack));
452 static rtx top_label_entry PROTO((struct labelNode **labelstack));
453 static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
457 /* All my cheesy stack/queue/misc data structure handling routines
459 ========================================================================= */
462 push_label_entry (labelstack, label)
463 struct labelNode **labelstack;
466 struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
468 newnode->label = label;
469 newnode->chain = *labelstack;
470 *labelstack = newnode;
474 pop_label_entry (labelstack)
475 struct labelNode **labelstack;
478 struct labelNode *tempnode;
480 if (! *labelstack) return NULL_RTX;
482 tempnode = *labelstack;
483 label = tempnode->label;
484 *labelstack = (*labelstack)->chain;
491 top_label_entry (labelstack)
492 struct labelNode **labelstack;
494 if (! *labelstack) return NULL_RTX;
496 return (*labelstack)->label;
500 push_except_stmts (exceptstack, catchstart, catchend)
501 struct exceptStack *exceptstack;
502 rtx catchstart, catchend;
504 struct exceptNode *newnode = (struct exceptNode*)
505 xmalloc (sizeof (struct exceptNode));
507 newnode->catchstart = catchstart;
508 newnode->catchend = catchend;
509 newnode->chain = exceptstack->top;
511 exceptstack->top = newnode;
515 pop_except_stmts (exceptstack, catchstart, catchend)
516 struct exceptStack *exceptstack;
517 rtx *catchstart, *catchend;
519 struct exceptNode *tempnode;
521 if (!exceptstack->top) {
522 *catchstart = *catchend = NULL_RTX;
526 tempnode = exceptstack->top;
527 exceptstack->top = exceptstack->top->chain;
529 *catchstart = tempnode->catchstart;
530 *catchend = tempnode->catchend;
536 /* Push to permanent obstack for rtl generation.
538 static struct obstack *saved_rtl_obstack;
542 extern struct obstack permanent_obstack;
543 extern struct obstack *rtl_obstack;
545 saved_rtl_obstack = rtl_obstack;
546 rtl_obstack = &permanent_obstack;
549 /* Pop back to normal rtl handling. */
553 extern struct obstack permanent_obstack;
554 extern struct obstack *rtl_obstack;
556 rtl_obstack = saved_rtl_obstack;
560 push_eh_entry (stack)
561 struct ehStack *stack;
563 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
564 struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
572 /* These are saved for the exception table. */
574 entry->start_label = gen_label_rtx ();
575 entry->end_label = gen_label_rtx ();
576 entry->exception_handler_label = gen_label_rtx ();
577 pop_rtl_from_perm ();
579 entry->finalization = NULL_TREE;
582 node->chain = stack->top;
585 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
587 return entry->start_label;
590 static struct ehEntry *
592 struct ehStack *stack;
594 struct ehNode *tempnode;
595 struct ehEntry *tempentry;
597 if (stack && (tempnode = stack->top)) {
598 tempentry = tempnode->entry;
599 stack->top = stack->top->chain;
608 static struct ehEntry *
609 copy_eh_entry (entry)
610 struct ehEntry *entry;
612 struct ehEntry *newentry;
614 newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
615 memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
621 enqueue_eh_entry (queue, entry)
622 struct ehQueue *queue;
623 struct ehEntry *entry;
625 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
630 if (queue->head == NULL)
636 queue->tail->chain = node;
641 static struct ehEntry *
642 dequeue_eh_entry (queue)
643 struct ehQueue *queue;
645 struct ehNode *tempnode;
646 struct ehEntry *tempentry;
648 if (queue->head == NULL)
651 tempnode = queue->head;
652 queue->head = queue->head->chain;
654 tempentry = tempnode->entry;
662 struct ehQueue *queue;
664 queue->head = queue->tail = NULL;
669 struct ehStack *stack;
675 new_except_stack (stack)
676 struct exceptStack *stack;
680 /* ========================================================================= */
683 lang_interim_eh (finalization)
687 end_protect (finalization);
692 /* sets up all the global eh stuff that needs to be initialized at the
693 start of compilation.
696 - Setting up all the function call trees
697 - Initializing the ehqueue
698 - Initializing the eh_table_output_queue
699 - Initializing the ehstack
700 - Initializing the exceptstack
704 init_exception_processing ()
706 extern tree define_function ();
707 tree unexpected_fndecl, terminate_fndecl;
708 tree set_unexpected_fndecl, set_terminate_fndecl;
709 tree catch_match_fndecl;
710 tree find_first_exception_match_fndecl;
714 interim_eh_hook = lang_interim_eh;
717 PFV = build_pointer_type (build_function_type (void_type_node, void_list_node));
719 /* arg list for the build_function_type call for set_terminate () and
721 temp = tree_cons (NULL_TREE, PFV, void_list_node);
723 push_lang_context (lang_name_c);
725 set_terminate_fndecl =
726 define_function ("set_terminate",
727 build_function_type (PFV, temp),
731 set_unexpected_fndecl =
732 define_function ("set_unexpected",
733 build_function_type (PFV, temp),
739 define_function ("unexpected",
740 build_function_type (void_type_node, void_list_node),
745 define_function ("terminate",
746 build_function_type (void_type_node, void_list_node),
751 define_function ("__throw_type_match",
752 build_function_type (integer_type_node,
753 tree_cons (NULL_TREE, string_type_node, tree_cons (NULL_TREE, ptr_type_node, void_list_node))),
757 find_first_exception_match_fndecl =
758 define_function ("__find_first_exception_table_match",
759 build_function_type (ptr_type_node,
760 tree_cons (NULL_TREE, ptr_type_node,
766 define_function ("__unwind_function",
767 build_function_type (void_type_node,
768 tree_cons (NULL_TREE, ptr_type_node, void_list_node)),
773 Unexpected = default_conversion (unexpected_fndecl);
774 Terminate = default_conversion (terminate_fndecl);
775 SetTerminate = default_conversion (set_terminate_fndecl);
776 SetUnexpected = default_conversion (set_unexpected_fndecl);
777 CatchMatch = default_conversion (catch_match_fndecl);
778 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
779 Unwind = default_conversion (unwind_fndecl);
780 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
782 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
785 throw_label = gen_label_rtx ();
787 saved_pc = gen_rtx (REG, Pmode, 16);
788 saved_throw_type = gen_rtx (REG, Pmode, 17);
789 saved_throw_value = gen_rtx (REG, Pmode, 18);
792 saved_pc = gen_rtx (REG, Pmode, 3);
793 saved_throw_type = gen_rtx (REG, Pmode, 4);
794 saved_throw_value = gen_rtx (REG, Pmode, 5);
797 saved_pc = gen_rtx (REG, Pmode, 12);
798 saved_throw_type = gen_rtx (REG, Pmode, 13);
799 saved_throw_value = gen_rtx (REG, Pmode, 14);
802 saved_pc = gen_rtx (REG, Pmode, 5);
803 saved_throw_type = gen_rtx (REG, Pmode, 6);
804 saved_throw_value = gen_rtx (REG, Pmode, 7);
806 new_eh_queue (&ehqueue);
807 new_eh_queue (&eh_table_output_queue);
808 new_eh_stack (&ehstack);
809 new_except_stack (&exceptstack);
812 /* call this to begin a block of unwind protection (ie: when an object is
819 emit_label (push_eh_entry (&ehstack));
823 /* call this to end a block of unwind protection. the finalization tree is
824 the finalization which needs to be run in order to cleanly unwind through
825 this level of protection. (ie: call this when a scope is exited)*/
827 end_protect (finalization)
830 struct ehEntry *entry = pop_eh_entry (&ehstack);
835 emit_label (entry->end_label);
837 entry->finalization = finalization;
839 enqueue_eh_entry (&ehqueue, entry);
842 /* call this on start of a try block. */
844 expand_start_try_stmts ()
853 expand_end_try_stmts ()
855 end_protect (integer_zero_node);
858 struct insn_save_node {
860 struct insn_save_node *chain;
863 static struct insn_save_node *InsnSave = NULL;
866 /* Used to keep track of where the catch blocks start. */
870 struct insn_save_node *newnode = (struct insn_save_node*)
871 xmalloc (sizeof (struct insn_save_node));
873 newnode->last = get_last_insn ();
874 newnode->chain = InsnSave;
878 /* Use to keep track of where the catch blocks start. */
882 struct insn_save_node *tempnode;
885 if (!InsnSave) return NULL_RTX;
888 temprtx = tempnode->last;
889 InsnSave = InsnSave->chain;
896 /* call this to start processing of all the catch blocks. */
898 expand_start_all_catch ()
900 struct ehEntry *entry;
906 emit_line_note (input_filename, lineno);
907 label = gen_label_rtx ();
908 /* The label for the exception handling block we will save. */
911 push_label_entry (&caught_return_label_stack, label);
913 /* Remember where we started. */
916 emit_insn (gen_nop ());
918 /* Will this help us not stomp on it? */
919 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
920 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
924 entry = dequeue_eh_entry (&ehqueue);
925 emit_label (entry->exception_handler_label);
927 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
929 /* When we get down to the matching entry, stop. */
930 if (entry->finalization == integer_zero_node)
936 /* This goes when the below moves out of our way. */
938 label = gen_label_rtx ();
942 /* All this should be out of line, and saved back in the exception handler
945 entry->start_label = entry->exception_handler_label;
946 /* These are saved for the exception table. */
948 entry->end_label = gen_label_rtx ();
949 entry->exception_handler_label = gen_label_rtx ();
950 entry->finalization = TerminateFunctionCall;
951 pop_rtl_from_perm ();
952 emit_label (entry->end_label);
954 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
956 /* After running the finalization, continue on out to the next
957 cleanup, if we have nothing better to do. */
958 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry->end_label));
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));
962 emit_jump (throw_label);
963 emit_label (entry->exception_handler_label);
964 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
970 /* call this to end processing of all the catch blocks. */
972 expand_end_all_catch ()
974 rtx catchstart, catchend, last;
980 /* Find the start of the catch block. */
981 last = pop_last_insn ();
982 catchstart = NEXT_INSN (last);
983 catchend = get_last_insn ();
985 NEXT_INSN (last) = 0;
986 set_last_insn (last);
988 /* this level of catch blocks is done, so set up the successful catch jump
989 label for the next layer of catch blocks. */
990 pop_label_entry (&caught_return_label_stack);
992 push_except_stmts (&exceptstack, catchstart, catchend);
994 /* Here we fall through into the continuation code. */
998 /* this is called from expand_exception_blocks () to expand the toplevel
999 finalizations for a function. */
1001 expand_leftover_cleanups ()
1003 struct ehEntry *entry;
1004 rtx first_label = NULL_RTX;
1009 /* Will this help us not stomp on it? */
1010 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
1011 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
1013 while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
1016 first_label = entry->exception_handler_label;
1017 emit_label (entry->exception_handler_label);
1019 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1021 /* leftover try block, opps. */
1022 if (entry->finalization == integer_zero_node)
1030 struct ehEntry entry;
1031 /* These are saved for the exception table. */
1033 label = gen_label_rtx ();
1034 entry.start_label = first_label;
1035 entry.end_label = label;
1036 entry.exception_handler_label = gen_label_rtx ();
1037 entry.finalization = TerminateFunctionCall;
1038 pop_rtl_from_perm ();
1041 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1043 /* After running the finalization, continue on out to the next
1044 cleanup, if we have nothing better to do. */
1045 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry.end_label));
1046 /* Will this help us not stomp on it? */
1047 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
1048 emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
1049 emit_jump (throw_label);
1050 emit_label (entry.exception_handler_label);
1051 expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
1056 /* call this to start a catch block. Typename is the typename, and identifier
1057 is the variable to place the object in or NULL if the variable doesn't
1058 matter. If typename is NULL, that means its a "catch (...)" or catch
1059 everything. In that case we don't need to do any type checking.
1060 (ie: it ends up as the "else" clause rather than an "else if" clause) */
1062 expand_start_catch_block (declspecs, declarator)
1063 tree declspecs, declarator;
1065 rtx false_label_rtx;
1066 rtx protect_label_rtx;
1074 /* Create a binding level for the parm. */
1075 expand_start_bindings (0);
1080 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
1082 /* Figure out the type that the initializer is. */
1083 init_type = TREE_TYPE (decl);
1084 if (TREE_CODE (init_type) != REFERENCE_TYPE)
1085 init_type = build_reference_type (init_type);
1087 init = convert_from_reference (save_expr (make_tree (init_type, saved_throw_value)));
1089 /* Do we need the below two lines? */
1090 /* Let `finish_decl' know that this initializer is ok. */
1091 DECL_INITIAL (decl) = init;
1092 /* This needs to be preallocated under the try block,
1093 in a union of all catch variables. */
1095 type = TREE_TYPE (decl);
1097 /* peel back references, so they match. */
1098 if (TREE_CODE (type) == REFERENCE_TYPE)
1099 type = TREE_TYPE (type);
1104 /* These are saved for the exception table. */
1106 false_label_rtx = gen_label_rtx ();
1107 protect_label_rtx = gen_label_rtx ();
1108 pop_rtl_from_perm ();
1109 push_label_entry (&false_label_stack, false_label_rtx);
1110 push_label_entry (&false_label_stack, protect_label_rtx);
1116 rtx call_rtx, return_value_rtx;
1117 tree catch_match_fcall;
1118 tree catchmatch_arg, argval;
1120 typestring = build_overload_name (type, 1, 1);
1122 params = tree_cons (NULL_TREE,
1123 combine_strings (build_string (strlen (typestring)+1, typestring)),
1124 tree_cons (NULL_TREE,
1125 make_tree (ptr_type_node, saved_throw_type),
1127 catch_match_fcall = build_function_call (CatchMatch, params);
1128 call_rtx = expand_call (catch_match_fcall, NULL_RTX, 0);
1131 hard_function_value (integer_type_node, catch_match_fcall);
1133 /* did the throw type match function return TRUE? */
1134 emit_cmp_insn (return_value_rtx, const0_rtx, NE, NULL_RTX,
1135 GET_MODE (return_value_rtx), 0, 0);
1137 /* if it returned FALSE, jump over the catch block, else fall into it */
1138 emit_jump_insn (gen_bne (false_label_rtx));
1139 finish_decl (decl, init, NULL_TREE, 0);
1143 /* Fall into the catch all section. */
1146 /* This is the starting of something to protect. */
1147 emit_label (protect_label_rtx);
1149 emit_line_note (input_filename, lineno);
1153 /* Call this to end a catch block. Its responsible for emitting the
1154 code to handle jumping back to the correct place, and for emitting
1155 the label to jump to if this catch block didn't match. */
1156 void expand_end_catch_block ()
1160 rtx start_protect_label_rtx;
1161 rtx end_protect_label_rtx;
1163 struct ehEntry entry;
1165 /* label we jump to if we caught the exception */
1166 emit_jump (top_label_entry (&caught_return_label_stack));
1168 /* Code to throw out to outer context, if we get an throw from within
1169 our catch handler. */
1170 /* These are saved for the exception table. */
1172 entry.exception_handler_label = gen_label_rtx ();
1173 pop_rtl_from_perm ();
1174 emit_label (entry.exception_handler_label);
1175 emit_move_insn (saved_pc, gen_rtx (LABEL_REF,
1177 top_label_entry (&caught_return_label_stack)));
1178 emit_jump (throw_label);
1179 /* No associated finalization. */
1180 entry.finalization = NULL_TREE;
1182 /* Because we are reordered out of line, we have to protect this. */
1183 /* label for the start of the protection region. */
1184 start_protect_label_rtx = pop_label_entry (&false_label_stack);
1186 /* Cleanup the EH paramater. */
1187 expand_end_bindings (decls = getdecls (), decls != NULL_TREE, 0);
1189 /* label we emit to jump to if this catch block didn't match. */
1190 emit_label (end_protect_label_rtx = pop_label_entry (&false_label_stack));
1192 /* Because we are reordered out of line, we have to protect this. */
1193 entry.start_label = start_protect_label_rtx;
1194 entry.end_label = end_protect_label_rtx;
1196 /* These set up a call to throw the caught exception into the outer
1198 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1202 /* cheesyness to save some typing. returns the return value rtx */
1204 do_function_call (func, params, return_type)
1205 tree func, params, return_type;
1208 func_call = build_function_call (func, params);
1209 expand_call (func_call, NULL_RTX, 0);
1210 if (return_type != NULL_TREE)
1211 return hard_function_value (return_type, func_call);
1215 /* unwind the stack. */
1217 do_unwind (throw_label)
1221 extern FILE *asm_out_file;
1226 /* call to __builtin_return_address () */
1227 params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1228 fcall = build_function_call (BuiltinReturnAddress, params);
1229 return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
1230 /* In the return, the new pc is pc+8, as the value comming in is
1231 really the address of the call insn, not the next insn. */
1232 emit_move_insn (return_val_rtx, plus_constant(gen_rtx (LABEL_REF,
1235 /* We use three values, PC, type, and value */
1236 easy_expand_asm ("st %l0,[%fp]");
1237 easy_expand_asm ("st %l1,[%fp+4]");
1238 easy_expand_asm ("st %l2,[%fp+8]");
1239 easy_expand_asm ("ret");
1240 easy_expand_asm ("restore");
1243 #if defined(__i386) || defined(__rs6000) || defined(__hppa)
1244 extern FILE *asm_out_file;
1249 /* call to __builtin_return_address () */
1250 params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1251 fcall = build_function_call (BuiltinReturnAddress, params);
1252 return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
1254 /* I would like to do this here, but doesn't seem to work. */
1255 emit_move_insn (return_val_rtx, gen_rtx (LABEL_REF,
1258 /* So, for now, just pass throw label to stack unwinder. */
1260 /* We use three values, PC, type, and value */
1261 params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
1262 gen_rtx (LABEL_REF, Pmode, throw_label)), NULL_TREE);
1264 do_function_call (Unwind, params, NULL_TREE);
1268 rtx temp_frame = frame_pointer_rtx;
1270 temp_frame = memory_address (Pmode, temp_frame);
1271 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
1273 /* hopefully this will successfully pop the frame! */
1274 emit_move_insn (frame_pointer_rtx, temp_frame);
1275 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
1276 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
1277 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1278 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
1281 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1282 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1284 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
1286 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1287 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1292 /* is called from expand_excpetion_blocks () to generate the code in a function
1293 to "throw" if anything in the function needs to preform a throw.
1295 expands "throw" as the following psuedo code:
1298 eh = find_first_exception_match (saved_pc);
1299 if (!eh) goto gotta_rethrow_it;
1303 saved_pc = __builtin_return_address (0);
1304 pop_to_previous_level ();
1309 expand_builtin_throw ()
1314 rtx gotta_rethrow_it = gen_label_rtx ();
1315 rtx gotta_call_terminate = gen_label_rtx ();
1316 rtx unwind_and_throw = gen_label_rtx ();
1317 rtx goto_unwind_and_throw = gen_label_rtx ();
1319 emit_label (throw_label);
1321 /* search for an exception handler for the saved_pc */
1322 return_val_rtx = do_function_call (FirstExceptionMatch,
1323 tree_cons (NULL_TREE, make_tree (ptr_type_node, saved_pc), NULL_TREE),
1326 /* did we find one? */
1327 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1328 GET_MODE (return_val_rtx), 0, 0);
1330 /* if not, jump to gotta_rethrow_it */
1331 emit_jump_insn (gen_beq (gotta_rethrow_it));
1333 /* we found it, so jump to it */
1334 emit_indirect_jump (return_val_rtx);
1336 /* code to deal with unwinding and looking for it again */
1337 emit_label (gotta_rethrow_it);
1339 /* call to __builtin_return_address () */
1340 params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1341 fcall = build_function_call (BuiltinReturnAddress, params);
1342 return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
1344 /* did __builtin_return_address () return a valid address? */
1345 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1346 GET_MODE (return_val_rtx), 0, 0);
1348 emit_jump_insn (gen_beq (gotta_call_terminate));
1351 /* On the SPARC, __builtin_return_address is already -8, no need to
1352 subtract any more from it. */
1353 emit_insn (gen_add2_insn (return_val_rtx, GEN_INT (-1)));
1357 emit_move_insn (saved_pc, return_val_rtx);
1358 do_unwind (throw_label);
1359 emit_jump (throw_label);
1361 /* no it didn't --> therefore we need to call terminate */
1362 emit_label (gotta_call_terminate);
1363 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1367 /* This is called to expand all the toplevel exception handling
1368 finalization for a function. It should only be called once per
1371 expand_exception_blocks ()
1373 rtx catchstart, catchend;
1377 funcend = gen_label_rtx ();
1378 emit_jump (funcend);
1379 /* expand_null_return (); */
1381 while (pop_except_stmts (&exceptstack, &catchstart, &catchend)) {
1382 last = get_last_insn ();
1383 NEXT_INSN (last) = catchstart;
1384 PREV_INSN (catchstart) = last;
1385 NEXT_INSN (catchend) = 0;
1386 set_last_insn (catchend);
1389 expand_leftover_cleanups ();
1392 static int have_done = 0;
1393 if (! have_done && TREE_PUBLIC (current_function_decl)
1394 && DECL_INTERFACE_KNOWN (current_function_decl)
1395 && ! DECL_EXTERNAL (current_function_decl))
1398 expand_builtin_throw ();
1401 emit_label (funcend);
1405 /* call this to expand a throw statement. This follows the following
1408 1. Allocate space to save the current PC onto the stack.
1409 2. Generate and emit a label and save its address into the
1410 newly allocate stack space since we can't save the pc directly.
1411 3. If this is the first call to throw in this function:
1412 generate a label for the throw block
1413 4. jump to the throw block label. */
1424 /* This is the label that represents where in the code we were, when
1425 we got an exception. This needs to be updated when we rethrow an
1426 exception, so that the matching routine knows to search out. */
1427 label = gen_label_rtx ();
1429 emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, label));
1433 /* throw expression */
1434 /* First, decay it. */
1435 exp = default_conversion (exp);
1436 type = TREE_TYPE (exp);
1439 char *typestring = build_overload_name (type, 1, 1);
1440 tree throw_type = build1 (ADDR_EXPR, ptr_type_node, combine_strings (build_string (strlen (typestring)+1, typestring)));
1441 rtx throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0);
1442 rtx throw_value_rtx;
1444 emit_move_insn (saved_throw_type, throw_type_rtx);
1445 exp = convert_to_reference (build_reference_type (build_type_variant (TREE_TYPE (exp), 1, 0)), exp, CONV_STATIC, LOOKUP_COMPLAIN, error_mark_node);
1446 if (exp == error_mark_node)
1447 error (" in thrown expression");
1448 throw_value_rtx = expand_expr (build_unary_op (ADDR_EXPR, exp, 0), NULL_RTX, VOIDmode, 0);
1449 emit_move_insn (saved_throw_value, throw_value_rtx);
1454 /* rethrow current exception */
1455 /* This part is easy, as we dont' have to do anything else. */
1458 emit_jump (throw_label);
1461 /* end of: my-cp-except.c */
1465 /* Output the exception table.
1466 Return the number of handlers. */
1468 build_exception_table ()
1472 extern FILE *asm_out_file;
1473 struct ehEntry *entry;
1479 while (entry = dequeue_eh_entry (&eh_table_output_queue))
1483 exception_section ();
1485 /* Beginning marker for table. */
1486 ASM_OUTPUT_ALIGN (asm_out_file, 2);
1487 ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_TABLE__");
1488 output_exception_table_entry (asm_out_file,
1489 const0_rtx, const0_rtx, const0_rtx);
1492 output_exception_table_entry (asm_out_file,
1493 entry->start_label, entry->end_label,
1494 entry->exception_handler_label);
1499 /* Ending marker for table. */
1500 ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_END__");
1501 output_exception_table_entry (asm_out_file,
1502 constm1_rtx, constm1_rtx, constm1_rtx);
1505 #endif /* TRY_NEW_EH */
1510 register_exception_table ()
1513 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
1515 gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
1517 #endif /* TRY_NEW_EH */
1520 /* Build a throw expression. */
1525 if (e != error_mark_node)
1527 e = build1 (THROW_EXPR, void_type_node, e);
1528 TREE_SIDE_EFFECTS (e) = 1;