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;
329 /* Indicates if we are in a catch clause. */
330 static tree saved_in_catch;
332 static int throw_used;
334 static rtx catch_clauses;
336 static struct ehStack ehstack;
337 static struct ehQueue ehqueue;
338 static struct ehQueue eh_table_output_queue;
339 static struct labelNode *false_label_stack = NULL;
340 static struct labelNode *caught_return_label_stack = NULL;
341 /* ========================================================================= */
343 /* function prototypes */
344 static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
345 static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
346 static rtx push_eh_entry PROTO((struct ehStack *stack));
347 static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
348 static void new_eh_queue PROTO((struct ehQueue *queue));
349 static void new_eh_stack PROTO((struct ehStack *stack));
350 static void push_label_entry PROTO((struct labelNode **labelstack, rtx rlabel, tree tlabel));
351 static rtx pop_label_entry PROTO((struct labelNode **labelstack));
352 static tree top_label_entry PROTO((struct labelNode **labelstack));
353 static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
356 /* Routines to save and restore eh context information. */
358 struct ehStack ehstack;
359 struct ehQueue ehqueue;
361 struct labelNode *false_label_stack;
362 struct labelNode *caught_return_label_stack;
366 /* Save the context and push into a new one. */
371 = (struct eh_context*)xmalloc (sizeof (struct eh_context));
373 p->ehstack = ehstack;
374 p->ehqueue = ehqueue;
375 p->catch_clauses = catch_clauses;
376 p->false_label_stack = false_label_stack;
377 p->caught_return_label_stack = caught_return_label_stack;
378 p->protect_list = protect_list;
380 new_eh_stack (&ehstack);
381 new_eh_queue (&ehqueue);
382 catch_clauses = NULL_RTX;
383 false_label_stack = NULL;
384 caught_return_label_stack = NULL;
385 protect_list = NULL_TREE;
390 /* Pop and restore the context. */
395 struct eh_context *p = (struct eh_context *)vp;
397 protect_list = p->protect_list;
398 caught_return_label_stack = p->caught_return_label_stack;
399 false_label_stack = p->false_label_stack;
400 catch_clauses = p->catch_clauses;
401 ehqueue = p->ehqueue;
402 ehstack = p->ehstack;
409 /* All my cheesy stack/queue/misc data structure handling routines
411 ========================================================================= */
414 push_label_entry (labelstack, rlabel, tlabel)
415 struct labelNode **labelstack;
419 struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
422 newnode->u.rlabel = rlabel;
424 newnode->u.tlabel = tlabel;
425 newnode->chain = *labelstack;
426 *labelstack = newnode;
430 pop_label_entry (labelstack)
431 struct labelNode **labelstack;
434 struct labelNode *tempnode;
436 if (! *labelstack) return NULL_RTX;
438 tempnode = *labelstack;
439 label = tempnode->u.rlabel;
440 *labelstack = (*labelstack)->chain;
447 top_label_entry (labelstack)
448 struct labelNode **labelstack;
450 if (! *labelstack) return NULL_TREE;
452 return (*labelstack)->u.tlabel;
455 /* Push to permanent obstack for rtl generation.
457 static struct obstack *saved_rtl_obstack;
462 extern struct obstack permanent_obstack;
463 extern struct obstack *rtl_obstack;
465 saved_rtl_obstack = rtl_obstack;
466 rtl_obstack = &permanent_obstack;
469 /* Pop back to normal rtl handling. */
473 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));
484 /* These are saved for the exception table. */
486 entry->start_label = gen_label_rtx ();
487 entry->end_label = gen_label_rtx ();
488 entry->exception_handler_label = gen_label_rtx ();
489 pop_rtl_from_perm ();
491 LABEL_PRESERVE_P (entry->start_label) = 1;
492 LABEL_PRESERVE_P (entry->end_label) = 1;
493 LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
495 entry->finalization = NULL_TREE;
496 entry->context = current_function_decl;
499 node->chain = stack->top;
502 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
504 return entry->start_label;
507 /* Pop an entry from the given STACK. */
508 static struct ehEntry *
510 struct ehStack *stack;
512 struct ehNode *tempnode;
513 struct ehEntry *tempentry;
515 tempnode = stack->top;
516 tempentry = tempnode->entry;
517 stack->top = stack->top->chain;
523 static struct ehEntry *
524 copy_eh_entry (entry)
525 struct ehEntry *entry;
527 struct ehEntry *newentry;
529 newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
530 memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
536 enqueue_eh_entry (queue, entry)
537 struct ehQueue *queue;
538 struct ehEntry *entry;
540 struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
545 if (queue->head == NULL)
551 queue->tail->chain = node;
556 static struct ehEntry *
557 dequeue_eh_entry (queue)
558 struct ehQueue *queue;
560 struct ehNode *tempnode;
561 struct ehEntry *tempentry;
563 if (queue->head == NULL)
566 tempnode = queue->head;
567 queue->head = queue->head->chain;
569 tempentry = tempnode->entry;
577 struct ehQueue *queue;
579 queue->head = queue->tail = NULL;
584 struct ehStack *stack;
589 /* cheesyness to save some typing. returns the return value rtx */
591 do_function_call (func, params, return_type)
592 tree func, params, return_type;
595 func_call = build_function_call (func, params);
596 expand_call (func_call, NULL_RTX, 0);
597 if (return_type != NULL_TREE)
598 return hard_function_value (return_type, func_call);
603 expand_internal_throw (pc)
606 emit_move_insn (DECL_RTL (saved_pc), pc);
608 emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw"));
610 do_function_call (Throw, NULL_TREE, NULL_TREE);
615 /* ========================================================================= */
618 lang_interim_eh (finalization)
622 end_protect (finalization);
627 extern tree auto_function PROTO((tree, tree, enum built_in_function));
629 /* sets up all the global eh stuff that needs to be initialized at the
630 start of compilation.
633 - Setting up all the function call trees
634 - Initializing the ehqueue
635 - Initializing the eh_table_output_queue
636 - Initializing the ehstack
640 init_exception_processing ()
642 extern tree define_function ();
643 tree unexpected_fndecl, terminate_fndecl;
644 tree set_unexpected_fndecl, set_terminate_fndecl;
645 tree catch_match_fndecl;
646 tree find_first_exception_match_fndecl;
652 tree PFV = build_pointer_type (build_function_type
653 (void_type_node, void_list_node));
655 /* arg list for the build_function_type call for set_terminate () and
657 tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
659 /* void (*pfvtype (void (*) ()))() */
660 tree pfvtype = build_function_type (PFV, pfvlist);
663 tree vtype = build_function_type (void_type_node, void_list_node);
665 set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
666 pfvtype, NOT_BUILT_IN);
667 set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
668 pfvtype, NOT_BUILT_IN);
669 unexpected_fndecl = auto_function (get_identifier ("unexpected"),
670 vtype, NOT_BUILT_IN);
671 terminate_fndecl = auto_function (get_identifier ("terminate"),
672 vtype, NOT_BUILT_IN);
674 interim_eh_hook = lang_interim_eh;
676 push_lang_context (lang_name_c);
679 builtin_function (flag_rtti
680 ? "__throw_type_match_rtti"
681 : "__throw_type_match",
682 build_function_type (ptr_type_node,
683 tree_cons (NULL_TREE, ptr_type_node,
684 tree_cons (NULL_TREE, ptr_type_node,
685 tree_cons (NULL_TREE, ptr_type_node,
687 NOT_BUILT_IN, NULL_PTR);
688 find_first_exception_match_fndecl =
689 builtin_function ("__find_first_exception_table_match",
690 build_function_type (ptr_type_node,
691 tree_cons (NULL_TREE, ptr_type_node,
693 NOT_BUILT_IN, NULL_PTR);
695 builtin_function ("__unwind_function",
696 build_function_type (void_type_node,
697 tree_cons (NULL_TREE, ptr_type_node,
699 NOT_BUILT_IN, NULL_PTR);
701 builtin_function ("__throw",
702 build_function_type (void_type_node, void_list_node),
703 NOT_BUILT_IN, NULL_PTR);
704 DECL_EXTERNAL (throw_fndecl) = 0;
705 TREE_PUBLIC (throw_fndecl) = 0;
707 builtin_function ("__empty",
708 build_function_type (void_type_node, void_list_node),
709 NOT_BUILT_IN, NULL_PTR);
710 DECL_EXTERNAL (empty_fndecl) = 1;
711 TREE_PUBLIC (empty_fndecl) = 1;
713 Unexpected = default_conversion (unexpected_fndecl);
714 Terminate = default_conversion (terminate_fndecl);
715 SetTerminate = default_conversion (set_terminate_fndecl);
716 SetUnexpected = default_conversion (set_unexpected_fndecl);
717 CatchMatch = default_conversion (catch_match_fndecl);
718 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
719 Unwind = default_conversion (unwind_fndecl);
720 Throw = default_conversion (throw_fndecl);
721 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
723 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
727 new_eh_queue (&ehqueue);
728 new_eh_queue (&eh_table_output_queue);
729 new_eh_stack (&ehstack);
731 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
732 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
733 d = start_decl (d, declspecs, 0, NULL_TREE);
735 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
736 saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
738 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
739 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
740 d = start_decl (d, declspecs, 0, NULL_TREE);
742 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
743 saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
745 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
746 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
747 d = start_decl (d, declspecs, 0, NULL_TREE);
749 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
750 saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
752 declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
753 d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
754 d = build_parse_node (CALL_EXPR, d, void_list_node, NULL_TREE);
755 d = start_decl (d, declspecs, 0, NULL_TREE);
757 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
758 saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
760 declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE);
761 d = get_identifier ("__eh_in_catch");
762 d = start_decl (d, declspecs, 0, NULL_TREE);
764 cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
765 saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
768 /* call this to begin a block of unwind protection (ie: when an object is
776 emit_label (push_eh_entry (&ehstack));
779 /* call this to end a block of unwind protection. the finalization tree is
780 the finalization which needs to be run in order to cleanly unwind through
781 this level of protection. (ie: call this when a scope is exited)*/
783 end_protect (finalization)
786 struct ehEntry *entry;
791 entry = pop_eh_entry (&ehstack);
793 emit_label (entry->end_label);
794 /* Put in something that takes up space, as otherwise the end
795 address for the EH region could have the exact same address as
796 the outer region, causing us to miss the fact that resuming
797 exception handling with this PC value would be inside the outer
799 emit_insn (gen_nop ());
801 entry->finalization = finalization;
803 enqueue_eh_entry (&ehqueue, entry);
806 /* call this on start of a try block. */
808 expand_start_try_stmts ()
817 expand_end_try_stmts ()
819 end_protect (integer_zero_node);
823 /* call this to start processing of all the catch blocks. */
825 expand_start_all_catch ()
827 struct ehEntry *entry;
833 emit_line_note (input_filename, lineno);
834 label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
836 /* The label for the exception handling block we will save. This is
837 Lresume, in the documention. */
838 expand_label (label);
840 /* Put in something that takes up space, as otherwise the end
841 address for the EH region could have the exact same address as
842 the outer region, causing us to miss the fact that resuming
843 exception handling with this PC value would be inside the outer
845 emit_insn (gen_nop ());
847 push_label_entry (&caught_return_label_stack, NULL_RTX, label);
849 /* Start a new sequence for all the catch blocks. We will add this
850 to the gloabl sequence catch_clauses, when we have completed all
851 the handlers in this handler-seq. */
856 entry = dequeue_eh_entry (&ehqueue);
857 emit_label (entry->exception_handler_label);
859 expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
861 /* When we get down to the matching entry, stop. */
862 if (entry->finalization == integer_zero_node)
865 /* The below can be optimized away, and we could just fall into the
866 next EH handler, if we are certain they are nested. */
867 /* Code to throw out to outer context, if we fall off end of the
869 expand_internal_throw (gen_rtx (LABEL_REF,
876 /* call this to end processing of all the catch blocks. */
878 expand_end_all_catch ()
880 rtx new_catch_clause;
885 /* Code to throw out to outer context, if we fall off end of catch
886 handlers. This is rethrow (Lresume, same id, same obj); in the
888 expand_internal_throw (gen_rtx (LABEL_REF,
890 DECL_RTL (top_label_entry (&caught_return_label_stack))));
892 /* Now we have the complete catch sequence. */
893 new_catch_clause = get_insns ();
896 /* this level of catch blocks is done, so set up the successful catch jump
897 label for the next layer of catch blocks. */
898 pop_label_entry (&caught_return_label_stack);
900 /* Add the new sequence of catchs to the main one for this
902 push_to_sequence (catch_clauses);
903 emit_insns (new_catch_clause);
904 catch_clauses = get_insns ();
907 /* Here we fall through into the continuation code. */
910 /* Build a type value for use at runtime for a type that is matched
911 against by the exception handling system. */
913 build_eh_type_type (type)
919 if (type == error_mark_node)
920 return error_mark_node;
922 /* peel back references, so they match. */
923 if (TREE_CODE (type) == REFERENCE_TYPE)
924 type = TREE_TYPE (type);
926 /* Peel off cv qualifiers. */
927 type = TYPE_MAIN_VARIANT (type);
931 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
934 typestring = build_overload_name (type, 1, 1);
935 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
936 return build1 (ADDR_EXPR, ptr_type_node, exp);
939 /* Build a type value for use at runtime for a exp that is thrown or
940 matched against by the exception handling system. */
947 exp = build_typeid (exp);
948 return build1 (ADDR_EXPR, ptr_type_node, exp);
950 return build_eh_type_type (TREE_TYPE (exp));
953 /* This routine creates the cleanup for the exception handling object. */
957 /* All cleanups must last longer than normal. */
958 int yes = suspend_momentary ();
960 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
961 tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
962 cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
963 build_modify_expr (saved_in_catch, NOP_EXPR,
964 build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node)));
965 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;
988 /* Create a binding level for the parm. */
989 expand_start_bindings (0);
991 false_label_rtx = gen_label_rtx ();
992 /* This is saved for the exception table. */
994 protect_label_rtx = gen_label_rtx ();
995 pop_rtl_from_perm ();
996 push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
997 push_label_entry (&false_label_stack, protect_label_rtx, NULL_TREE);
1002 rtx call_rtx, return_value_rtx;
1005 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1,
1006 NULL_TREE, NULL_TREE);
1008 if (decl == NULL_TREE)
1010 error ("invalid catch parameter");
1014 /* Make sure we mark the catch param as used, otherwise we'll get
1015 a warning about an unused ((anonymous)). */
1016 TREE_USED (decl) = 1;
1018 /* Figure out the type that the initializer is. */
1019 init_type = TREE_TYPE (decl);
1020 if (TREE_CODE (init_type) != REFERENCE_TYPE
1021 && TREE_CODE (init_type) != POINTER_TYPE)
1022 init_type = build_reference_type (init_type);
1024 exp = saved_throw_value;
1025 exp = tree_cons (NULL_TREE,
1026 build_eh_type_type (TREE_TYPE (decl)),
1027 tree_cons (NULL_TREE,
1029 tree_cons (NULL_TREE, exp, NULL_TREE)));
1030 exp = build_function_call (CatchMatch, exp);
1031 call_rtx = expand_call (exp, NULL_RTX, 0);
1032 assemble_external (TREE_OPERAND (CatchMatch, 0));
1034 return_value_rtx = hard_function_value (ptr_type_node, exp);
1036 /* did the throw type match function return TRUE? */
1037 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
1038 GET_MODE (return_value_rtx), 0, 0);
1040 /* if it returned FALSE, jump over the catch block, else fall into it */
1041 emit_jump_insn (gen_beq (false_label_rtx));
1045 init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
1047 /* Do we need the below two lines? */
1048 /* Let `cp_finish_decl' know that this initializer is ok. */
1049 DECL_INITIAL (decl) = init;
1050 decl = pushdecl (decl);
1051 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
1057 /* Fall into the catch all section. */
1060 emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
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;
1327 params = void_list_node;
1328 t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE);
1329 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1331 t, NULL_TREE, NULL_TREE, 0);
1332 store_parm_decls ();
1336 expand_start_bindings (0);
1338 gotta_rethrow_it = gen_label_rtx ();
1339 gotta_call_terminate = gen_label_rtx ();
1340 top_of_loop = gen_label_rtx ();
1341 unwind_first = gen_label_rtx ();
1343 /* These two can be frontend specific. If wanted, they can go in
1345 /* Do we have a valid object we are throwing? */
1346 emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
1347 GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
1348 emit_jump_insn (gen_beq (gotta_call_terminate));
1350 emit_jump (unwind_first);
1352 emit_label (top_of_loop);
1354 /* search for an exception handler for the saved_pc */
1355 return_val_rtx = do_function_call (FirstExceptionMatch,
1356 tree_cons (NULL_TREE, saved_pc, NULL_TREE),
1358 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
1360 /* did we find one? */
1361 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1362 GET_MODE (return_val_rtx), 0, 0);
1364 /* if not, jump to gotta_rethrow_it */
1365 emit_jump_insn (gen_beq (gotta_rethrow_it));
1367 /* we found it, so jump to it */
1368 emit_indirect_jump (return_val_rtx);
1370 /* code to deal with unwinding and looking for it again */
1371 emit_label (gotta_rethrow_it);
1373 /* call to __builtin_return_address () */
1374 #if defined (ARM_FRAME_RTX) /* was __arm */
1375 /* This should be moved into arm.h:RETURN_ADDR_RTX */
1376 /* This replaces a 'call' to __builtin_return_address */
1377 return_val_rtx = gen_reg_rtx (Pmode);
1378 emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
1380 params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
1381 fcall = build_function_call (BuiltinReturnAddress, params);
1382 return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
1385 /* did __builtin_return_address () return a valid address? */
1386 emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
1387 GET_MODE (return_val_rtx), 0, 0);
1389 emit_jump_insn (gen_beq (gotta_call_terminate));
1391 return_val_rtx = eh_outer_context (return_val_rtx);
1394 emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1396 do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
1397 emit_jump (top_of_loop);
1399 /* no it didn't --> therefore we need to call terminate */
1400 emit_label (gotta_call_terminate);
1401 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1402 assemble_external (TREE_OPERAND (Terminate, 0));
1405 rtx ret_val, return_val_rtx;
1406 emit_label (unwind_first);
1407 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1408 0, hard_frame_pointer_rtx);
1410 /* Set it up so that we continue inside, at the top of the loop. */
1411 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
1412 #ifdef RETURN_ADDR_OFFSET
1413 return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1414 if (return_val_rtx != ret_val)
1415 emit_move_insn (ret_val, return_val_rtx);
1418 /* Fall into epilogue to unwind prologue. */
1421 expand_end_bindings (getdecls (), 1, 0);
1425 finish_function (lineno, 0, 0);
1430 expand_start_eh_spec ()
1436 expand_end_eh_spec (raises)
1439 tree expr, second_try;
1440 rtx check = gen_label_rtx ();
1442 rtx ret = gen_reg_rtx (Pmode);
1443 rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
1444 rtx end = gen_label_rtx ();
1446 expr = make_node (RTL_EXPR);
1447 TREE_TYPE (expr) = void_type_node;
1448 RTL_EXPR_RTL (expr) = const0_rtx;
1449 TREE_SIDE_EFFECTS (expr) = 1;
1450 start_sequence_for_rtl_expr (expr);
1451 cont = gen_label_rtx ();
1452 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1455 jumpif (make_tree (integer_type_node, flag), end);
1456 do_function_call (Terminate, NULL_TREE, NULL_TREE);
1457 assemble_external (TREE_OPERAND (Terminate, 0));
1459 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1464 expr = make_node (RTL_EXPR);
1465 TREE_TYPE (expr) = void_type_node;
1466 RTL_EXPR_RTL (expr) = const0_rtx;
1467 TREE_SIDE_EFFECTS (expr) = 1;
1468 start_sequence_for_rtl_expr (expr);
1470 cont = gen_label_rtx ();
1471 emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
1474 jumpif (make_tree (integer_type_node, flag), end);
1476 do_function_call (Unexpected, NULL_TREE, NULL_TREE);
1477 assemble_external (TREE_OPERAND (Unexpected, 0));
1479 end_protect (second_try);
1482 emit_move_insn (flag, const1_rtx);
1483 cont = gen_label_rtx ();
1487 tree match_type = TREE_VALUE (raises);
1491 /* check TREE_VALUE (raises) here */
1492 exp = saved_throw_value;
1493 exp = tree_cons (NULL_TREE,
1494 build_eh_type_type (match_type),
1495 tree_cons (NULL_TREE,
1497 tree_cons (NULL_TREE, exp, NULL_TREE)));
1498 exp = build_function_call (CatchMatch, exp);
1499 assemble_external (TREE_OPERAND (CatchMatch, 0));
1504 raises = TREE_CHAIN (raises);
1506 emit_move_insn (flag, const0_rtx);
1508 emit_indirect_jump (ret);
1511 RTL_EXPR_SEQUENCE (expr) = get_insns ();
1517 /* This is called to expand all the toplevel exception handling
1518 finalization for a function. It should only be called once per
1521 expand_exception_blocks ()
1528 funcend = gen_label_rtx ();
1529 emit_jump (funcend);
1530 /* expand_null_return (); */
1534 /* Add all the catch clauses here. */
1535 emit_insns (catch_clauses);
1536 catch_clauses = NULL_RTX;
1538 expand_leftover_cleanups ();
1540 insns = get_insns ();
1543 /* Do this after we expand leftover cleanups, so that the end_protect
1544 that expand_end_eh_spec does will match the right start_protect,
1545 and make sure it comes out before the terminate protected region. */
1546 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1548 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1549 push_to_sequence (insns);
1551 /* Now expand any new ones. */
1552 expand_leftover_cleanups ();
1554 insns = get_insns ();
1560 struct ehEntry entry;
1562 /* These are saved for the exception table. */
1564 entry.start_label = gen_label_rtx ();
1565 entry.end_label = gen_label_rtx ();
1566 entry.exception_handler_label = gen_label_rtx ();
1567 entry.finalization = TerminateFunctionCall;
1568 entry.context = current_function_decl;
1569 assemble_external (TREE_OPERAND (Terminate, 0));
1570 pop_rtl_from_perm ();
1572 LABEL_PRESERVE_P (entry.start_label) = 1;
1573 LABEL_PRESERVE_P (entry.end_label) = 1;
1574 LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
1576 emit_label (entry.start_label);
1579 enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
1581 emit_label (entry.exception_handler_label);
1582 expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
1583 emit_label (entry.end_label);
1588 /* Mark the end of the stack unwinder. */
1591 end_eh_unwinder (funcend);
1592 expand_leftover_cleanups ();
1593 unwind_insns = get_insns ();
1597 insns = unwind_insns;
1602 emit_label (funcend);
1604 /* Only if we had previous insns do we want to emit the jump around
1605 them. If there weren't any, then insns will remain NULL_RTX. */
1607 insns = get_insns ();
1616 static int counter = 0;
1617 int old_interface_unknown = interface_unknown;
1622 push_cp_function_context (NULL_TREE);
1623 push_to_top_level ();
1625 /* No need to mangle this. */
1626 push_lang_context (lang_name_c);
1628 interface_unknown = 1;
1630 params = void_list_node;
1631 /* tcf stands for throw clean funciton. */
1632 sprintf (name, "__tcf_%d", counter++);
1633 t = build_parse_node (CALL_EXPR, get_identifier (name), params, NULL_TREE);
1634 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1636 t, NULL_TREE, NULL_TREE, 0);
1637 store_parm_decls ();
1641 expand_start_bindings (0);
1642 emit_line_note (input_filename, lineno);
1644 interface_unknown = old_interface_unknown;
1646 pop_lang_context ();
1648 return current_function_decl;
1654 expand_end_bindings (getdecls (), 1, 0);
1658 finish_function (lineno, 0, 0);
1660 pop_from_top_level ();
1661 pop_cp_function_context (NULL_TREE);
1664 /* call this to expand a throw statement. This follows the following
1667 1. Allocate space to save the current PC onto the stack.
1668 2. Generate and emit a label and save its address into the
1669 newly allocated stack space since we can't save the pc directly.
1670 3. If this is the first call to throw in this function:
1671 generate a label for the throw block
1672 4. jump to the throw block label. */
1682 /* This is the label that represents where in the code we were, when
1683 we got an exception. This needs to be updated when we rethrow an
1684 exception, so that the matching routine knows to search out. */
1685 label = gen_label_rtx ();
1691 tree cleanup = empty_fndecl, e;
1693 /* throw expression */
1694 /* First, decay it. */
1695 exp = decay_conversion (exp);
1697 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1699 throw_type = build_eh_type (exp);
1700 exp = build_reinterpret_cast (ptr_type_node, exp);
1707 /* Make a copy of the thrown object. WP 15.1.5 */
1708 exp = build_new (NULL_TREE, TREE_TYPE (exp),
1709 build_tree_list (NULL_TREE, exp),
1712 if (exp == error_mark_node)
1713 error (" in thrown expression");
1715 object = build_indirect_ref (exp, NULL_PTR);
1716 throw_type = build_eh_type (object);
1719 object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
1720 object = build_indirect_ref (object, NULL_PTR);
1721 cleanup = maybe_build_cleanup (object);
1723 expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1724 cleanup_insns = get_insns ();
1727 if (cleanup && cleanup_insns)
1729 cleanup = start_anon_func ();
1731 expand_expr (maybe_build_cleanup (object), const0_rtx, VOIDmode, 0);
1735 mark_addressable (cleanup);
1739 cleanup = empty_fndecl;
1743 if (cleanup == empty_fndecl)
1744 assemble_external (empty_fndecl);
1746 e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
1747 expand_expr (e, const0_rtx, VOIDmode, 0);
1749 e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
1750 e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
1751 expand_expr (e, const0_rtx, VOIDmode, 0);
1753 cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
1754 cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
1755 expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1759 /* rethrow current exception */
1760 /* This part is easy, as we don't have to do anything else. */
1763 expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label));
1767 end_protect_partials () {
1768 while (protect_list)
1770 end_protect (TREE_VALUE (protect_list));
1771 protect_list = TREE_CHAIN (protect_list);
1776 might_have_exceptions_p ()
1778 if (eh_table_output_queue.head)
1783 /* Output the exception table.
1784 Return the number of handlers. */
1786 emit_exception_table ()
1789 extern FILE *asm_out_file;
1790 struct ehEntry *entry;
1795 exception_section ();
1797 /* Beginning marker for table. */
1798 assemble_align (GET_MODE_ALIGNMENT (Pmode));
1799 assemble_label ("__EXCEPTION_TABLE__");
1800 output_exception_table_entry (asm_out_file,
1801 const0_rtx, const0_rtx, const0_rtx);
1803 while (entry = dequeue_eh_entry (&eh_table_output_queue))
1805 tree context = entry->context;
1807 if (context && ! TREE_ASM_WRITTEN (context))
1811 output_exception_table_entry (asm_out_file,
1812 entry->start_label, entry->end_label,
1813 entry->exception_handler_label);
1816 /* Ending marker for table. */
1817 assemble_label ("__EXCEPTION_END__");
1818 output_exception_table_entry (asm_out_file,
1819 constm1_rtx, constm1_rtx, constm1_rtx);
1823 register_exception_table ()
1825 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
1827 gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
1831 /* Build a throw expression. */
1836 if (e != error_mark_node)
1838 if (current_template_parms)
1839 return build_min (THROW_EXPR, void_type_node, e);
1840 e = build1 (THROW_EXPR, void_type_node, e);
1841 TREE_SIDE_EFFECTS (e) = 1;
1848 start_eh_unwinder ()
1854 end_eh_unwinder (end)
1858 rtx return_val_rtx, ret_val, label;
1863 expr = make_node (RTL_EXPR);
1864 TREE_TYPE (expr) = void_type_node;
1865 RTL_EXPR_RTL (expr) = const0_rtx;
1866 TREE_SIDE_EFFECTS (expr) = 1;
1867 start_sequence_for_rtl_expr (expr);
1869 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1870 0, hard_frame_pointer_rtx);
1871 return_val_rtx = copy_to_reg (ret_val);
1873 return_val_rtx = eh_outer_context (return_val_rtx);
1875 emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
1877 #ifdef JUMP_TO_THROW
1878 emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw"));
1880 label = gen_label_rtx ();
1881 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
1884 #ifdef RETURN_ADDR_OFFSET
1885 return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1886 if (return_val_rtx != ret_val)
1887 emit_move_insn (ret_val, return_val_rtx);
1892 #ifndef JUMP_TO_THROW
1894 do_function_call (Throw, NULL_TREE, NULL_TREE);
1897 RTL_EXPR_SEQUENCE (expr) = get_insns ();