1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 1992, 1993, 1994, 1995 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, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
25 /* High-level class interface. */
38 extern void (*interim_eh_hook) PROTO((tree));
39 rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
41 /* holds the fndecl for __builtin_return_address () */
42 tree builtin_return_address_fndecl;
49 if (! flag_handle_exceptions)
51 static int warned = 0;
52 if (! warned && do_warn)
54 error ("exception handling disabled, use -fhandle-exceptions to enable.");
64 NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
65 to supporting exception handling as per ANSI C++ working draft.
66 It is a complete rewrite of all the EH stuff that was here before
68 1. Throw specifications of functions still don't work.
70 1. Destructors are called properly :-)
71 2. No overhead for the non-exception thrown case.
72 3. Fixing shortcoming 1 is simple.
73 -Tad Hunt (tad@mail.csh.rit.edu)
77 /* A couple of backend routines from m88k.c */
79 /* used to cache a call to __builtin_return_address () */
80 static tree BuiltinReturnAddress;
85 /* XXX - Tad: for EH */
86 /* output an exception table entry */
89 output_exception_table_entry (file, start_label, end_label, eh_label)
91 rtx start_label, end_label, eh_label;
95 assemble_integer (start_label, GET_MODE_SIZE (Pmode), 1);
96 assemble_integer (end_label, GET_MODE_SIZE (Pmode), 1);
97 assemble_integer (eh_label, GET_MODE_SIZE (Pmode), 1);
98 putc ('\n', file); /* blank line */
102 easy_expand_asm (str)
105 expand_asm (build_string (strlen (str)+1, str));
110 /* This is the startup, and finish stuff per exception table. */
112 /* XXX - Tad: exception handling section */
113 #ifndef EXCEPT_SECTION_ASM_OP
114 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
117 #ifdef EXCEPT_SECTION_ASM_OP
121 void *exception_handler;
123 #endif /* EXCEPT_SECTION_ASM_OP */
125 #ifdef EXCEPT_SECTION_ASM_OP
127 /* on machines which support it, the exception table lives in another section,
128 but it needs a label so we can reference it... This sets up that
130 asm (EXCEPT_SECTION_ASM_OP);
131 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
132 asm (TEXT_SECTION_ASM_OP);
134 #endif /* EXCEPT_SECTION_ASM_OP */
136 #ifdef EXCEPT_SECTION_ASM_OP
138 /* we need to know where the end of the exception table is... so this
141 asm (EXCEPT_SECTION_ASM_OP);
142 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
143 asm (TEXT_SECTION_ASM_OP);
145 #endif /* EXCEPT_SECTION_ASM_OP */
152 #ifdef ASM_OUTPUT_SECTION_NAME
153 named_section (NULL_TREE, ".gcc_except_table");
158 #if defined (TARGET_POWERPC) /* are we on a __rs6000? */
161 readonly_data_section ();
169 /* from: my-cp-except.c */
171 /* VI: ":set ts=4" */
173 #include <stdio.h> */
183 #include "insn-flags.h"
189 /* ======================================================================
190 Briefly the algorithm works like this:
192 When a constructor or start of a try block is encountered,
193 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
194 new entry in the unwind protection stack and returns a label to
195 output to start the protection for that block.
197 When a destructor or end try block is encountered, pop_eh_entry
198 (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
199 created when push_eh_entry () was called. The ehEntry structure
200 contains three things at this point. The start protect label,
201 the end protect label, and the exception handler label. The end
202 protect label should be output before the call to the destructor
203 (if any). If it was a destructor, then its parse tree is stored
204 in the finalization variable in the ehEntry structure. Otherwise
205 the finalization variable is set to NULL to reflect the fact that
206 is the the end of a try block. Next, this modified ehEntry node
207 is enqueued in the finalizations queue by calling
208 enqueue_eh_entry (&queue,entry).
210 +---------------------------------------------------------------+
211 |XXX: Will need modification to deal with partially |
212 | constructed arrays of objects |
214 | Basically, this consists of keeping track of how many |
215 | of the objects have been constructed already (this |
216 | should be in a register though, so that shouldn't be a |
218 +---------------------------------------------------------------+
220 When a catch block is encountered, there is a lot of work to be
223 Since we don't want to generate the catch block inline with the
224 regular flow of the function, we need to have some way of doing
225 so. Luckily, we can use sequences to defer the catch sections.
226 When the start of a catch block is encountered, we start the
227 sequence. After the catch block is generated, we end the
230 Next we must insure that when the catch block is executed, all
231 finalizations for the matching try block have been completed. If
232 any of those finalizations throw an exception, we must call
233 terminate according to the ARM (section r.15.6.1). What this
234 means is that we need to dequeue and emit finalizations for each
235 entry in the ehQueue until we get to an entry with a NULL
236 finalization field. For any of the finalization entries, if it
237 is not a call to terminate (), we must protect it by giving it
238 another start label, end label, and exception handler label,
239 setting its finalization tree to be a call to terminate (), and
240 enqueue'ing this new ehEntry to be output at an outer level.
241 Finally, after all that is done, we can get around to outputting
242 the catch block which basically wraps all the "catch (...) {...}"
243 statements in a big if/then/else construct that matches the
244 correct block to call.
246 ===================================================================== */
248 extern rtx emit_insn PROTO((rtx));
249 extern rtx gen_nop PROTO(());
251 /* local globals for function calls
252 ====================================================================== */
254 /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
255 "set_unexpected ()" after default_conversion. (lib-except.c) */
256 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch, Throw;
258 /* used to cache __find_first_exception_table_match ()
259 for throw (lib-except.c) */
260 static tree FirstExceptionMatch;
262 /* used to cache a call to __unwind_function () (lib-except.c) */
265 /* holds a ready to emit call to "terminate ()". */
266 static tree TerminateFunctionCall;
268 static tree empty_fndecl;
270 /* ====================================================================== */
274 /* data structures for my various quick and dirty stacks and queues
275 Eventually, most of this should go away, because I think it can be
276 integrated with stuff already built into the compiler. */
278 /* =================================================================== */
285 struct labelNode *chain;
289 /* this is the most important structure here. Basically this is how I store
290 an exception table entry internally. */
294 rtx exception_handler_label;
301 struct ehEntry *entry;
302 struct ehNode *chain;
313 /* ========================================================================= */
317 /* local globals - these local globals are for storing data necessary for
318 generating the exception table and code in the correct order.
320 ========================================================================= */
322 /* Holds the pc for doing "throw" */
324 /* Holds the type of the thing being thrown. */
325 tree saved_throw_type;
326 /* Holds the value being thrown. */
327 tree saved_throw_value;
328 /* Holds the cleanup for the value being thrown. */
333 static rtx catch_clauses;
335 static struct ehStack ehstack;
336 static struct ehQueue ehqueue;
337 static struct ehQueue eh_table_output_queue;
338 static struct labelNode *false_label_stack = NULL;
339 static struct labelNode *caught_return_label_stack = NULL;
340 /* ========================================================================= */
342 /* function prototypes */
343 static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
344 static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
345 static rtx push_eh_entry PROTO((struct ehStack *stack));
346 static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
347 static void new_eh_queue PROTO((struct ehQueue *queue));
348 static void new_eh_stack PROTO((struct ehStack *stack));
349 static void push_label_entry PROTO((struct labelNode **labelstack, rtx rlabel, tree tlabel));
350 static rtx pop_label_entry PROTO((struct labelNode **labelstack));
351 static tree top_label_entry PROTO((struct labelNode **labelstack));
352 static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
355 /* Routines to save and restore eh context information. */
357 struct ehStack ehstack;
358 struct ehQueue ehqueue;
360 struct labelNode *false_label_stack;
361 struct labelNode *caught_return_label_stack;
365 /* Save the context and push into a new one. */
370 = (struct eh_context*)xmalloc (sizeof (struct eh_context));
372 p->ehstack = ehstack;
373 p->ehqueue = ehqueue;
374 p->catch_clauses = catch_clauses;
375 p->false_label_stack = false_label_stack;
376 p->caught_return_label_stack = caught_return_label_stack;
377 p->protect_list = protect_list;
379 new_eh_stack (&ehstack);
380 new_eh_queue (&ehqueue);
381 catch_clauses = NULL_RTX;
382 false_label_stack = NULL;
383 caught_return_label_stack = NULL;
384 protect_list = NULL_TREE;
389 /* Pop and restore the context. */
394 struct eh_context *p = (struct eh_context *)vp;
396 protect_list = p->protect_list;
397 caught_return_label_stack = p->caught_return_label_stack;
398 false_label_stack = p->false_label_stack;
399 catch_clauses = p->catch_clauses;
400 ehqueue = p->ehqueue;
401 ehstack = p->ehstack;
408 /* All my cheesy stack/queue/misc data structure handling routines
410 ========================================================================= */
413 push_label_entry (labelstack, rlabel, tlabel)
414 struct labelNode **labelstack;
418 struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
421 newnode->u.rlabel = rlabel;
423 newnode->u.tlabel = tlabel;
424 newnode->chain = *labelstack;
425 *labelstack = newnode;
429 pop_label_entry (labelstack)
430 struct labelNode **labelstack;
433 struct labelNode *tempnode;
435 if (! *labelstack) return NULL_RTX;
437 tempnode = *labelstack;
438 label = tempnode->u.rlabel;
439 *labelstack = (*labelstack)->chain;
446 top_label_entry (labelstack)
447 struct labelNode **labelstack;
449 if (! *labelstack) return NULL_TREE;
451 return (*labelstack)->u.tlabel;
454 /* Push to permanent obstack for rtl generation.
456 static struct obstack *saved_rtl_obstack;
460 extern struct obstack permanent_obstack;
461 extern struct obstack *rtl_obstack;
463 saved_rtl_obstack = rtl_obstack;
464 rtl_obstack = &permanent_obstack;
467 /* Pop back to normal rtl handling. */
471 extern struct obstack permanent_obstack;
472 extern struct obstack *rtl_obstack;
474 rtl_obstack = saved_rtl_obstack;
478 push_eh_entry (stack)
479 struct ehStack *stack;
481 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
482 struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
490 /* These are saved for the exception table. */
492 entry->start_label = gen_label_rtx ();
493 entry->end_label = gen_label_rtx ();
494 entry->exception_handler_label = gen_label_rtx ();
495 pop_rtl_from_perm ();
497 LABEL_PRESERVE_P (entry->start_label) = 1;
498 LABEL_PRESERVE_P (entry->end_label) = 1;
499 LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
501 entry->finalization = NULL_TREE;
502 entry->context = current_function_decl;
505 node->chain = stack->top;
508 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
510 return entry->start_label;
513 static struct ehEntry *
515 struct ehStack *stack;
517 struct ehNode *tempnode;
518 struct ehEntry *tempentry;
520 if (stack && (tempnode = stack->top)) {
521 tempentry = tempnode->entry;
522 stack->top = stack->top->chain;
531 static struct ehEntry *
532 copy_eh_entry (entry)
533 struct ehEntry *entry;
535 struct ehEntry *newentry;
537 newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
538 memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
544 enqueue_eh_entry (queue, entry)
545 struct ehQueue *queue;
546 struct ehEntry *entry;
548 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
553 if (queue->head == NULL)
559 queue->tail->chain = node;
564 static struct ehEntry *
565 dequeue_eh_entry (queue)
566 struct ehQueue *queue;
568 struct ehNode *tempnode;
569 struct ehEntry *tempentry;
571 if (queue->head == NULL)
574 tempnode = queue->head;
575 queue->head = queue->head->chain;
577 tempentry = tempnode->entry;
585 struct ehQueue *queue;
587 queue->head = queue->tail = NULL;
592 struct ehStack *stack;
597 /* cheesyness to save some typing. returns the return value rtx */
599 do_function_call (func, params, return_type)
600 tree func, params, return_type;
603 func_call = build_function_call (func, params);
604 expand_call (func_call, NULL_RTX, 0);
605 if (return_type != NULL_TREE)
606 return hard_function_value (return_type, func_call);
611 expand_internal_throw (pc)
616 emit_move_insn (DECL_RTL (saved_pc), pc);
618 emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw"));
620 do_function_call (Throw, NULL_TREE, NULL_TREE);
625 /* ========================================================================= */
628 lang_interim_eh (finalization)
632 end_protect (finalization);
637 extern tree auto_function PROTO((tree, tree, enum built_in_function));
639 /* sets up all the global eh stuff that needs to be initialized at the
640 start of compilation.
643 - Setting up all the function call trees
644 - Initializing the ehqueue
645 - Initializing the eh_table_output_queue
646 - Initializing the ehstack
650 init_exception_processing ()
652 extern tree define_function ();
653 tree unexpected_fndecl, terminate_fndecl;
654 tree set_unexpected_fndecl, set_terminate_fndecl;
655 tree catch_match_fndecl;
656 tree find_first_exception_match_fndecl;
662 tree PFV = build_pointer_type (build_function_type
663 (void_type_node, void_list_node));
665 /* arg list for the build_function_type call for set_terminate () and
667 tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
669 /* void (*pfvtype (void (*) ()))() */
670 tree pfvtype = build_function_type (PFV, pfvlist);
673 tree vtype = build_function_type (void_type_node, void_list_node);
675 set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
676 pfvtype, NOT_BUILT_IN);
677 set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
678 pfvtype, NOT_BUILT_IN);
679 unexpected_fndecl = auto_function (get_identifier ("unexpected"),
680 vtype, NOT_BUILT_IN);
681 terminate_fndecl = auto_function (get_identifier ("terminate"),
682 vtype, NOT_BUILT_IN);
684 interim_eh_hook = lang_interim_eh;
686 push_lang_context (lang_name_c);
689 builtin_function (flag_rtti
690 ? "__throw_type_match_rtti"
691 : "__throw_type_match",
692 build_function_type (ptr_type_node,
693 tree_cons (NULL_TREE, ptr_type_node,
694 tree_cons (NULL_TREE, ptr_type_node,
695 tree_cons (NULL_TREE, ptr_type_node,
697 NOT_BUILT_IN, NULL_PTR);
698 find_first_exception_match_fndecl =
699 builtin_function ("__find_first_exception_table_match",
700 build_function_type (ptr_type_node,
701 tree_cons (NULL_TREE, ptr_type_node,
703 NOT_BUILT_IN, NULL_PTR);
705 builtin_function ("__unwind_function",
706 build_function_type (void_type_node,
707 tree_cons (NULL_TREE, ptr_type_node,
709 NOT_BUILT_IN, NULL_PTR);
711 builtin_function ("__throw",
712 build_function_type (void_type_node, void_list_node),
713 NOT_BUILT_IN, NULL_PTR);
714 DECL_EXTERNAL (throw_fndecl) = 0;
715 TREE_PUBLIC (throw_fndecl) = 0;
717 builtin_function ("__empty",
718 build_function_type (void_type_node, void_list_node),
719 NOT_BUILT_IN, NULL_PTR);
720 DECL_EXTERNAL (empty_fndecl) = 1;
721 TREE_PUBLIC (empty_fndecl) = 1;
723 Unexpected = default_conversion (unexpected_fndecl);
724 Terminate = default_conversion (terminate_fndecl);
725 SetTerminate = default_conversion (set_terminate_fndecl);
726 SetUnexpected = default_conversion (set_unexpected_fndecl);
727 CatchMatch = default_conversion (catch_match_fndecl);
728 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
729 Unwind = default_conversion (unwind_fndecl);
730 Throw = default_conversion (throw_fndecl);
731 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
733 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
737 new_eh_queue (&ehqueue);
738 new_eh_queue (&eh_table_output_queue);
739 new_eh_stack (&ehstack);
741 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
742 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
743 d = start_decl (d, declspecs, 0, NULL_TREE);
745 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
746 saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
748 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
749 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
750 d = start_decl (d, declspecs, 0, NULL_TREE);
752 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
753 saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
755 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
756 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
757 d = start_decl (d, declspecs, 0, NULL_TREE);
759 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
760 saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
762 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
763 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
764 d = build_parse_node (CALL_EXPR, d, void_list_node, NULL_TREE);
765 d = start_decl (d, declspecs, 0, NULL_TREE);
767 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
768 saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
771 /* call this to begin a block of unwind protection (ie: when an object is
779 emit_label (push_eh_entry (&ehstack));
782 /* call this to end a block of unwind protection. the finalization tree is
783 the finalization which needs to be run in order to cleanly unwind through
784 this level of protection. (ie: call this when a scope is exited)*/
786 end_protect (finalization)
789 struct ehEntry *entry;
794 entry = pop_eh_entry (&ehstack);
796 emit_label (entry->end_label);
797 /* Put in something that takes up space, as otherwise the end
798 address for the EH region could have the exact same address as
799 the outer region, causing us to miss the fact that resuming
800 exception handling with this PC value would be inside the outer
802 emit_insn (gen_nop ());
804 entry->finalization = finalization;
806 enqueue_eh_entry (&ehqueue, entry);
809 /* call this on start of a try block. */
811 expand_start_try_stmts ()
820 expand_end_try_stmts ()
822 end_protect (integer_zero_node);
826 /* call this to start processing of all the catch blocks. */
828 expand_start_all_catch ()
830 struct ehEntry *entry;
836 emit_line_note (input_filename, lineno);
837 label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
839 /* The label for the exception handling block we will save. This is
840 Lresume, in the documention. */
841 expand_label (label);
843 /* Put in something that takes up space, as otherwise the end
844 address for the EH region could have the exact same address as
845 the outer region, causing us to miss the fact that resuming
846 exception handling with this PC value would be inside the outer
848 emit_insn (gen_nop ());
850 push_label_entry (&caught_return_label_stack, NULL_RTX, label);
852 /* Start a new sequence for all the catch blocks. We will add this
853 to the gloabl sequence catch_clauses, when we have completed all
854 the handlers in this handler-seq. */
859 entry = dequeue_eh_entry (&ehqueue);
860 emit_label (entry->exception_handler_label);
862 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
864 /* When we get down to the matching entry, stop. */
865 if (entry->finalization == integer_zero_node)
868 /* The below can be optimized away, and we could just fall into the
869 next EH handler, if we are certain they are nested. */
870 /* Code to throw out to outer context, if we fall off end of the
872 expand_internal_throw (gen_rtx (LABEL_REF,
879 /* call this to end processing of all the catch blocks. */
881 expand_end_all_catch ()
883 rtx new_catch_clause;
888 /* Code to throw out to outer context, if we fall off end of catch
889 handlers. This is rethrow (Lresume, same id, same obj); in the
891 expand_internal_throw (gen_rtx (LABEL_REF,
893 DECL_RTL (top_label_entry (&caught_return_label_stack))));
895 /* Now we have the complete catch sequence. */
896 new_catch_clause = get_insns ();
899 /* this level of catch blocks is done, so set up the successful catch jump
900 label for the next layer of catch blocks. */
901 pop_label_entry (&caught_return_label_stack);
903 /* Add the new sequence of catchs to the main one for this
905 push_to_sequence (catch_clauses);
906 emit_insns (new_catch_clause);
907 catch_clauses = get_insns ();
910 /* Here we fall through into the continuation code. */
913 /* Build a type value for use at runtime for a type that is matched
914 against by the exception handling system. */
916 build_eh_type_type (type)
922 if (type == error_mark_node)
923 return error_mark_node;
925 /* peel back references, so they match. */
926 if (TREE_CODE (type) == REFERENCE_TYPE)
927 type = TREE_TYPE (type);
929 /* Peel off cv qualifiers. */
930 type = TYPE_MAIN_VARIANT (type);
934 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
937 typestring = build_overload_name (type, 1, 1);
938 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
939 return build1 (ADDR_EXPR, ptr_type_node, exp);
942 /* Build a type value for use at runtime for a exp that is thrown or
943 matched against by the exception handling system. */
950 exp = build_typeid (exp);
951 return build1 (ADDR_EXPR, ptr_type_node, exp);
953 return build_eh_type_type (TREE_TYPE (exp));
956 /* This routine creates the cleanup for the exception handling object. */
960 /* All cleanups must last longer than normal. */
961 int yes = suspend_momentary ();
963 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
964 tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
965 cp_expand_decl_cleanup (NULL_TREE, cleanup);
967 resume_momentary (yes);
971 /* call this to start a catch block. Typename is the typename, and identifier
972 is the variable to place the object in or NULL if the variable doesn't
973 matter. If typename is NULL, that means its a "catch (...)" or catch
974 everything. In that case we don't need to do any type checking.
975 (ie: it ends up as the "else" clause rather than an "else if" clause) */
977 expand_start_catch_block (declspecs, declarator)
978 tree declspecs, declarator;
981 rtx protect_label_rtx;
982 tree decl = NULL_TREE;
989 /* Create a binding level for the parm. */
990 expand_start_bindings (0);
992 false_label_rtx = gen_label_rtx ();
993 /* This is saved for the exception table. */
995 protect_label_rtx = gen_label_rtx ();
996 pop_rtl_from_perm ();
997 push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
998 push_label_entry (&false_label_stack, protect_label_rtx, NULL_TREE);
1003 rtx call_rtx, return_value_rtx;
1006 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1,
1007 NULL_TREE, NULL_TREE);
1009 if (decl == NULL_TREE)
1011 error ("invalid catch parameter");
1015 /* Make sure we mark the catch param as used, otherwise we'll get
1016 a warning about an unused ((anonymous)). */
1017 TREE_USED (decl) = 1;
1019 /* Figure out the type that the initializer is. */
1020 init_type = TREE_TYPE (decl);
1021 if (TREE_CODE (init_type) != REFERENCE_TYPE
1022 && TREE_CODE (init_type) != POINTER_TYPE)
1023 init_type = build_reference_type (init_type);
1025 exp = saved_throw_value;
1026 exp = tree_cons (NULL_TREE,
1027 build_eh_type_type (TREE_TYPE (decl)),
1028 tree_cons (NULL_TREE,
1030 tree_cons (NULL_TREE, exp, NULL_TREE)));
1031 exp = build_function_call (CatchMatch, exp);
1032 call_rtx = expand_call (exp, NULL_RTX, 0);
1033 assemble_external (TREE_OPERAND (CatchMatch, 0));
1035 return_value_rtx = hard_function_value (ptr_type_node, exp);
1037 /* did the throw type match function return TRUE? */
1038 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
1039 GET_MODE (return_value_rtx), 0, 0);
1041 /* if it returned FALSE, jump over the catch block, else fall into it */
1042 emit_jump_insn (gen_beq (false_label_rtx));
1046 init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
1048 /* Do we need the below two lines? */
1049 /* Let `cp_finish_decl' know that this initializer is ok. */
1050 DECL_INITIAL (decl) = init;
1051 decl = pushdecl (decl);
1052 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1058 /* Fall into the catch all section. */
1061 /* This is the starting of something to protect. */
1062 emit_label (protect_label_rtx);
1064 emit_line_note (input_filename, lineno);
1068 /* this is called from expand_exception_blocks and
1069 expand_end_catch_block to expand the toplevel finalizations for a
1070 function. We return the first label emitted, if any, otherwise
1073 expand_leftover_cleanups ()
1075 struct ehEntry *entry;
1076 rtx first_label = NULL_RTX;
1078 while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
1081 first_label = entry->exception_handler_label;
1082 emit_label (entry->exception_handler_label);
1084 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1086 /* The below can be optimized away, and we could just fall into the
1087 next EH handler, if we are certain they are nested. */
1088 /* Code to throw out to outer context, if we fall off end of the
1090 expand_internal_throw (gen_rtx (LABEL_REF,
1094 /* leftover try block, opps. */
1095 if (entry->finalization == integer_zero_node)
1104 /* Call this to end a catch block. Its responsible for emitting the
1105 code to handle jumping back to the correct place, and for emitting
1106 the label to jump to if this catch block didn't match. */
1107 void expand_end_catch_block ()
1109 rtx start_protect_label_rtx;
1110 rtx end_protect_label_rtx;
1112 struct ehEntry entry;
1117 /* fall to outside the try statement when done executing handler and
1118 we fall off end of handler. This is jump Lresume in the
1120 expand_goto (top_label_entry (&caught_return_label_stack));
1122 /* We end the rethrow protection region as soon as we hit a label. */
1123 end_protect_label_rtx = expand_leftover_cleanups ();
1125 /* Code to throw out to outer context, if we get a throw from within
1126 our catch handler. */
1127 /* These are saved for the exception table. */
1129 entry.exception_handler_label = gen_label_rtx ();
1130 pop_rtl_from_perm ();
1131 /* This label is Lhandler in the documentation. */
1132 emit_label (entry.exception_handler_label);
1133 expand_internal_throw (gen_rtx (LABEL_REF,
1135 DECL_RTL (top_label_entry (&caught_return_label_stack))));
1137 /* No associated finalization. */
1138 entry.finalization = NULL_TREE;
1139 entry.context = current_function_decl;
1141 if (end_protect_label_rtx == NULL_RTX)
1142 end_protect_label_rtx = entry.exception_handler_label;
1144 /* Because we are emitted out of line, we have to protect this. */
1145 /* label for the start of the protection region. */
1146 start_protect_label_rtx = pop_label_entry (&false_label_stack);
1148 /* Cleanup the EH parameter. */
1149 decls = getdecls ();
1150 expand_end_bindings (decls, decls != NULL_TREE, 0);
1152 /* label we emit to jump to if this catch block didn't match. */
1153 /* This the closing } in the `if (eq) {' of the documentation. */
1154 emit_label (pop_label_entry (&false_label_stack));
1156 /* Because we are reordered out of line, we have to protect this. */
1157 entry.start_label = start_protect_label_rtx;
1158 entry.end_label = end_protect_label_rtx;
1160 LABEL_PRESERVE_P (entry.start_label) = 1;
1161 LABEL_PRESERVE_P (entry.end_label) = 1;
1162 LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1164 /* These set up a call to throw the caught exception into the outer
1166 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1169 /* unwind the stack. */
1171 do_unwind (inner_throw_label)
1172 rtx inner_throw_label;
1174 #if defined (SPARC_STACK_ALIGN) /* was sparc */
1175 /* This doesn't work for the flat model sparc, I bet. */
1181 /* call to __builtin_return_address () */
1182 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1183 fcall = build_function_call (BuiltinReturnAddress, params);
1184 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1185 /* In the return, the new pc is pc+8, as the value coming in is
1186 really the address of the call insn, not the next insn. */
1187 temp = gen_reg_rtx (Pmode);
1188 emit_move_insn (temp, inner_throw_label);
1189 emit_move_insn (return_val_rtx, plus_constant (temp, -8));
1190 easy_expand_asm ("ret");
1191 easy_expand_asm ("restore");
1194 #if defined (ARM_FRAME_RTX) /* was __arm */
1195 if (flag_omit_frame_pointer)
1196 sorry ("this implementation of exception handling requires a frame pointer");
1198 emit_move_insn (stack_pointer_rtx,
1199 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
1200 emit_move_insn (hard_frame_pointer_rtx,
1201 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
1203 #if defined (TARGET_88000) /* was m88k */
1204 rtx temp_frame = frame_pointer_rtx;
1206 temp_frame = memory_address (Pmode, temp_frame);
1207 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
1209 /* hopefully this will successfully pop the frame! */
1210 emit_move_insn (frame_pointer_rtx, temp_frame);
1211 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
1212 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
1213 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1214 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
1217 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1218 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1220 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
1222 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1223 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1226 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
1232 /* I would like to do this here, but the move below doesn't seem to work. */
1233 /* call to __builtin_return_address () */
1234 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1235 fcall = build_function_call (BuiltinReturnAddress, params);
1236 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1238 emit_move_insn (return_val_rtx, inner_throw_label);
1239 /* So, for now, just pass throw label to stack unwinder. */
1241 params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
1242 inner_throw_label), NULL_TREE);
1244 do_function_call (Unwind, params, NULL_TREE);
1245 assemble_external (TREE_OPERAND (Unwind, 0));
1251 /* Given the return address, compute the new pc to throw. This has to
1252 work for the current frame of the current function, and the one
1253 above it in the case of throw. */
1255 eh_outer_context (addr)
1258 #if defined (ARM_FRAME_RTX) /* was __arm */
1259 /* On the ARM, '__builtin_return_address', must have 4
1260 subtracted from it. */
1261 emit_insn (gen_add2_insn (addr, GEN_INT (-4)));
1263 /* If we are generating code for an ARM2/ARM3 machine or for an ARM6
1264 in 26 bit mode, the condition codes must be masked out of the
1265 return value, or else they will confuse BuiltinReturnAddress.
1266 This does not apply to ARM6 and later processors when running in
1269 emit_insn (gen_rtx (SET, Pmode,
1271 gen_rtx (AND, Pmode,
1272 addr, GEN_INT (0x03fffffc))));
1274 #if ! defined (SPARC_STACK_ALIGN) /* was sparc */
1275 #if defined (TARGET_SNAKE)
1276 /* On HPPA, the low order two bits hold the priviledge level, so we
1277 must get rid of them. */
1278 emit_insn (gen_rtx (SET, Pmode,
1280 gen_rtx (AND, Pmode,
1281 addr, GEN_INT (0xfffffffc))));
1284 /* On the SPARC, __builtin_return_address is already -8 or -12, no
1285 need to subtract any more from it. */
1286 addr = plus_constant (addr, -1);
1293 /* is called from expand_exception_blocks () to generate the code in a function
1294 to "throw" if anything in the function needs to perform a throw.
1296 expands "throw" as the following pseudo code:
1299 eh = find_first_exception_match (saved_pc);
1300 if (!eh) goto gotta_rethrow_it;
1304 saved_pc = __builtin_return_address (0);
1305 pop_to_previous_level ();
1310 expand_builtin_throw ()
1315 rtx gotta_rethrow_it;
1316 rtx gotta_call_terminate;
1317 rtx unwind_and_throw;
1318 rtx goto_unwind_and_throw;
1329 params = void_list_node;
1330 t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE);
1331 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1333 t, NULL_TREE, NULL_TREE, 0);
1334 store_parm_decls ();
1338 expand_start_bindings (0);
1340 gotta_rethrow_it = gen_label_rtx ();
1341 gotta_call_terminate = gen_label_rtx ();
1342 unwind_and_throw = gen_label_rtx ();
1343 goto_unwind_and_throw = gen_label_rtx ();
1344 top_of_loop = gen_label_rtx ();
1345 unwind_first = gen_label_rtx ();
1347 emit_jump (unwind_first);
1349 emit_label (top_of_loop);
1351 /* search for an exception handler for the saved_pc */
1352 return_val_rtx = do_function_call (FirstExceptionMatch,
1353 tree_cons (NULL_TREE, saved_pc, NULL_TREE),
1355 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
1357 /* did we find one? */
1358 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1359 GET_MODE (return_val_rtx), 0, 0);
1361 /* if not, jump to gotta_rethrow_it */
1362 emit_jump_insn (gen_beq (gotta_rethrow_it));
1364 /* we found it, so jump to it */
1365 emit_indirect_jump (return_val_rtx);
1367 /* code to deal with unwinding and looking for it again */
1368 emit_label (gotta_rethrow_it);
1370 /* call to __builtin_return_address () */
1371 #if defined (ARM_FRAME_RTX) /* was __arm */
1372 /* This should be moved into arm.h:RETURN_ADDR_RTX */
1373 /* This replaces a 'call' to __builtin_return_address */
1374 return_val_rtx = gen_reg_rtx (Pmode);
1375 emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
1377 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1378 fcall = build_function_call (BuiltinReturnAddress, params);
1379 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1382 /* did __builtin_return_address () return a valid address? */
1383 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1384 GET_MODE (return_val_rtx), 0, 0);
1386 emit_jump_insn (gen_beq (gotta_call_terminate));
1388 return_val_rtx = eh_outer_context (return_val_rtx);
1391 emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1393 do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
1394 emit_jump (top_of_loop);
1396 /* no it didn't --> therefore we need to call terminate */
1397 emit_label (gotta_call_terminate);
1398 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1399 assemble_external (TREE_OPERAND (Terminate, 0));
1402 rtx ret_val, return_val_rtx;
1403 emit_label (unwind_first);
1404 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1405 0, hard_frame_pointer_rtx);
1407 /* Set it up so that we continue inside, at the top of the loop. */
1408 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
1409 #ifdef RETURN_ADDR_OFFSET
1410 return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1411 if (return_val_rtx != ret_val)
1412 emit_move_insn (ret_val, return_val_rtx);
1415 /* Fall into epilogue to unwind prologue. */
1418 expand_end_bindings (getdecls(), 1, 0);
1422 finish_function (lineno, 0, 0);
1427 expand_start_eh_spec ()
1433 expand_end_eh_spec (raises)
1436 tree expr, second_try;
1437 rtx check = gen_label_rtx ();
1439 rtx ret = gen_reg_rtx (Pmode);
1440 rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
1441 rtx end = gen_label_rtx ();
1443 expr = make_node (RTL_EXPR);
1444 TREE_TYPE (expr) = void_type_node;
1445 RTL_EXPR_RTL (expr) = const0_rtx;
1446 TREE_SIDE_EFFECTS (expr) = 1;
1447 start_sequence_for_rtl_expr (expr);
1448 cont = gen_label_rtx ();
1449 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1452 jumpif (make_tree (integer_type_node, flag), end);
1453 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1454 assemble_external (TREE_OPERAND (Terminate, 0));
1456 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1461 expr = make_node (RTL_EXPR);
1462 TREE_TYPE (expr) = void_type_node;
1463 RTL_EXPR_RTL (expr) = const0_rtx;
1464 TREE_SIDE_EFFECTS (expr) = 1;
1465 start_sequence_for_rtl_expr (expr);
1467 cont = gen_label_rtx ();
1468 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1471 jumpif (make_tree (integer_type_node, flag), end);
1473 do_function_call (Unexpected, NULL_TREE, NULL_TREE);
1474 assemble_external (TREE_OPERAND (Unexpected, 0));
1476 end_protect (second_try);
1479 emit_move_insn (flag, const1_rtx);
1480 cont = gen_label_rtx ();
1484 tree match_type = TREE_VALUE (raises);
1488 /* check TREE_VALUE (raises) here */
1489 exp = saved_throw_value;
1490 exp = tree_cons (NULL_TREE,
1491 build_eh_type_type (match_type),
1492 tree_cons (NULL_TREE,
1494 tree_cons (NULL_TREE, exp, NULL_TREE)));
1495 exp = build_function_call (CatchMatch, exp);
1496 assemble_external (TREE_OPERAND (CatchMatch, 0));
1501 raises = TREE_CHAIN (raises);
1503 emit_move_insn (flag, const0_rtx);
1505 emit_indirect_jump (ret);
1508 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1514 /* This is called to expand all the toplevel exception handling
1515 finalization for a function. It should only be called once per
1518 expand_exception_blocks ()
1525 funcend = gen_label_rtx ();
1526 emit_jump (funcend);
1527 /* expand_null_return (); */
1531 /* Add all the catch clauses here. */
1532 emit_insns (catch_clauses);
1533 catch_clauses = NULL_RTX;
1535 expand_leftover_cleanups ();
1537 insns = get_insns ();
1540 /* Do this after we expand leftover cleanups, so that the end_protect
1541 that expand_end_eh_spec does will match the right start_protect,
1542 and make sure it comes out before the terminate protected region. */
1543 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1545 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1546 push_to_sequence (insns);
1548 /* Now expand any new ones. */
1549 expand_leftover_cleanups ();
1551 insns = get_insns ();
1557 struct ehEntry entry;
1559 /* These are saved for the exception table. */
1561 entry.start_label = gen_label_rtx ();
1562 entry.end_label = gen_label_rtx ();
1563 entry.exception_handler_label = gen_label_rtx ();
1564 entry.finalization = TerminateFunctionCall;
1565 entry.context = current_function_decl;
1566 assemble_external (TREE_OPERAND (Terminate, 0));
1567 pop_rtl_from_perm ();
1569 LABEL_PRESERVE_P (entry.start_label) = 1;
1570 LABEL_PRESERVE_P (entry.end_label) = 1;
1571 LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1573 emit_label (entry.start_label);
1576 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1578 emit_label (entry.exception_handler_label);
1579 expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
1580 emit_label (entry.end_label);
1585 /* Mark the end of the stack unwinder. */
1588 end_eh_unwinder (funcend);
1589 expand_leftover_cleanups ();
1590 unwind_insns = get_insns ();
1594 insns = unwind_insns;
1599 emit_label (funcend);
1601 /* Only if we had previous insns do we want to emit the jump around
1602 them. If there weren't any, then insns will remain NULL_RTX. */
1604 insns = get_insns ();
1613 static int counter = 0;
1618 push_cp_function_context (NULL_TREE);
1619 push_to_top_level ();
1621 /* No need to mangle this. */
1622 push_lang_context (lang_name_c);
1624 params = void_list_node;
1625 /* tcf stands for throw clean funciton. */
1626 sprintf (name, "__tcf_%d", counter++);
1627 t = build_parse_node (CALL_EXPR, get_identifier (name), params, NULL_TREE);
1628 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1630 t, NULL_TREE, NULL_TREE, 0);
1631 store_parm_decls ();
1635 expand_start_bindings (0);
1636 emit_line_note (input_filename, lineno);
1638 pop_lang_context ();
1640 return current_function_decl;
1646 expand_end_bindings (getdecls(), 1, 0);
1650 finish_function (lineno, 0, 0);
1652 pop_from_top_level ();
1653 pop_cp_function_context (NULL_TREE);
1656 /* call this to expand a throw statement. This follows the following
1659 1. Allocate space to save the current PC onto the stack.
1660 2. Generate and emit a label and save its address into the
1661 newly allocated stack space since we can't save the pc directly.
1662 3. If this is the first call to throw in this function:
1663 generate a label for the throw block
1664 4. jump to the throw block label. */
1674 /* This is the label that represents where in the code we were, when
1675 we got an exception. This needs to be updated when we rethrow an
1676 exception, so that the matching routine knows to search out. */
1677 label = gen_label_rtx ();
1683 tree cleanup = empty_fndecl, e;
1685 /* throw expression */
1686 /* First, decay it. */
1687 exp = decay_conversion (exp);
1689 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1691 throw_type = build_eh_type (exp);
1692 exp = build_reinterpret_cast (ptr_type_node, exp);
1698 /* Make a copy of the thrown object. WP 15.1.5 */
1699 exp = build_new (NULL_TREE, TREE_TYPE (exp),
1700 build_tree_list (NULL_TREE, exp),
1703 if (exp == error_mark_node)
1704 error (" in thrown expression");
1706 object = build_indirect_ref (exp, NULL_PTR);
1707 throw_type = build_eh_type (object);
1710 object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
1711 object = build_indirect_ref (object, NULL_PTR);
1712 cleanup = maybe_build_cleanup (object);
1714 expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1715 cleanup_insns = get_insns ();
1718 if (cleanup && cleanup_insns)
1720 cleanup = start_anon_func ();
1722 expand_expr (maybe_build_cleanup (object), const0_rtx, VOIDmode, 0);
1726 mark_addressable (cleanup);
1730 cleanup = empty_fndecl;
1734 if (cleanup == empty_fndecl)
1735 assemble_external (empty_fndecl);
1737 e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
1738 expand_expr (e, const0_rtx, VOIDmode, 0);
1740 e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
1741 e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
1742 expand_expr (e, const0_rtx, VOIDmode, 0);
1744 cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
1745 cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
1746 expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1750 /* rethrow current exception */
1751 /* This part is easy, as we don't have to do anything else. */
1754 expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label));
1758 end_protect_partials () {
1759 while (protect_list)
1761 end_protect (TREE_VALUE (protect_list));
1762 protect_list = TREE_CHAIN (protect_list);
1767 might_have_exceptions_p ()
1769 if (eh_table_output_queue.head)
1774 /* Output the exception table.
1775 Return the number of handlers. */
1777 emit_exception_table ()
1780 extern FILE *asm_out_file;
1781 struct ehEntry *entry;
1787 exception_section ();
1789 /* Beginning marker for table. */
1790 assemble_align (GET_MODE_ALIGNMENT (Pmode));
1791 assemble_label ("__EXCEPTION_TABLE__");
1792 output_exception_table_entry (asm_out_file,
1793 const0_rtx, const0_rtx, const0_rtx);
1795 while (entry = dequeue_eh_entry (&eh_table_output_queue))
1797 tree context = entry->context;
1799 if (context && ! TREE_ASM_WRITTEN (context))
1803 output_exception_table_entry (asm_out_file,
1804 entry->start_label, entry->end_label,
1805 entry->exception_handler_label);
1808 /* Ending marker for table. */
1809 assemble_label ("__EXCEPTION_END__");
1810 output_exception_table_entry (asm_out_file,
1811 constm1_rtx, constm1_rtx, constm1_rtx);
1815 register_exception_table ()
1817 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
1819 gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
1823 /* Build a throw expression. */
1828 if (e != error_mark_node)
1830 e = build1 (THROW_EXPR, void_type_node, e);
1831 TREE_SIDE_EFFECTS (e) = 1;
1837 start_eh_unwinder ()
1842 end_eh_unwinder (end)
1846 rtx return_val_rtx, ret_val, label;
1851 expr = make_node (RTL_EXPR);
1852 TREE_TYPE (expr) = void_type_node;
1853 RTL_EXPR_RTL (expr) = const0_rtx;
1854 TREE_SIDE_EFFECTS (expr) = 1;
1855 start_sequence_for_rtl_expr (expr);
1857 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1858 0, hard_frame_pointer_rtx);
1859 return_val_rtx = copy_to_reg (ret_val);
1861 return_val_rtx = eh_outer_context (return_val_rtx);
1863 emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1865 #ifdef JUMP_TO_THROW
1866 emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw"));
1868 label = gen_label_rtx ();
1869 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
1872 #ifdef RETURN_ADDR_OFFSET
1873 return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1874 if (return_val_rtx != ret_val)
1875 emit_move_insn (ret_val, return_val_rtx);
1880 #ifndef JUMP_TO_THROW
1882 do_function_call (Throw, NULL_TREE, NULL_TREE);
1885 RTL_EXPR_SEQUENCE (expr) = get_insns ();