aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/except.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/except.c')
-rw-r--r--gcc/cp/except.c1152
1 files changed, 0 insertions, 1152 deletions
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
deleted file mode 100644
index 37f6dfea6c7..00000000000
--- a/gcc/cp/except.c
+++ /dev/null
@@ -1,1152 +0,0 @@
-/* Handle exceptional things in C++.
- Copyright (C) 1989, 92-95, 1996 Free Software Foundation, Inc.
- Contributed by Michael Tiemann <tiemann@cygnus.com>
- Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
- initial re-implementation courtesy Tad Hunt.
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-
-#include "config.h"
-#include "tree.h"
-#include "rtl.h"
-#include "cp-tree.h"
-#include "flags.h"
-#include "obstack.h"
-#include "expr.h"
-#include "output.h"
-#include "except.h"
-#include "function.h"
-
-rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
-
-/* holds the fndecl for __builtin_return_address () */
-tree builtin_return_address_fndecl;
-
-/* A couple of backend routines from m88k.c */
-
-/* used to cache a call to __builtin_return_address () */
-static tree BuiltinReturnAddress;
-
-
-#include <stdio.h>
-
-static void
-easy_expand_asm (str)
- char *str;
-{
- expand_asm (build_string (strlen (str)+1, str));
-}
-
-
-#if 0
-/* This is the startup, and finish stuff per exception table. */
-
-/* XXX - Tad: exception handling section */
-#ifndef EXCEPT_SECTION_ASM_OP
-#define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
-#endif
-
-#ifdef EXCEPT_SECTION_ASM_OP
-typedef struct {
- void *start_region;
- void *end_region;
- void *exception_handler;
- } exception_table;
-#endif /* EXCEPT_SECTION_ASM_OP */
-
-#ifdef EXCEPT_SECTION_ASM_OP
-
- /* on machines which support it, the exception table lives in another section,
- but it needs a label so we can reference it... This sets up that
- label! */
-asm (EXCEPT_SECTION_ASM_OP);
-exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
-asm (TEXT_SECTION_ASM_OP);
-
-#endif /* EXCEPT_SECTION_ASM_OP */
-
-#ifdef EXCEPT_SECTION_ASM_OP
-
- /* we need to know where the end of the exception table is... so this
- is how we do it! */
-
-asm (EXCEPT_SECTION_ASM_OP);
-exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
-asm (TEXT_SECTION_ASM_OP);
-
-#endif /* EXCEPT_SECTION_ASM_OP */
-
-#endif
-
-#include "decl.h"
-#include "insn-flags.h"
-#include "obstack.h"
-
-/* ======================================================================
- Briefly the algorithm works like this:
-
- When a constructor or start of a try block is encountered,
- push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
- new entry in the unwind protection stack and returns a label to
- output to start the protection for that block.
-
- When a destructor or end try block is encountered, pop_eh_entry
- (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
- created when push_eh_entry () was called. The eh_entry structure
- contains three things at this point. The start protect label,
- the end protect label, and the exception handler label. The end
- protect label should be output before the call to the destructor
- (if any). If it was a destructor, then its parse tree is stored
- in the finalization variable in the eh_entry structure. Otherwise
- the finalization variable is set to NULL to reflect the fact that
- is the the end of a try block. Next, this modified eh_entry node
- is enqueued in the finalizations queue by calling
- enqueue_eh_entry (&queue,entry).
-
- +---------------------------------------------------------------+
- |XXX: Will need modification to deal with partially |
- | constructed arrays of objects |
- | |
- | Basically, this consists of keeping track of how many |
- | of the objects have been constructed already (this |
- | should be in a register though, so that shouldn't be a |
- | problem. |
- +---------------------------------------------------------------+
-
- When a catch block is encountered, there is a lot of work to be
- done.
-
- Since we don't want to generate the catch block inline with the
- regular flow of the function, we need to have some way of doing
- so. Luckily, we can use sequences to defer the catch sections.
- When the start of a catch block is encountered, we start the
- sequence. After the catch block is generated, we end the
- sequence.
-
- Next we must insure that when the catch block is executed, all
- finalizations for the matching try block have been completed. If
- any of those finalizations throw an exception, we must call
- terminate according to the ARM (section r.15.6.1). What this
- means is that we need to dequeue and emit finalizations for each
- entry in the eh_queue until we get to an entry with a NULL
- finalization field. For any of the finalization entries, if it
- is not a call to terminate (), we must protect it by giving it
- another start label, end label, and exception handler label,
- setting its finalization tree to be a call to terminate (), and
- enqueue'ing this new eh_entry to be output at an outer level.
- Finally, after all that is done, we can get around to outputting
- the catch block which basically wraps all the "catch (...) {...}"
- statements in a big if/then/else construct that matches the
- correct block to call.
-
- ===================================================================== */
-
-extern rtx emit_insn PROTO((rtx));
-extern rtx gen_nop PROTO(());
-
-/* local globals for function calls
- ====================================================================== */
-
-/* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
- "set_unexpected ()" after default_conversion. (lib-except.c) */
-static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
-
-/* used to cache __find_first_exception_table_match ()
- for throw (lib-except.c) */
-static tree FirstExceptionMatch;
-
-/* used to cache a call to __unwind_function () (lib-except.c) */
-static tree Unwind;
-
-/* holds a ready to emit call to "terminate ()". */
-static tree TerminateFunctionCall;
-
-static tree empty_fndecl;
-
-/* ====================================================================== */
-
-
-/* ========================================================================= */
-
-
-
-/* local globals - these local globals are for storing data necessary for
- generating the exception table and code in the correct order.
-
- ========================================================================= */
-
-/* Holds the pc for doing "throw" */
-static tree saved_pc;
-/* Holds the type of the thing being thrown. */
-static tree saved_throw_type;
-/* Holds the value being thrown. */
-static tree saved_throw_value;
-/* Holds the cleanup for the value being thrown. */
-static tree saved_cleanup;
-/* Indicates if we are in a catch clause. */
-static tree saved_in_catch;
-
-extern int throw_used;
-extern rtx catch_clauses;
-
-/* ========================================================================= */
-
-/* Cheesyness to save some typing. Returns the return value rtx. */
-
-static rtx
-do_function_call (func, params, return_type)
- tree func, params, return_type;
-{
- tree func_call;
- func_call = build_function_call (func, params);
- expand_call (func_call, NULL_RTX, 0);
- if (return_type != NULL_TREE)
- return hard_function_value (return_type, func_call);
- return NULL_RTX;
-}
-
-/* ========================================================================= */
-
-/* sets up all the global eh stuff that needs to be initialized at the
- start of compilation.
-
- This includes:
- - Setting up all the function call trees. */
-
-void
-init_exception_processing ()
-{
- extern tree define_function ();
- tree unexpected_fndecl, terminate_fndecl;
- tree set_unexpected_fndecl, set_terminate_fndecl;
- tree catch_match_fndecl;
- tree find_first_exception_match_fndecl;
- tree unwind_fndecl;
- tree declspecs;
- tree d;
-
- /* void (*)() */
- tree PFV = build_pointer_type (build_function_type
- (void_type_node, void_list_node));
-
- /* arg list for the build_function_type call for set_terminate () and
- set_unexpected () */
- tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
-
- /* void (*pfvtype (void (*) ()))() */
- tree pfvtype = build_function_type (PFV, pfvlist);
-
- /* void vtype () */
- tree vtype = build_function_type (void_type_node, void_list_node);
-
- set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
- pfvtype, NOT_BUILT_IN);
- set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
- pfvtype, NOT_BUILT_IN);
- unexpected_fndecl = auto_function (get_identifier ("unexpected"),
- vtype, NOT_BUILT_IN);
- terminate_fndecl = auto_function (get_identifier ("terminate"),
- vtype, NOT_BUILT_IN);
-
- push_lang_context (lang_name_c);
-
- catch_match_fndecl =
- builtin_function (flag_rtti
- ? "__throw_type_match_rtti"
- : "__throw_type_match",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)))),
- NOT_BUILT_IN, NULL_PTR);
- find_first_exception_match_fndecl =
- builtin_function ("__find_first_exception_table_match",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN, NULL_PTR);
- unwind_fndecl =
- builtin_function ("__unwind_function",
- build_function_type (void_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN, NULL_PTR);
- empty_fndecl =
- builtin_function ("__empty",
- build_function_type (void_type_node, void_list_node),
- NOT_BUILT_IN, NULL_PTR);
- DECL_EXTERNAL (empty_fndecl) = 1;
- TREE_PUBLIC (empty_fndecl) = 1;
-
- Unexpected = default_conversion (unexpected_fndecl);
- Terminate = default_conversion (terminate_fndecl);
- SetTerminate = default_conversion (set_terminate_fndecl);
- SetUnexpected = default_conversion (set_unexpected_fndecl);
- CatchMatch = default_conversion (catch_match_fndecl);
- FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
- Unwind = default_conversion (unwind_fndecl);
- BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
-
- TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
-
- pop_lang_context ();
-
- declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
- d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
- d = start_decl (d, declspecs, 0);
- DECL_COMMON (d) = 1;
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
- saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
-
- declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
- d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
- d = start_decl (d, declspecs, 0);
- DECL_COMMON (d) = 1;
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
- saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
-
- declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
- d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
- d = start_decl (d, declspecs, 0);
- DECL_COMMON (d) = 1;
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
- saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
-
- declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
- d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
- d = make_call_declarator (d, void_list_node, NULL_TREE, NULL_TREE);
- d = start_decl (d, declspecs, 0);
- DECL_COMMON (d) = 1;
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
- saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
-
- declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE);
- d = get_identifier ("__eh_in_catch");
- d = start_decl (d, declspecs, 0);
- DECL_COMMON (d) = 1;
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
- saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
-}
-
-/* Build a type value for use at runtime for a type that is matched
- against by the exception handling system. */
-
-static tree
-build_eh_type_type (type)
- tree type;
-{
- char *typestring;
- tree exp;
-
- if (type == error_mark_node)
- return error_mark_node;
-
- /* peel back references, so they match. */
- if (TREE_CODE (type) == REFERENCE_TYPE)
- type = TREE_TYPE (type);
-
- /* Peel off cv qualifiers. */
- type = TYPE_MAIN_VARIANT (type);
-
- if (flag_rtti)
- {
- return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
- }
-
- typestring = build_overload_name (type, 1, 1);
- exp = combine_strings (build_string (strlen (typestring)+1, typestring));
- return build1 (ADDR_EXPR, ptr_type_node, exp);
-}
-
-/* Build a type value for use at runtime for a exp that is thrown or
- matched against by the exception handling system. */
-
-static tree
-build_eh_type (exp)
- tree exp;
-{
- if (flag_rtti)
- {
- exp = build_typeid (exp);
- return build1 (ADDR_EXPR, ptr_type_node, exp);
- }
- return build_eh_type_type (TREE_TYPE (exp));
-}
-
-/* This routine creates the cleanup for the exception handling object. */
-
-static void
-push_eh_cleanup ()
-{
- /* All cleanups must last longer than normal. */
- int yes = suspend_momentary ();
-
- /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
- tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
- cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
- build_modify_expr (saved_in_catch, NOP_EXPR,
- build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node)));
- expand_decl_cleanup (NULL_TREE, cleanup);
-
- resume_momentary (yes);
-}
-
-
-/* call this to start a catch block. Typename is the typename, and identifier
- is the variable to place the object in or NULL if the variable doesn't
- matter. If typename is NULL, that means its a "catch (...)" or catch
- everything. In that case we don't need to do any type checking.
- (ie: it ends up as the "else" clause rather than an "else if" clause) */
-
-void
-expand_start_catch_block (declspecs, declarator)
- tree declspecs, declarator;
-{
- rtx false_label_rtx;
- tree decl = NULL_TREE;
- tree init;
-
- if (processing_template_decl)
- {
- if (declspecs)
- {
- decl = grokdeclarator (declarator, declspecs, CATCHPARM,
- 1, NULL_TREE);
- pushdecl (decl);
- decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
- copy_to_permanent (declspecs),
- NULL_TREE);
- add_tree (decl);
- }
- return;
- }
-
- if (! doing_eh (1))
- return;
-
- /* Create a binding level for the parm. */
- pushlevel (0);
- expand_start_bindings (0);
-
- false_label_rtx = gen_label_rtx ();
- push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
-
- if (declspecs)
- {
- tree exp;
- rtx call_rtx, return_value_rtx;
- tree init_type;
-
- decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
-
- if (decl == NULL_TREE)
- {
- error ("invalid catch parameter");
-
- /* This is cheap, but we want to maintain the data structures. */
- expand_eh_region_start ();
- return;
- }
-
- /* Make sure we mark the catch param as used, otherwise we'll get
- a warning about an unused ((anonymous)). */
- TREE_USED (decl) = 1;
-
- /* Figure out the type that the initializer is. */
- init_type = TREE_TYPE (decl);
- if (TREE_CODE (init_type) != REFERENCE_TYPE
- && TREE_CODE (init_type) != POINTER_TYPE)
- init_type = build_reference_type (init_type);
-
- exp = saved_throw_value;
- exp = tree_cons (NULL_TREE,
- build_eh_type_type (TREE_TYPE (decl)),
- tree_cons (NULL_TREE,
- saved_throw_type,
- tree_cons (NULL_TREE, exp, NULL_TREE)));
- exp = build_function_call (CatchMatch, exp);
- call_rtx = expand_call (exp, NULL_RTX, 0);
- assemble_external (TREE_OPERAND (CatchMatch, 0));
-
- return_value_rtx = hard_function_value (ptr_type_node, exp);
-
- /* did the throw type match function return TRUE? */
- emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
- GET_MODE (return_value_rtx), 0, 0);
-
- /* if it returned FALSE, jump over the catch block, else fall into it */
- emit_jump_insn (gen_beq (false_label_rtx));
-
- push_eh_cleanup ();
-
- init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
-
- /* Do we need the below two lines? */
- /* Let `cp_finish_decl' know that this initializer is ok. */
- DECL_INITIAL (decl) = init;
- decl = pushdecl (decl);
- cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
- }
- else
- {
- push_eh_cleanup ();
-
- /* Fall into the catch all section. */
- }
-
- emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
-
- /* Because we are reordered out of line, we arrange
- to rethrow in the outer context, should we encounter
- an exception in the catch handler.
-
- Matches the end in expand_end_catch_block (). */
- expand_eh_region_start ();
-
- emit_line_note (input_filename, lineno);
-}
-
-
-
-/* Call this to end a catch block. Its responsible for emitting the
- code to handle jumping back to the correct place, and for emitting
- the label to jump to if this catch block didn't match. */
-
-void
-expand_end_catch_block ()
-{
- rtx start_region_label_rtx;
- rtx end_region_label_rtx;
- tree decls, t;
-
- if (! doing_eh (1))
- return;
-
- /* Fall to outside the try statement when done executing handler and
- we fall off end of handler. This is jump Lresume in the
- documentation. */
- expand_goto (top_label_entry (&caught_return_label_stack));
-
- t = make_node (RTL_EXPR);
- TREE_TYPE (t) = void_type_node;
- RTL_EXPR_RTL (t) = const0_rtx;
- TREE_SIDE_EFFECTS (t) = 1;
- start_sequence_for_rtl_expr (t);
- expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
- RTL_EXPR_SEQUENCE (t) = get_insns ();
- end_sequence ();
-
- /* Matches the start in expand_start_catch_block (). */
- expand_eh_region_end (t);
-
- expand_leftover_cleanups ();
-
- /* Cleanup the EH parameter. */
- expand_end_bindings (getdecls (), kept_level_p (), 0);
- poplevel (kept_level_p (), 1, 0);
-
- /* label we emit to jump to if this catch block didn't match. */
- /* This the closing } in the `if (eq) {' of the documentation. */
- emit_label (pop_label_entry (&false_label_stack));
-}
-
-/* unwind the stack. */
-
-static void
-do_unwind (inner_throw_label)
- rtx inner_throw_label;
-{
-#if defined (SPARC_STACK_ALIGN) /* was sparc */
- /* This doesn't work for the flat model sparc, I bet. */
- tree fcall;
- tree params;
- rtx return_val_rtx;
- rtx temp;
-
- /* call to __builtin_return_address () */
- params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
- fcall = build_function_call (BuiltinReturnAddress, params);
- return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
- /* In the return, the new pc is pc+8, as the value coming in is
- really the address of the call insn, not the next insn. */
- temp = gen_reg_rtx (Pmode);
- emit_move_insn (temp, inner_throw_label);
- emit_move_insn (return_val_rtx, plus_constant (temp, -8));
- emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31)));
- easy_expand_asm ("ret");
- easy_expand_asm ("restore");
- emit_barrier ();
-#endif
-#if defined (ARM_FRAME_RTX) /* was __arm */
- if (flag_omit_frame_pointer)
- sorry ("this implementation of exception handling requires a frame pointer");
-
- emit_move_insn (stack_pointer_rtx,
- gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
- emit_move_insn (hard_frame_pointer_rtx,
- gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
-#endif
-#if defined (TARGET_88000) /* was m88k */
- rtx temp_frame = frame_pointer_rtx;
-
- temp_frame = memory_address (Pmode, temp_frame);
- temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
-
- /* hopefully this will successfully pop the frame! */
- emit_move_insn (frame_pointer_rtx, temp_frame);
- emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
- emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
- emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
- (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
-
-#if 0
- emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
- -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
-
- emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
-
- emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
- (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
-#endif
-#endif
-#if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
- tree fcall;
- tree params;
- rtx return_val_rtx;
-
-#if 0
- /* I would like to do this here, but the move below doesn't seem to work. */
- /* call to __builtin_return_address () */
- params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
- fcall = build_function_call (BuiltinReturnAddress, params);
- return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
-
- emit_move_insn (return_val_rtx, inner_throw_label);
- /* So, for now, just pass throw label to stack unwinder. */
-#endif
- params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
- inner_throw_label), NULL_TREE);
-
- do_function_call (Unwind, params, NULL_TREE);
- assemble_external (TREE_OPERAND (Unwind, 0));
- emit_barrier ();
-#endif
-}
-
-
-/* is called from expand_exception_blocks () to generate the code in a function
- to "throw" if anything in the function needs to perform a throw.
-
- expands "throw" as the following pseudo code:
-
- throw:
- eh = find_first_exception_match (saved_pc);
- if (!eh) goto gotta_rethrow_it;
- goto eh;
-
- gotta_rethrow_it:
- saved_pc = __builtin_return_address (0);
- pop_to_previous_level ();
- goto throw; */
-
-void
-expand_builtin_throw ()
-{
- tree fcall;
- tree params;
- rtx return_val_rtx;
- rtx gotta_rethrow_it;
- rtx gotta_call_terminate;
- rtx top_of_loop;
- rtx unwind_first;
- tree t;
-
- if (! doing_eh (0))
- return;
-
- if (! throw_used)
- return;
-
- params = void_list_node;
- t = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE,
- NULL_TREE);
- start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
- void_list_node),
- t, NULL_TREE, 0);
- store_parm_decls ();
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
-
- gotta_rethrow_it = gen_label_rtx ();
- gotta_call_terminate = gen_label_rtx ();
- top_of_loop = gen_label_rtx ();
- unwind_first = gen_label_rtx ();
-
- /* These two can be frontend specific. If wanted, they can go in
- expand_throw. */
- /* Do we have a valid object we are throwing? */
- emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
- GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
- emit_jump_insn (gen_beq (gotta_call_terminate));
-
- emit_jump (unwind_first);
-
- emit_label (top_of_loop);
-
- /* search for an exception handler for the saved_pc */
- return_val_rtx = do_function_call (FirstExceptionMatch,
- tree_cons (NULL_TREE, saved_pc, NULL_TREE),
- ptr_type_node);
- assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
-
- /* did we find one? */
- emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
- GET_MODE (return_val_rtx), 0, 0);
-
- /* if not, jump to gotta_rethrow_it */
- emit_jump_insn (gen_beq (gotta_rethrow_it));
-
- /* we found it, so jump to it */
- emit_indirect_jump (return_val_rtx);
-
- /* code to deal with unwinding and looking for it again */
- emit_label (gotta_rethrow_it);
-
- /* call to __builtin_return_address () */
-#if defined (ARM_FRAME_RTX) /* was __arm */
- /* This should be moved into arm.h:RETURN_ADDR_RTX */
- /* This replaces a 'call' to __builtin_return_address */
- return_val_rtx = gen_reg_rtx (Pmode);
- emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
-#else
- params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
- fcall = build_function_call (BuiltinReturnAddress, params);
- return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
-#endif
-
- /* did __builtin_return_address () return a valid address? */
- emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
- GET_MODE (return_val_rtx), 0, 0);
-
- emit_jump_insn (gen_beq (gotta_call_terminate));
-
- return_val_rtx = eh_outer_context (return_val_rtx);
-
- /* Yes it did. */
- emit_move_insn (eh_saved_pc_rtx, return_val_rtx);
-
- do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
- emit_jump (top_of_loop);
-
- /* no it didn't --> therefore we need to call terminate */
- emit_label (gotta_call_terminate);
- do_function_call (Terminate, NULL_TREE, NULL_TREE);
- assemble_external (TREE_OPERAND (Terminate, 0));
-
- {
- rtx ret_val, return_val_rtx;
- emit_label (unwind_first);
- ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
- 0, hard_frame_pointer_rtx);
-
- /* Set it up so that we continue inside, at the top of the loop. */
- emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
-#ifdef RETURN_ADDR_OFFSET
- return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
- if (return_val_rtx != ret_val)
- emit_move_insn (ret_val, return_val_rtx);
-#endif
-
- /* Fall into epilogue to unwind prologue. */
- }
-
- expand_end_bindings (getdecls (), 1, 0);
- poplevel (1, 0, 0);
- pop_momentary ();
-
- finish_function (lineno, 0, 0);
-}
-
-
-void
-expand_start_eh_spec ()
-{
- expand_eh_region_start ();
-}
-
-static void
-expand_end_eh_spec (raises)
- tree raises;
-{
- tree expr, second_try;
- rtx check = gen_label_rtx ();
- rtx cont;
- rtx ret = gen_reg_rtx (Pmode);
- rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
- rtx end = gen_label_rtx ();
-
- expr = make_node (RTL_EXPR);
- TREE_TYPE (expr) = void_type_node;
- RTL_EXPR_RTL (expr) = const0_rtx;
- TREE_SIDE_EFFECTS (expr) = 1;
- start_sequence_for_rtl_expr (expr);
- cont = gen_label_rtx ();
- emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
- emit_jump (check);
- emit_label (cont);
- jumpif (make_tree (integer_type_node, flag), end);
- do_function_call (Terminate, NULL_TREE, NULL_TREE);
- assemble_external (TREE_OPERAND (Terminate, 0));
- emit_barrier ();
- RTL_EXPR_SEQUENCE (expr) = get_insns ();
- end_sequence ();
-
- second_try = expr;
-
- expr = make_node (RTL_EXPR);
- TREE_TYPE (expr) = void_type_node;
- RTL_EXPR_RTL (expr) = const0_rtx;
- TREE_SIDE_EFFECTS (expr) = 1;
- start_sequence_for_rtl_expr (expr);
-
- cont = gen_label_rtx ();
- emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
- emit_jump (check);
- emit_label (cont);
- jumpif (make_tree (integer_type_node, flag), end);
- expand_eh_region_start ();
- do_function_call (Unexpected, NULL_TREE, NULL_TREE);
- assemble_external (TREE_OPERAND (Unexpected, 0));
- emit_barrier ();
- expand_eh_region_end (second_try);
-
- emit_label (check);
- emit_move_insn (flag, const1_rtx);
- cont = gen_label_rtx ();
- while (raises)
- {
- tree exp;
- tree match_type = TREE_VALUE (raises);
-
- if (match_type)
- {
- /* check TREE_VALUE (raises) here */
- exp = saved_throw_value;
- exp = tree_cons (NULL_TREE,
- build_eh_type_type (match_type),
- tree_cons (NULL_TREE,
- saved_throw_type,
- tree_cons (NULL_TREE, exp, NULL_TREE)));
- exp = build_function_call (CatchMatch, exp);
- assemble_external (TREE_OPERAND (CatchMatch, 0));
-
- jumpif (exp, cont);
- }
-
- raises = TREE_CHAIN (raises);
- }
- emit_move_insn (flag, const0_rtx);
- emit_label (cont);
- emit_indirect_jump (ret);
- emit_label (end);
-
- RTL_EXPR_SEQUENCE (expr) = get_insns ();
- end_sequence ();
-
- expand_eh_region_end (expr);
-}
-
-/* This is called to expand all the toplevel exception handling
- finalization for a function. It should only be called once per
- function. */
-
-void
-expand_exception_blocks ()
-{
- rtx funcend;
- rtx insn, insns;
- rtx eh_spec_insns = NULL_RTX;
-
- start_sequence ();
-
- funcend = gen_label_rtx ();
- emit_jump (funcend);
- /* expand_null_return (); */
-
- start_sequence ();
-
- /* Add all the catch clauses here. */
- emit_insns (catch_clauses);
- catch_clauses = NULL_RTX;
-
- expand_leftover_cleanups ();
-
- insns = get_insns ();
- end_sequence ();
-
- /* Do this after we expand leftover cleanups, so that the expand_eh_region_end
- that expand_end_eh_spec does will match the right expand_eh_region_start,
- and make sure it comes out before the terminate protected region. */
- if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
- {
-#if 1
- {
- rtx insns;
- /* New... */
- start_sequence ();
- expand_start_eh_spec ();
- eh_spec_insns = get_insns ();
- end_sequence ();
- }
-#endif
-
- expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
- push_to_sequence (insns);
-
- /* Now expand any new ones. */
- expand_leftover_cleanups ();
-
- insns = get_insns ();
- end_sequence ();
- }
-
- if (insns)
- {
- /* Is this necessary? */
- assemble_external (TREE_OPERAND (Terminate, 0));
-
- expand_eh_region_start ();
- emit_insns (insns);
- expand_eh_region_end (TerminateFunctionCall);
- expand_leftover_cleanups ();
- }
-
- {
- /* Mark the end of the stack unwinder. */
- rtx unwind_insns;
- start_sequence ();
-#if 0
- end_eh_unwinder ();
-#endif
- unwind_insns = get_insns ();
- end_sequence ();
- if (unwind_insns)
- {
- insns = unwind_insns;
- emit_insns (insns);
- }
- }
-
- emit_label (funcend);
-
- /* Only if we had previous insns do we want to emit the jump around
- them. If there weren't any, then insns will remain NULL_RTX. */
- if (insns)
- insns = get_insns ();
- end_sequence ();
-
-#if 1
- if (eh_spec_insns)
- emit_insns_after (eh_spec_insns, get_insns ());
-#else
- if (eh_spec_insns)
- store_after_parms (eh_spec_insns);
-#endif
-
- insn = get_last_insn ();
- while (GET_CODE (insn) == NOTE
- || (GET_CODE (insn) == INSN
- && (GET_CODE (PATTERN (insn)) == USE
- || GET_CODE (PATTERN (insn)) == CLOBBER)))
- insn = PREV_INSN (insn);
-
- emit_insns_after (insns, insn);
-}
-
-tree
-start_anon_func ()
-{
- static int counter = 0;
- int old_interface_unknown = interface_unknown;
- char name[32];
- tree params;
- tree t;
-
- push_cp_function_context (NULL_TREE);
- push_to_top_level ();
-
- /* No need to mangle this. */
- push_lang_context (lang_name_c);
-
- interface_unknown = 1;
-
- params = void_list_node;
- /* tcf stands for throw clean funciton. */
- sprintf (name, "__tcf_%d", counter++);
- t = make_call_declarator (get_identifier (name), params, NULL_TREE,
- NULL_TREE);
- start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
- void_list_node),
- t, NULL_TREE, 0);
- store_parm_decls ();
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
- emit_line_note (input_filename, lineno);
-
- interface_unknown = old_interface_unknown;
-
- pop_lang_context ();
-
- return current_function_decl;
-}
-
-void
-end_anon_func ()
-{
- expand_end_bindings (getdecls (), 1, 0);
- poplevel (1, 0, 0);
- pop_momentary ();
-
- finish_function (lineno, 0, 0);
-
- pop_from_top_level ();
- pop_cp_function_context (NULL_TREE);
-}
-
-/* Expand a throw statement. This follows the following
- algorithm:
-
- 1. Allocate space to save the current PC onto the stack.
- 2. Generate and emit a label and save its address into the
- newly allocated stack space since we can't save the pc directly.
- 3. If this is the first call to throw in this function:
- generate a label for the throw block
- 4. jump to the throw block label. */
-
-void
-expand_throw (exp)
- tree exp;
-{
- rtx label;
-
- if (! doing_eh (1))
- return;
-
- if (exp)
- {
- tree throw_type;
- tree cleanup = empty_fndecl, e;
-
- /* throw expression */
- /* First, decay it. */
- exp = decay_conversion (exp);
-
- if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
- {
- throw_type = build_eh_type (exp);
- exp = build_reinterpret_cast (ptr_type_node, exp);
- }
- else
- {
- tree object;
-
- /* Make a copy of the thrown object. WP 15.1.5 */
- exp = build_new (NULL_TREE, TREE_TYPE (exp),
- build_tree_list (NULL_TREE, exp),
- 0);
-
- if (exp == error_mark_node)
- error (" in thrown expression");
-
- object = build_indirect_ref (exp, NULL_PTR);
- throw_type = build_eh_type (object);
-
- start_sequence ();
- object = build_reinterpret_cast (TREE_TYPE (exp), saved_throw_value);
- object = build_indirect_ref (object, NULL_PTR);
- cleanup = maybe_build_cleanup_and_delete (object);
- end_sequence ();
-
- if (cleanup)
- {
- cleanup = start_anon_func ();
-
- expand_expr (maybe_build_cleanup_and_delete (object),
- const0_rtx, VOIDmode, 0);
-
- end_anon_func ();
-
- mark_addressable (cleanup);
- }
- else
- {
- cleanup = empty_fndecl;
- }
- }
-
- if (cleanup == empty_fndecl)
- assemble_external (empty_fndecl);
-
- e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
- expand_expr (e, const0_rtx, VOIDmode, 0);
-
- e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
- e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
- expand_expr (e, const0_rtx, VOIDmode, 0);
-
- cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
- cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
- expand_expr (cleanup, const0_rtx, VOIDmode, 0);
- }
- else
- {
- /* rethrow current exception */
- /* This part is easy, as we don't have to do anything else. */
- }
-
- /* This is the label that represents where in the code we were, when
- we got an exception. This needs to be updated when we rethrow an
- exception, so that the matching routine knows to search out. */
- label = gen_label_rtx ();
- emit_label (label);
-
- expand_internal_throw (label);
-}
-
-/* Build a throw expression. */
-
-tree
-build_throw (e)
- tree e;
-{
- if (e != error_mark_node)
- {
- if (processing_template_decl)
- return build_min (THROW_EXPR, void_type_node, e);
- e = build1 (THROW_EXPR, void_type_node, e);
- TREE_SIDE_EFFECTS (e) = 1;
- TREE_USED (e) = 1;
- }
- return e;
-}