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));
40 static void end_eh_unwinder PROTO((rtx));
42 /* holds the fndecl for __builtin_return_address () */
43 tree builtin_return_address_fndecl;
50 if (! flag_handle_exceptions)
52 static int warned = 0;
53 if (! warned && do_warn)
55 error ("exception handling disabled, use -fhandle-exceptions to enable.");
65 NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
66 to supporting exception handling as per ANSI C++ working draft.
67 It is a complete rewrite of all the EH stuff that was here before
69 1. Throw specifications of functions still don't work.
71 1. Destructors are called properly :-)
72 2. No overhead for the non-exception thrown case.
73 3. Fixing shortcoming 1 is simple.
74 -Tad Hunt (tad@mail.csh.rit.edu)
78 /* A couple of backend routines from m88k.c */
80 /* used to cache a call to __builtin_return_address () */
81 static tree BuiltinReturnAddress;
86 /* XXX - Tad: for EH */
87 /* output an exception table entry */
90 output_exception_table_entry (file, start_label, end_label, eh_label)
92 rtx start_label, end_label, eh_label;
94 assemble_integer (start_label, GET_MODE_SIZE (Pmode), 1);
95 assemble_integer (end_label, GET_MODE_SIZE (Pmode), 1);
96 assemble_integer (eh_label, GET_MODE_SIZE (Pmode), 1);
97 putc ('\n', file); /* blank line */
101 easy_expand_asm (str)
104 expand_asm (build_string (strlen (str)+1, str));
109 /* This is the startup, and finish stuff per exception table. */
111 /* XXX - Tad: exception handling section */
112 #ifndef EXCEPT_SECTION_ASM_OP
113 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
116 #ifdef EXCEPT_SECTION_ASM_OP
120 void *exception_handler;
122 #endif /* EXCEPT_SECTION_ASM_OP */
124 #ifdef EXCEPT_SECTION_ASM_OP
126 /* on machines which support it, the exception table lives in another section,
127 but it needs a label so we can reference it... This sets up that
129 asm (EXCEPT_SECTION_ASM_OP);
130 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
131 asm (TEXT_SECTION_ASM_OP);
133 #endif /* EXCEPT_SECTION_ASM_OP */
135 #ifdef EXCEPT_SECTION_ASM_OP
137 /* we need to know where the end of the exception table is... so this
140 asm (EXCEPT_SECTION_ASM_OP);
141 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
142 asm (TEXT_SECTION_ASM_OP);
144 #endif /* EXCEPT_SECTION_ASM_OP */
151 #ifdef ASM_OUTPUT_SECTION_NAME
152 named_section (NULL_TREE, ".gcc_except_table");
157 #if defined (TARGET_POWERPC) /* are we on a __rs6000? */
160 readonly_data_section ();
168 /* from: my-cp-except.c */
170 /* VI: ":set ts=4" */
172 #include <stdio.h> */
182 #include "insn-flags.h"
188 /* ======================================================================
189 Briefly the algorithm works like this:
191 When a constructor or start of a try block is encountered,
192 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
193 new entry in the unwind protection stack and returns a label to
194 output to start the protection for that block.
196 When a destructor or end try block is encountered, pop_eh_entry
197 (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
198 created when push_eh_entry () was called. The ehEntry structure
199 contains three things at this point. The start protect label,
200 the end protect label, and the exception handler label. The end
201 protect label should be output before the call to the destructor
202 (if any). If it was a destructor, then its parse tree is stored
203 in the finalization variable in the ehEntry structure. Otherwise
204 the finalization variable is set to NULL to reflect the fact that
205 is the the end of a try block. Next, this modified ehEntry node
206 is enqueued in the finalizations queue by calling
207 enqueue_eh_entry (&queue,entry).
209 +---------------------------------------------------------------+
210 |XXX: Will need modification to deal with partially |
211 | constructed arrays of objects |
213 | Basically, this consists of keeping track of how many |
214 | of the objects have been constructed already (this |
215 | should be in a register though, so that shouldn't be a |
217 +---------------------------------------------------------------+
219 When a catch block is encountered, there is a lot of work to be
222 Since we don't want to generate the catch block inline with the
223 regular flow of the function, we need to have some way of doing
224 so. Luckily, we can use sequences to defer the catch sections.
225 When the start of a catch block is encountered, we start the
226 sequence. After the catch block is generated, we end the
229 Next we must insure that when the catch block is executed, all
230 finalizations for the matching try block have been completed. If
231 any of those finalizations throw an exception, we must call
232 terminate according to the ARM (section r.15.6.1). What this
233 means is that we need to dequeue and emit finalizations for each
234 entry in the ehQueue until we get to an entry with a NULL
235 finalization field. For any of the finalization entries, if it
236 is not a call to terminate (), we must protect it by giving it
237 another start label, end label, and exception handler label,
238 setting its finalization tree to be a call to terminate (), and
239 enqueue'ing this new ehEntry to be output at an outer level.
240 Finally, after all that is done, we can get around to outputting
241 the catch block which basically wraps all the "catch (...) {...}"
242 statements in a big if/then/else construct that matches the
243 correct block to call.
245 ===================================================================== */
247 extern rtx emit_insn PROTO((rtx));
248 extern rtx gen_nop PROTO(());
250 /* local globals for function calls
251 ====================================================================== */
253 /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
254 "set_unexpected ()" after default_conversion. (lib-except.c) */
255 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch, Throw;
257 /* used to cache __find_first_exception_table_match ()
258 for throw (lib-except.c) */
259 static tree FirstExceptionMatch;
261 /* used to cache a call to __unwind_function () (lib-except.c) */
264 /* holds a ready to emit call to "terminate ()". */
265 static tree TerminateFunctionCall;
267 static tree empty_fndecl;
269 /* ====================================================================== */
273 /* data structures for my various quick and dirty stacks and queues
274 Eventually, most of this should go away, because I think it can be
275 integrated with stuff already built into the compiler. */
277 /* =================================================================== */
284 struct labelNode *chain;
288 /* this is the most important structure here. Basically this is how I store
289 an exception table entry internally. */
293 rtx exception_handler_label;
300 struct ehEntry *entry;
301 struct ehNode *chain;
312 /* ========================================================================= */
316 /* local globals - these local globals are for storing data necessary for
317 generating the exception table and code in the correct order.
319 ========================================================================= */
321 /* Holds the pc for doing "throw" */
322 static tree saved_pc;
323 /* Holds the type of the thing being thrown. */
324 static tree saved_throw_type;
325 /* Holds the value being thrown. */
326 static tree saved_throw_value;
327 /* Holds the cleanup for the value being thrown. */
328 static tree saved_cleanup;
330 static int throw_used;
332 static rtx catch_clauses;
334 static struct ehStack ehstack;
335 static struct ehQueue ehqueue;
336 static struct ehQueue eh_table_output_queue;
337 static struct labelNode *false_label_stack = NULL;
338 static struct labelNode *caught_return_label_stack = NULL;
339 /* ========================================================================= */
341 /* function prototypes */
342 static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
343 static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
344 static rtx push_eh_entry PROTO((struct ehStack *stack));
345 static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
346 static void new_eh_queue PROTO((struct ehQueue *queue));
347 static void new_eh_stack PROTO((struct ehStack *stack));
348 static void push_label_entry PROTO((struct labelNode **labelstack, rtx rlabel, tree tlabel));
349 static rtx pop_label_entry PROTO((struct labelNode **labelstack));
350 static tree top_label_entry PROTO((struct labelNode **labelstack));
351 static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
354 /* Routines to save and restore eh context information. */
356 struct ehStack ehstack;
357 struct ehQueue ehqueue;
359 struct labelNode *false_label_stack;
360 struct labelNode *caught_return_label_stack;
364 /* Save the context and push into a new one. */
369 = (struct eh_context*)xmalloc (sizeof (struct eh_context));
371 p->ehstack = ehstack;
372 p->ehqueue = ehqueue;
373 p->catch_clauses = catch_clauses;
374 p->false_label_stack = false_label_stack;
375 p->caught_return_label_stack = caught_return_label_stack;
376 p->protect_list = protect_list;
378 new_eh_stack (&ehstack);
379 new_eh_queue (&ehqueue);
380 catch_clauses = NULL_RTX;
381 false_label_stack = NULL;
382 caught_return_label_stack = NULL;
383 protect_list = NULL_TREE;
388 /* Pop and restore the context. */
393 struct eh_context *p = (struct eh_context *)vp;
395 protect_list = p->protect_list;
396 caught_return_label_stack = p->caught_return_label_stack;
397 false_label_stack = p->false_label_stack;
398 catch_clauses = p->catch_clauses;
399 ehqueue = p->ehqueue;
400 ehstack = p->ehstack;
407 /* All my cheesy stack/queue/misc data structure handling routines
409 ========================================================================= */
412 push_label_entry (labelstack, rlabel, tlabel)
413 struct labelNode **labelstack;
417 struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
420 newnode->u.rlabel = rlabel;
422 newnode->u.tlabel = tlabel;
423 newnode->chain = *labelstack;
424 *labelstack = newnode;
428 pop_label_entry (labelstack)
429 struct labelNode **labelstack;
432 struct labelNode *tempnode;
434 if (! *labelstack) return NULL_RTX;
436 tempnode = *labelstack;
437 label = tempnode->u.rlabel;
438 *labelstack = (*labelstack)->chain;
445 top_label_entry (labelstack)
446 struct labelNode **labelstack;
448 if (! *labelstack) return NULL_TREE;
450 return (*labelstack)->u.tlabel;
453 /* Push to permanent obstack for rtl generation.
455 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 *rtl_obstack;
472 rtl_obstack = saved_rtl_obstack;
476 push_eh_entry (stack)
477 struct ehStack *stack;
479 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
480 struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
482 /* These are saved for the exception table. */
484 entry->start_label = gen_label_rtx ();
485 entry->end_label = gen_label_rtx ();
486 entry->exception_handler_label = gen_label_rtx ();
487 pop_rtl_from_perm ();
489 LABEL_PRESERVE_P (entry->start_label) = 1;
490 LABEL_PRESERVE_P (entry->end_label) = 1;
491 LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
493 entry->finalization = NULL_TREE;
494 entry->context = current_function_decl;
497 node->chain = stack->top;
500 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
502 return entry->start_label;
505 /* Pop an entry from the given STACK. */
506 static struct ehEntry *
508 struct ehStack *stack;
510 struct ehNode *tempnode;
511 struct ehEntry *tempentry;
513 tempnode = stack->top;
514 tempentry = tempnode->entry;
515 stack->top = stack->top->chain;
521 static struct ehEntry *
522 copy_eh_entry (entry)
523 struct ehEntry *entry;
525 struct ehEntry *newentry;
527 newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
528 memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
534 enqueue_eh_entry (queue, entry)
535 struct ehQueue *queue;
536 struct ehEntry *entry;
538 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
543 if (queue->head == NULL)
549 queue->tail->chain = node;
554 static struct ehEntry *
555 dequeue_eh_entry (queue)
556 struct ehQueue *queue;
558 struct ehNode *tempnode;
559 struct ehEntry *tempentry;
561 if (queue->head == NULL)
564 tempnode = queue->head;
565 queue->head = queue->head->chain;
567 tempentry = tempnode->entry;
575 struct ehQueue *queue;
577 queue->head = queue->tail = NULL;
582 struct ehStack *stack;
587 /* cheesyness to save some typing. returns the return value rtx */
589 do_function_call (func, params, return_type)
590 tree func, params, return_type;
593 func_call = build_function_call (func, params);
594 expand_call (func_call, NULL_RTX, 0);
595 if (return_type != NULL_TREE)
596 return hard_function_value (return_type, func_call);
601 expand_internal_throw (pc)
604 emit_move_insn (DECL_RTL (saved_pc), pc);
606 emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw"));
608 do_function_call (Throw, NULL_TREE, NULL_TREE);
613 /* ========================================================================= */
616 lang_interim_eh (finalization)
620 end_protect (finalization);
625 extern tree auto_function PROTO((tree, tree, enum built_in_function));
627 /* sets up all the global eh stuff that needs to be initialized at the
628 start of compilation.
631 - Setting up all the function call trees
632 - Initializing the ehqueue
633 - Initializing the eh_table_output_queue
634 - Initializing the ehstack
638 init_exception_processing ()
640 extern tree define_function ();
641 tree unexpected_fndecl, terminate_fndecl;
642 tree set_unexpected_fndecl, set_terminate_fndecl;
643 tree catch_match_fndecl;
644 tree find_first_exception_match_fndecl;
650 tree PFV = build_pointer_type (build_function_type
651 (void_type_node, void_list_node));
653 /* arg list for the build_function_type call for set_terminate () and
655 tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
657 /* void (*pfvtype (void (*) ()))() */
658 tree pfvtype = build_function_type (PFV, pfvlist);
661 tree vtype = build_function_type (void_type_node, void_list_node);
663 set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
664 pfvtype, NOT_BUILT_IN);
665 set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
666 pfvtype, NOT_BUILT_IN);
667 unexpected_fndecl = auto_function (get_identifier ("unexpected"),
668 vtype, NOT_BUILT_IN);
669 terminate_fndecl = auto_function (get_identifier ("terminate"),
670 vtype, NOT_BUILT_IN);
672 interim_eh_hook = lang_interim_eh;
674 push_lang_context (lang_name_c);
677 builtin_function (flag_rtti
678 ? "__throw_type_match_rtti"
679 : "__throw_type_match",
680 build_function_type (ptr_type_node,
681 tree_cons (NULL_TREE, ptr_type_node,
682 tree_cons (NULL_TREE, ptr_type_node,
683 tree_cons (NULL_TREE, ptr_type_node,
685 NOT_BUILT_IN, NULL_PTR);
686 find_first_exception_match_fndecl =
687 builtin_function ("__find_first_exception_table_match",
688 build_function_type (ptr_type_node,
689 tree_cons (NULL_TREE, ptr_type_node,
691 NOT_BUILT_IN, NULL_PTR);
693 builtin_function ("__unwind_function",
694 build_function_type (void_type_node,
695 tree_cons (NULL_TREE, ptr_type_node,
697 NOT_BUILT_IN, NULL_PTR);
699 builtin_function ("__throw",
700 build_function_type (void_type_node, void_list_node),
701 NOT_BUILT_IN, NULL_PTR);
702 DECL_EXTERNAL (throw_fndecl) = 0;
703 TREE_PUBLIC (throw_fndecl) = 0;
705 builtin_function ("__empty",
706 build_function_type (void_type_node, void_list_node),
707 NOT_BUILT_IN, NULL_PTR);
708 DECL_EXTERNAL (empty_fndecl) = 1;
709 TREE_PUBLIC (empty_fndecl) = 1;
711 Unexpected = default_conversion (unexpected_fndecl);
712 Terminate = default_conversion (terminate_fndecl);
713 SetTerminate = default_conversion (set_terminate_fndecl);
714 SetUnexpected = default_conversion (set_unexpected_fndecl);
715 CatchMatch = default_conversion (catch_match_fndecl);
716 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
717 Unwind = default_conversion (unwind_fndecl);
718 Throw = default_conversion (throw_fndecl);
719 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
721 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
725 new_eh_queue (&ehqueue);
726 new_eh_queue (&eh_table_output_queue);
727 new_eh_stack (&ehstack);
729 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
730 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
731 d = start_decl (d, declspecs, 0, NULL_TREE);
733 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
734 saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
736 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
737 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
738 d = start_decl (d, declspecs, 0, NULL_TREE);
740 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
741 saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
743 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
744 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
745 d = start_decl (d, declspecs, 0, NULL_TREE);
747 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
748 saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
750 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
751 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
752 d = build_parse_node (CALL_EXPR, d, void_list_node, NULL_TREE);
753 d = start_decl (d, declspecs, 0, NULL_TREE);
755 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
756 saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
759 /* call this to begin a block of unwind protection (ie: when an object is
767 emit_label (push_eh_entry (&ehstack));
770 /* call this to end a block of unwind protection. the finalization tree is
771 the finalization which needs to be run in order to cleanly unwind through
772 this level of protection. (ie: call this when a scope is exited)*/
774 end_protect (finalization)
777 struct ehEntry *entry;
782 entry = pop_eh_entry (&ehstack);
784 emit_label (entry->end_label);
785 /* Put in something that takes up space, as otherwise the end
786 address for the EH region could have the exact same address as
787 the outer region, causing us to miss the fact that resuming
788 exception handling with this PC value would be inside the outer
790 emit_insn (gen_nop ());
792 entry->finalization = finalization;
794 enqueue_eh_entry (&ehqueue, entry);
797 /* call this on start of a try block. */
799 expand_start_try_stmts ()
808 expand_end_try_stmts ()
810 end_protect (integer_zero_node);
814 /* call this to start processing of all the catch blocks. */
816 expand_start_all_catch ()
818 struct ehEntry *entry;
824 emit_line_note (input_filename, lineno);
825 label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
827 /* The label for the exception handling block we will save. This is
828 Lresume, in the documention. */
829 expand_label (label);
831 /* Put in something that takes up space, as otherwise the end
832 address for the EH region could have the exact same address as
833 the outer region, causing us to miss the fact that resuming
834 exception handling with this PC value would be inside the outer
836 emit_insn (gen_nop ());
838 push_label_entry (&caught_return_label_stack, NULL_RTX, label);
840 /* Start a new sequence for all the catch blocks. We will add this
841 to the gloabl sequence catch_clauses, when we have completed all
842 the handlers in this handler-seq. */
847 entry = dequeue_eh_entry (&ehqueue);
848 emit_label (entry->exception_handler_label);
850 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
852 /* When we get down to the matching entry, stop. */
853 if (entry->finalization == integer_zero_node)
856 /* The below can be optimized away, and we could just fall into the
857 next EH handler, if we are certain they are nested. */
858 /* Code to throw out to outer context, if we fall off end of the
860 expand_internal_throw (gen_rtx (LABEL_REF,
867 /* call this to end processing of all the catch blocks. */
869 expand_end_all_catch ()
871 rtx new_catch_clause;
876 /* Code to throw out to outer context, if we fall off end of catch
877 handlers. This is rethrow (Lresume, same id, same obj); in the
879 expand_internal_throw (gen_rtx (LABEL_REF,
881 DECL_RTL (top_label_entry (&caught_return_label_stack))));
883 /* Now we have the complete catch sequence. */
884 new_catch_clause = get_insns ();
887 /* this level of catch blocks is done, so set up the successful catch jump
888 label for the next layer of catch blocks. */
889 pop_label_entry (&caught_return_label_stack);
891 /* Add the new sequence of catchs to the main one for this
893 push_to_sequence (catch_clauses);
894 emit_insns (new_catch_clause);
895 catch_clauses = get_insns ();
898 /* Here we fall through into the continuation code. */
901 /* Build a type value for use at runtime for a type that is matched
902 against by the exception handling system. */
904 build_eh_type_type (type)
910 if (type == error_mark_node)
911 return error_mark_node;
913 /* peel back references, so they match. */
914 if (TREE_CODE (type) == REFERENCE_TYPE)
915 type = TREE_TYPE (type);
917 /* Peel off cv qualifiers. */
918 type = TYPE_MAIN_VARIANT (type);
922 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
925 typestring = build_overload_name (type, 1, 1);
926 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
927 return build1 (ADDR_EXPR, ptr_type_node, exp);
930 /* Build a type value for use at runtime for a exp that is thrown or
931 matched against by the exception handling system. */
938 exp = build_typeid (exp);
939 return build1 (ADDR_EXPR, ptr_type_node, exp);
941 return build_eh_type_type (TREE_TYPE (exp));
944 /* This routine creates the cleanup for the exception handling object. */
948 /* All cleanups must last longer than normal. */
949 int yes = suspend_momentary ();
951 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
952 tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
953 cp_expand_decl_cleanup (NULL_TREE, cleanup);
955 resume_momentary (yes);
959 /* call this to start a catch block. Typename is the typename, and identifier
960 is the variable to place the object in or NULL if the variable doesn't
961 matter. If typename is NULL, that means its a "catch (...)" or catch
962 everything. In that case we don't need to do any type checking.
963 (ie: it ends up as the "else" clause rather than an "else if" clause) */
965 expand_start_catch_block (declspecs, declarator)
966 tree declspecs, declarator;
969 rtx protect_label_rtx;
970 tree decl = NULL_TREE;
976 /* Create a binding level for the parm. */
977 expand_start_bindings (0);
979 false_label_rtx = gen_label_rtx ();
980 /* This is saved for the exception table. */
982 protect_label_rtx = gen_label_rtx ();
983 pop_rtl_from_perm ();
984 push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
985 push_label_entry (&false_label_stack, protect_label_rtx, NULL_TREE);
990 rtx call_rtx, return_value_rtx;
993 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1,
994 NULL_TREE, NULL_TREE);
996 if (decl == NULL_TREE)
998 error ("invalid catch parameter");
1002 /* Make sure we mark the catch param as used, otherwise we'll get
1003 a warning about an unused ((anonymous)). */
1004 TREE_USED (decl) = 1;
1006 /* Figure out the type that the initializer is. */
1007 init_type = TREE_TYPE (decl);
1008 if (TREE_CODE (init_type) != REFERENCE_TYPE
1009 && TREE_CODE (init_type) != POINTER_TYPE)
1010 init_type = build_reference_type (init_type);
1012 exp = saved_throw_value;
1013 exp = tree_cons (NULL_TREE,
1014 build_eh_type_type (TREE_TYPE (decl)),
1015 tree_cons (NULL_TREE,
1017 tree_cons (NULL_TREE, exp, NULL_TREE)));
1018 exp = build_function_call (CatchMatch, exp);
1019 call_rtx = expand_call (exp, NULL_RTX, 0);
1020 assemble_external (TREE_OPERAND (CatchMatch, 0));
1022 return_value_rtx = hard_function_value (ptr_type_node, exp);
1024 /* did the throw type match function return TRUE? */
1025 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
1026 GET_MODE (return_value_rtx), 0, 0);
1028 /* if it returned FALSE, jump over the catch block, else fall into it */
1029 emit_jump_insn (gen_beq (false_label_rtx));
1033 init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
1035 /* Do we need the below two lines? */
1036 /* Let `cp_finish_decl' know that this initializer is ok. */
1037 DECL_INITIAL (decl) = init;
1038 decl = pushdecl (decl);
1039 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1045 /* Fall into the catch all section. */
1048 /* This is the starting of something to protect. */
1049 emit_label (protect_label_rtx);
1051 emit_line_note (input_filename, lineno);
1055 /* this is called from expand_exception_blocks and
1056 expand_end_catch_block to expand the toplevel finalizations for a
1057 function. We return the first label emitted, if any, otherwise
1060 expand_leftover_cleanups ()
1062 struct ehEntry *entry;
1063 rtx first_label = NULL_RTX;
1065 while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
1068 first_label = entry->exception_handler_label;
1069 emit_label (entry->exception_handler_label);
1071 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
1073 /* The below can be optimized away, and we could just fall into the
1074 next EH handler, if we are certain they are nested. */
1075 /* Code to throw out to outer context, if we fall off end of the
1077 expand_internal_throw (gen_rtx (LABEL_REF,
1081 /* leftover try block, opps. */
1082 if (entry->finalization == integer_zero_node)
1091 /* Call this to end a catch block. Its responsible for emitting the
1092 code to handle jumping back to the correct place, and for emitting
1093 the label to jump to if this catch block didn't match. */
1094 void expand_end_catch_block ()
1096 rtx start_protect_label_rtx;
1097 rtx end_protect_label_rtx;
1099 struct ehEntry entry;
1104 /* fall to outside the try statement when done executing handler and
1105 we fall off end of handler. This is jump Lresume in the
1107 expand_goto (top_label_entry (&caught_return_label_stack));
1109 /* We end the rethrow protection region as soon as we hit a label. */
1110 end_protect_label_rtx = expand_leftover_cleanups ();
1112 /* Code to throw out to outer context, if we get a throw from within
1113 our catch handler. */
1114 /* These are saved for the exception table. */
1116 entry.exception_handler_label = gen_label_rtx ();
1117 pop_rtl_from_perm ();
1118 /* This label is Lhandler in the documentation. */
1119 emit_label (entry.exception_handler_label);
1120 expand_internal_throw (gen_rtx (LABEL_REF,
1122 DECL_RTL (top_label_entry (&caught_return_label_stack))));
1124 /* No associated finalization. */
1125 entry.finalization = NULL_TREE;
1126 entry.context = current_function_decl;
1128 if (end_protect_label_rtx == NULL_RTX)
1129 end_protect_label_rtx = entry.exception_handler_label;
1131 /* Because we are emitted out of line, we have to protect this. */
1132 /* label for the start of the protection region. */
1133 start_protect_label_rtx = pop_label_entry (&false_label_stack);
1135 /* Cleanup the EH parameter. */
1136 decls = getdecls ();
1137 expand_end_bindings (decls, decls != NULL_TREE, 0);
1139 /* label we emit to jump to if this catch block didn't match. */
1140 /* This the closing } in the `if (eq) {' of the documentation. */
1141 emit_label (pop_label_entry (&false_label_stack));
1143 /* Because we are reordered out of line, we have to protect this. */
1144 entry.start_label = start_protect_label_rtx;
1145 entry.end_label = end_protect_label_rtx;
1147 LABEL_PRESERVE_P (entry.start_label) = 1;
1148 LABEL_PRESERVE_P (entry.end_label) = 1;
1149 LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1151 /* These set up a call to throw the caught exception into the outer
1153 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1156 /* unwind the stack. */
1158 do_unwind (inner_throw_label)
1159 rtx inner_throw_label;
1161 #if defined (SPARC_STACK_ALIGN) /* was sparc */
1162 /* This doesn't work for the flat model sparc, I bet. */
1168 /* call to __builtin_return_address () */
1169 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1170 fcall = build_function_call (BuiltinReturnAddress, params);
1171 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1172 /* In the return, the new pc is pc+8, as the value coming in is
1173 really the address of the call insn, not the next insn. */
1174 temp = gen_reg_rtx (Pmode);
1175 emit_move_insn (temp, inner_throw_label);
1176 emit_move_insn (return_val_rtx, plus_constant (temp, -8));
1177 easy_expand_asm ("ret");
1178 easy_expand_asm ("restore");
1181 #if defined (ARM_FRAME_RTX) /* was __arm */
1182 if (flag_omit_frame_pointer)
1183 sorry ("this implementation of exception handling requires a frame pointer");
1185 emit_move_insn (stack_pointer_rtx,
1186 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
1187 emit_move_insn (hard_frame_pointer_rtx,
1188 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
1190 #if defined (TARGET_88000) /* was m88k */
1191 rtx temp_frame = frame_pointer_rtx;
1193 temp_frame = memory_address (Pmode, temp_frame);
1194 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
1196 /* hopefully this will successfully pop the frame! */
1197 emit_move_insn (frame_pointer_rtx, temp_frame);
1198 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
1199 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
1200 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1201 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
1204 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1205 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1207 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
1209 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
1210 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
1213 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
1219 /* I would like to do this here, but the move below doesn't seem to work. */
1220 /* call to __builtin_return_address () */
1221 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1222 fcall = build_function_call (BuiltinReturnAddress, params);
1223 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1225 emit_move_insn (return_val_rtx, inner_throw_label);
1226 /* So, for now, just pass throw label to stack unwinder. */
1228 params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
1229 inner_throw_label), NULL_TREE);
1231 do_function_call (Unwind, params, NULL_TREE);
1232 assemble_external (TREE_OPERAND (Unwind, 0));
1238 /* Given the return address, compute the new pc to throw. This has to
1239 work for the current frame of the current function, and the one
1240 above it in the case of throw. */
1242 eh_outer_context (addr)
1245 #if defined (ARM_FRAME_RTX) /* was __arm */
1246 /* On the ARM, '__builtin_return_address', must have 4
1247 subtracted from it. */
1248 emit_insn (gen_add2_insn (addr, GEN_INT (-4)));
1250 /* If we are generating code for an ARM2/ARM3 machine or for an ARM6
1251 in 26 bit mode, the condition codes must be masked out of the
1252 return value, or else they will confuse BuiltinReturnAddress.
1253 This does not apply to ARM6 and later processors when running in
1256 emit_insn (gen_rtx (SET, Pmode,
1258 gen_rtx (AND, Pmode,
1259 addr, GEN_INT (0x03fffffc))));
1261 #if ! defined (SPARC_STACK_ALIGN) /* was sparc */
1262 #if defined (TARGET_SNAKE)
1263 /* On HPPA, the low order two bits hold the priviledge level, so we
1264 must get rid of them. */
1265 emit_insn (gen_rtx (SET, Pmode,
1267 gen_rtx (AND, Pmode,
1268 addr, GEN_INT (0xfffffffc))));
1271 /* On the SPARC, __builtin_return_address is already -8 or -12, no
1272 need to subtract any more from it. */
1273 addr = plus_constant (addr, -1);
1280 /* is called from expand_exception_blocks () to generate the code in a function
1281 to "throw" if anything in the function needs to perform a throw.
1283 expands "throw" as the following pseudo code:
1286 eh = find_first_exception_match (saved_pc);
1287 if (!eh) goto gotta_rethrow_it;
1291 saved_pc = __builtin_return_address (0);
1292 pop_to_previous_level ();
1297 expand_builtin_throw ()
1302 rtx gotta_rethrow_it;
1303 rtx gotta_call_terminate;
1314 params = void_list_node;
1315 t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE);
1316 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1318 t, NULL_TREE, NULL_TREE, 0);
1319 store_parm_decls ();
1323 expand_start_bindings (0);
1325 gotta_rethrow_it = gen_label_rtx ();
1326 gotta_call_terminate = gen_label_rtx ();
1327 top_of_loop = gen_label_rtx ();
1328 unwind_first = gen_label_rtx ();
1330 emit_jump (unwind_first);
1332 emit_label (top_of_loop);
1334 /* search for an exception handler for the saved_pc */
1335 return_val_rtx = do_function_call (FirstExceptionMatch,
1336 tree_cons (NULL_TREE, saved_pc, NULL_TREE),
1338 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
1340 /* did we find one? */
1341 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1342 GET_MODE (return_val_rtx), 0, 0);
1344 /* if not, jump to gotta_rethrow_it */
1345 emit_jump_insn (gen_beq (gotta_rethrow_it));
1347 /* we found it, so jump to it */
1348 emit_indirect_jump (return_val_rtx);
1350 /* code to deal with unwinding and looking for it again */
1351 emit_label (gotta_rethrow_it);
1353 /* call to __builtin_return_address () */
1354 #if defined (ARM_FRAME_RTX) /* was __arm */
1355 /* This should be moved into arm.h:RETURN_ADDR_RTX */
1356 /* This replaces a 'call' to __builtin_return_address */
1357 return_val_rtx = gen_reg_rtx (Pmode);
1358 emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
1360 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1361 fcall = build_function_call (BuiltinReturnAddress, params);
1362 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1365 /* did __builtin_return_address () return a valid address? */
1366 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1367 GET_MODE (return_val_rtx), 0, 0);
1369 emit_jump_insn (gen_beq (gotta_call_terminate));
1371 return_val_rtx = eh_outer_context (return_val_rtx);
1374 emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1376 do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
1377 emit_jump (top_of_loop);
1379 /* no it didn't --> therefore we need to call terminate */
1380 emit_label (gotta_call_terminate);
1381 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1382 assemble_external (TREE_OPERAND (Terminate, 0));
1385 rtx ret_val, return_val_rtx;
1386 emit_label (unwind_first);
1387 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1388 0, hard_frame_pointer_rtx);
1390 /* Set it up so that we continue inside, at the top of the loop. */
1391 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
1392 #ifdef RETURN_ADDR_OFFSET
1393 return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1394 if (return_val_rtx != ret_val)
1395 emit_move_insn (ret_val, return_val_rtx);
1398 /* Fall into epilogue to unwind prologue. */
1401 expand_end_bindings (getdecls(), 1, 0);
1405 finish_function (lineno, 0, 0);
1410 expand_start_eh_spec ()
1416 expand_end_eh_spec (raises)
1419 tree expr, second_try;
1420 rtx check = gen_label_rtx ();
1422 rtx ret = gen_reg_rtx (Pmode);
1423 rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
1424 rtx end = gen_label_rtx ();
1426 expr = make_node (RTL_EXPR);
1427 TREE_TYPE (expr) = void_type_node;
1428 RTL_EXPR_RTL (expr) = const0_rtx;
1429 TREE_SIDE_EFFECTS (expr) = 1;
1430 start_sequence_for_rtl_expr (expr);
1431 cont = gen_label_rtx ();
1432 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1435 jumpif (make_tree (integer_type_node, flag), end);
1436 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1437 assemble_external (TREE_OPERAND (Terminate, 0));
1439 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1444 expr = make_node (RTL_EXPR);
1445 TREE_TYPE (expr) = void_type_node;
1446 RTL_EXPR_RTL (expr) = const0_rtx;
1447 TREE_SIDE_EFFECTS (expr) = 1;
1448 start_sequence_for_rtl_expr (expr);
1450 cont = gen_label_rtx ();
1451 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1454 jumpif (make_tree (integer_type_node, flag), end);
1456 do_function_call (Unexpected, NULL_TREE, NULL_TREE);
1457 assemble_external (TREE_OPERAND (Unexpected, 0));
1459 end_protect (second_try);
1462 emit_move_insn (flag, const1_rtx);
1463 cont = gen_label_rtx ();
1467 tree match_type = TREE_VALUE (raises);
1471 /* check TREE_VALUE (raises) here */
1472 exp = saved_throw_value;
1473 exp = tree_cons (NULL_TREE,
1474 build_eh_type_type (match_type),
1475 tree_cons (NULL_TREE,
1477 tree_cons (NULL_TREE, exp, NULL_TREE)));
1478 exp = build_function_call (CatchMatch, exp);
1479 assemble_external (TREE_OPERAND (CatchMatch, 0));
1484 raises = TREE_CHAIN (raises);
1486 emit_move_insn (flag, const0_rtx);
1488 emit_indirect_jump (ret);
1491 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1497 /* This is called to expand all the toplevel exception handling
1498 finalization for a function. It should only be called once per
1501 expand_exception_blocks ()
1508 funcend = gen_label_rtx ();
1509 emit_jump (funcend);
1510 /* expand_null_return (); */
1514 /* Add all the catch clauses here. */
1515 emit_insns (catch_clauses);
1516 catch_clauses = NULL_RTX;
1518 expand_leftover_cleanups ();
1520 insns = get_insns ();
1523 /* Do this after we expand leftover cleanups, so that the end_protect
1524 that expand_end_eh_spec does will match the right start_protect,
1525 and make sure it comes out before the terminate protected region. */
1526 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1528 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1529 push_to_sequence (insns);
1531 /* Now expand any new ones. */
1532 expand_leftover_cleanups ();
1534 insns = get_insns ();
1540 struct ehEntry entry;
1542 /* These are saved for the exception table. */
1544 entry.start_label = gen_label_rtx ();
1545 entry.end_label = gen_label_rtx ();
1546 entry.exception_handler_label = gen_label_rtx ();
1547 entry.finalization = TerminateFunctionCall;
1548 entry.context = current_function_decl;
1549 assemble_external (TREE_OPERAND (Terminate, 0));
1550 pop_rtl_from_perm ();
1552 LABEL_PRESERVE_P (entry.start_label) = 1;
1553 LABEL_PRESERVE_P (entry.end_label) = 1;
1554 LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1556 emit_label (entry.start_label);
1559 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1561 emit_label (entry.exception_handler_label);
1562 expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
1563 emit_label (entry.end_label);
1568 /* Mark the end of the stack unwinder. */
1571 end_eh_unwinder (funcend);
1572 expand_leftover_cleanups ();
1573 unwind_insns = get_insns ();
1577 insns = unwind_insns;
1582 emit_label (funcend);
1584 /* Only if we had previous insns do we want to emit the jump around
1585 them. If there weren't any, then insns will remain NULL_RTX. */
1587 insns = get_insns ();
1596 static int counter = 0;
1601 push_cp_function_context (NULL_TREE);
1602 push_to_top_level ();
1604 /* No need to mangle this. */
1605 push_lang_context (lang_name_c);
1607 params = void_list_node;
1608 /* tcf stands for throw clean funciton. */
1609 sprintf (name, "__tcf_%d", counter++);
1610 t = build_parse_node (CALL_EXPR, get_identifier (name), params, NULL_TREE);
1611 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1613 t, NULL_TREE, NULL_TREE, 0);
1614 store_parm_decls ();
1618 expand_start_bindings (0);
1619 emit_line_note (input_filename, lineno);
1621 pop_lang_context ();
1623 return current_function_decl;
1629 expand_end_bindings (getdecls(), 1, 0);
1633 finish_function (lineno, 0, 0);
1635 pop_from_top_level ();
1636 pop_cp_function_context (NULL_TREE);
1639 /* call this to expand a throw statement. This follows the following
1642 1. Allocate space to save the current PC onto the stack.
1643 2. Generate and emit a label and save its address into the
1644 newly allocated stack space since we can't save the pc directly.
1645 3. If this is the first call to throw in this function:
1646 generate a label for the throw block
1647 4. jump to the throw block label. */
1657 /* This is the label that represents where in the code we were, when
1658 we got an exception. This needs to be updated when we rethrow an
1659 exception, so that the matching routine knows to search out. */
1660 label = gen_label_rtx ();
1666 tree cleanup = empty_fndecl, e;
1668 /* throw expression */
1669 /* First, decay it. */
1670 exp = decay_conversion (exp);
1672 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1674 throw_type = build_eh_type (exp);
1675 exp = build_reinterpret_cast (ptr_type_node, exp);
1681 /* Make a copy of the thrown object. WP 15.1.5 */
1682 exp = build_new (NULL_TREE, TREE_TYPE (exp),
1683 build_tree_list (NULL_TREE, exp),
1686 if (exp == error_mark_node)
1687 error (" in thrown expression");
1689 object = build_indirect_ref (exp, NULL_PTR);
1690 throw_type = build_eh_type (object);
1693 object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
1694 object = build_indirect_ref (object, NULL_PTR);
1695 cleanup = maybe_build_cleanup (object);
1697 expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1698 cleanup_insns = get_insns ();
1701 if (cleanup && cleanup_insns)
1703 cleanup = start_anon_func ();
1705 expand_expr (maybe_build_cleanup (object), const0_rtx, VOIDmode, 0);
1709 mark_addressable (cleanup);
1713 cleanup = empty_fndecl;
1717 if (cleanup == empty_fndecl)
1718 assemble_external (empty_fndecl);
1720 e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
1721 expand_expr (e, const0_rtx, VOIDmode, 0);
1723 e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
1724 e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
1725 expand_expr (e, const0_rtx, VOIDmode, 0);
1727 cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
1728 cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
1729 expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1733 /* rethrow current exception */
1734 /* This part is easy, as we don't have to do anything else. */
1737 expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label));
1741 end_protect_partials () {
1742 while (protect_list)
1744 end_protect (TREE_VALUE (protect_list));
1745 protect_list = TREE_CHAIN (protect_list);
1750 might_have_exceptions_p ()
1752 if (eh_table_output_queue.head)
1757 /* Output the exception table.
1758 Return the number of handlers. */
1760 emit_exception_table ()
1763 extern FILE *asm_out_file;
1764 struct ehEntry *entry;
1769 exception_section ();
1771 /* Beginning marker for table. */
1772 assemble_align (GET_MODE_ALIGNMENT (Pmode));
1773 assemble_label ("__EXCEPTION_TABLE__");
1774 output_exception_table_entry (asm_out_file,
1775 const0_rtx, const0_rtx, const0_rtx);
1777 while (entry = dequeue_eh_entry (&eh_table_output_queue))
1779 tree context = entry->context;
1781 if (context && ! TREE_ASM_WRITTEN (context))
1785 output_exception_table_entry (asm_out_file,
1786 entry->start_label, entry->end_label,
1787 entry->exception_handler_label);
1790 /* Ending marker for table. */
1791 assemble_label ("__EXCEPTION_END__");
1792 output_exception_table_entry (asm_out_file,
1793 constm1_rtx, constm1_rtx, constm1_rtx);
1797 register_exception_table ()
1799 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
1801 gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
1805 /* Build a throw expression. */
1810 if (e != error_mark_node)
1812 e = build1 (THROW_EXPR, void_type_node, e);
1813 TREE_SIDE_EFFECTS (e) = 1;
1820 start_eh_unwinder ()
1826 end_eh_unwinder (end)
1830 rtx return_val_rtx, ret_val, label;
1835 expr = make_node (RTL_EXPR);
1836 TREE_TYPE (expr) = void_type_node;
1837 RTL_EXPR_RTL (expr) = const0_rtx;
1838 TREE_SIDE_EFFECTS (expr) = 1;
1839 start_sequence_for_rtl_expr (expr);
1841 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1842 0, hard_frame_pointer_rtx);
1843 return_val_rtx = copy_to_reg (ret_val);
1845 return_val_rtx = eh_outer_context (return_val_rtx);
1847 emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1849 #ifdef JUMP_TO_THROW
1850 emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw"));
1852 label = gen_label_rtx ();
1853 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
1856 #ifdef RETURN_ADDR_OFFSET
1857 return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1858 if (return_val_rtx != ret_val)
1859 emit_move_insn (ret_val, return_val_rtx);
1864 #ifndef JUMP_TO_THROW
1866 do_function_call (Throw, NULL_TREE, NULL_TREE);
1869 RTL_EXPR_SEQUENCE (expr) = get_insns ();