IA-64 ABI Exception Handling.
From-SVN: r40924
This commit is contained in:
parent
ce1c98ea45
commit
52a11cbfcf
114
gcc/ChangeLog
114
gcc/ChangeLog
@ -1,3 +1,117 @@
|
||||
2001-03-28 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* except.c: Rewrite entirely for IA-64 ABI exception handling.
|
||||
* except.h: Likewise.
|
||||
|
||||
* Makefile.in (LIB2ADDEH): Mention unwind-dw2*.c
|
||||
(LIB2ADDEHDEP): New.
|
||||
(LIB2FUNCS_EH): Remove.
|
||||
(LIB2ADD): Remove LIB2ADDEH.
|
||||
(libgcc.mk): Pass LIB2ADDEHDEP, don't pass LIB2FUNCS_EH.
|
||||
(LIBGCC_DEPS): Use LIB2ADDEHDEP.
|
||||
(crt{begin,end}[S].o): Likewise.
|
||||
(except.o): Update includes.
|
||||
* mklibgcc.in: Remove LIB2FUNCS_EH, add LIB2ADDEH, LIB2ADDEHDEP.
|
||||
(libgcc2_c_dep): Use LIB2ADDEHDEP.
|
||||
|
||||
* basic-block.h (struct basic_block_def): Remove eh_beg, eh_end.
|
||||
* bb-reorder.c (reorder_basic_blocks): Don't disable for EH.
|
||||
* builtins.def (BUILT_IN_EH_RETURN_DATA_REGNO): New.
|
||||
* builtins.c (expand_builtin): Implement it.
|
||||
[BUILT_IN_EH_RETURN]: Update for nr arguments change.
|
||||
* c-common.c (c_common_nodes_and_builtins): Declare it.
|
||||
* c-decl.c (init_decl_processing): Update __builtin_eh_return.
|
||||
* calls.c (libfunc_nothrow): Remove.
|
||||
(emit_library_call_value_1): Don't call it.
|
||||
* crtstuff.c: Include unwind-dw2-fde.h instead of frame.h.
|
||||
* dwarf2.h (dwarf_call_frame_info): Add dwarf2.1 elements.
|
||||
(DW_EH_PE_*): New defines for pointer encoding in .eh_frame.
|
||||
* dwarf2out.c (struct dw_fde_struct): Add uses_eh_lsda, funcdef_number.
|
||||
(current_funcdef_number): Globalize.
|
||||
(output_call_frame_info): Emit frame data if an lsda is needed.
|
||||
Generate augmentation for personality routine. Don't play with
|
||||
difference symbols.
|
||||
(dwarf2out_begin_prologue): Record funcdef_number.
|
||||
* dwarf2out.h (current_funcdef_number): Declare.
|
||||
* expr.c (expand_expr): Update for except.h name changes.
|
||||
Remove POPDCC_EXPR, POPDHC_EXPR. Add EXC_PTR_EXPR.
|
||||
* expr.h (LTI_throw, LTI_rethrow): Remove.
|
||||
(LTI_sjthrow, LTI_sjpopnthrow, LTI_terminate): Remove.
|
||||
(LTI_eh_rtime_match): Remove.
|
||||
(LTI_unwind_resume, LTI_eh_personality): Add.
|
||||
(LTI_unwind_sjlj_register, LTI_unwind_sjlj_unregister): Add.
|
||||
* final.c (final): Don't call check_exception_handler_labels,
|
||||
init_insn_eh_region, or free_insn_eh_region.
|
||||
(final_scan_insn): Always emit debug labels for
|
||||
NOTE_INSN_EH_REGION notes.
|
||||
* flags.h (flag_new_exceptions): Remove.
|
||||
* flow.c (entry_exit_blocks): Remove eh_beg, eh_end.
|
||||
(record_active_eh_regions): Remove.
|
||||
(count_basic_blocks): Check all instructions for REG_EH_REGION.
|
||||
Use can_throw_internal.
|
||||
(find_basic_blocks_1): Likewise.
|
||||
(move_stray_eh_region_notes): Remove.
|
||||
(find_label_refs): No eh_return_stub_label.
|
||||
(make_edges): Likewise. No init/free_eh_nesting_info. Handle RESX.
|
||||
(make_eh_edge): No eh_nest_info. Update for reachable_handlers
|
||||
changes.
|
||||
(delete_unreachable_blocks): Don't track deleted handlers.
|
||||
(flow_delete_block): Use maybe_remove_eh_handler.
|
||||
(delete_eh_regions): Remove.
|
||||
(merge_blocks): Don't check for eh region match.
|
||||
(mark_regs_live_at_end): Handle EH_RETURN_DATA_REGNO,
|
||||
EH_RETURN_STACKADJ_RTX, EH_RETURN_HANDLER_RTX.
|
||||
(init_propagate_block_info): Disable dead frame store optimization
|
||||
when current_function_calls_eh_return.
|
||||
(dump_bb): Don't print eh_beg, eh_end.
|
||||
* function.c (fixup_var_refs): No catch_clauses.
|
||||
(expand_function_end): Likewise. Call expand_eh_return before
|
||||
the return register use. Call sjlj_emit_function_exit_after.
|
||||
(expand_function_start): Force pseudo DECL_RESULT if sjlj exceptions.
|
||||
* function.h (struct function): Add calls_eh_return, uses_eh_lsda.
|
||||
* ifcvt.c (dead_or_predicable): Remove eh region check.
|
||||
* integrate.c (function_cannot_inline_p): Disallow __builtin_eh_return.
|
||||
Don't check for EH vs parameters.
|
||||
(expand_inline_function_eh_labelmap, eif_eh_map): Remove.
|
||||
(expand_inline_function): Call duplicate_eh_regions.
|
||||
(copy_insn_list): Don't handle NOTE_INSN_EH_REGION_BEG/END.
|
||||
(copy_insn_notes): Remap REG_EH_REGION notes.
|
||||
(copy_rtx_and_substitute): Remove SYMBOL_REF_NEED_ADJUST check.
|
||||
* integrate.h (struct inline_remap): Add local_return_label.
|
||||
* jump.c (jump_optimize_1): Don't init/free_insn_eh_region, nor
|
||||
check_exception_handler_labels, nor exception_optimize.
|
||||
(find_cross_jump): No EH region check.
|
||||
* optabs.c (init_optabs): Update for changed eh libfuncs.
|
||||
* rtl.def (RESX): New.
|
||||
* rtl.h (SYMBOL_REF_NEED_ADJUST): Remove.
|
||||
* stmt.c (expand_decl_cleanup): Simplify using_eh_for_cleanups_p
|
||||
checks. Update for except.h name changes.
|
||||
(expand_cleanups): Likewise.
|
||||
(expand_dcc_cleanup, expand_dhc_cleanup): Remove.
|
||||
* toplev.c (dump_file_index, dump_file): Add .02.eh dump.
|
||||
(compile_file): Call init_eh before init_optabs. Don't
|
||||
output_exception_table here.
|
||||
(rest_of_compilation): Call convert_from_eh_region_ranges,
|
||||
convert_to_eh_region_ranges, output_function_exception_table.
|
||||
Don't emit_eh_context.
|
||||
* tree.def (POPDHC_EXPR, POPDCC_EXPR): Remove.
|
||||
(EXC_PTR_EXPR): New.
|
||||
|
||||
* md.texi (eh_epilogue): Remove.
|
||||
(eh_return): Document.
|
||||
* tm.texi (EH_RETURN_DATA_REGNO): Document.
|
||||
(EH_RETURN_STACKADJ_RTX, EH_RETURN_HANDLER_RTX): Document.
|
||||
|
||||
* eh-common.h: Remove file.
|
||||
* frame-dwarf2.c, frame.c, frame.h: Remove files.
|
||||
* libgcc2.c (L_eh): Remove.
|
||||
|
||||
* unwind-dw2-fde.c: New file, largely copied from frame.c.
|
||||
* unwind-dw2-fde.h: New file.
|
||||
* unwind-dw2.c: New file, largely cribbed from frame-dwarf2.c.
|
||||
* unwind-sjlj.c, unwind.h, unwind.inc: New files.
|
||||
* libgcc-std.ver: Update for eh symbols.
|
||||
|
||||
2001-03-27 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* regmove.c (perhaps_ends_bb_p): Use can_throw_internal to
|
||||
|
@ -397,8 +397,10 @@ LIBGCC2_INCLUDES =
|
||||
# Additional target-dependent options for compiling libgcc2.a.
|
||||
TARGET_LIBGCC2_CFLAGS =
|
||||
|
||||
# Additional sources to handle exceptions; overridden by some targets.
|
||||
LIB2ADDEH = $(srcdir)/frame-dwarf2.c
|
||||
# Additional sources to handle exceptions; overridden on ia64.
|
||||
LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \
|
||||
$(srcdir)/unwind-sjlj.c
|
||||
LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h
|
||||
|
||||
# libgcc1-test target (must also be overridable for a target)
|
||||
LIBGCC1_TEST = libgcc1-test
|
||||
@ -794,8 +796,6 @@ LIB2FUNCS = _muldi3 _divdi3 _moddi3 _udivdi3 _umoddi3 _negdi2 \
|
||||
_mulvsi3 _mulvdi3 _negvsi2 _negvdi2 \
|
||||
_ctors
|
||||
|
||||
LIB2FUNCS_EH = _eh
|
||||
|
||||
FPBIT_FUNCS = _pack_sf _unpack_sf _addsub_sf _mul_sf _div_sf \
|
||||
_fpcmp_parts_sf _compare_sf _eq_sf _ne_sf _gt_sf _ge_sf \
|
||||
_lt_sf _le_sf _unord_sf _si_to_sf _sf_to_si _negate_sf _make_sf \
|
||||
@ -1033,7 +1033,7 @@ xlimits.h: glimits.h limitx.h limity.h
|
||||
#
|
||||
# Build libgcc.a.
|
||||
|
||||
LIB2ADD = $(LIB2ADDEH) $(LIB2FUNCS_EXTRA)
|
||||
LIB2ADD = $(LIB2FUNCS_EXTRA)
|
||||
|
||||
libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) xgcc$(exeext)
|
||||
objext='$(objext)' \
|
||||
@ -1043,8 +1043,9 @@ libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) xgcc$(exeext)
|
||||
LIB1ASMFUNCS='$(LIB1ASMFUNCS)' \
|
||||
LIB1FUNCS_EXTRA='$(LIB1FUNCS_EXTRA)' \
|
||||
LIB2FUNCS='$(LIB2FUNCS)' \
|
||||
LIB2FUNCS_EH='$(LIB2FUNCS_EH)' \
|
||||
LIB2ADD='$(LIB2ADD)' \
|
||||
LIB2ADDEH='$(LIB2ADDEH)' \
|
||||
LIB2ADDEHDEP='$(LIB2ADDEHDEP)' \
|
||||
FPBIT='$(FPBIT)' \
|
||||
FPBIT_FUNCS='$(FPBIT_FUNCS)' \
|
||||
DPBIT='$(DPBIT)' \
|
||||
@ -1064,8 +1065,9 @@ libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) xgcc$(exeext)
|
||||
# All the things that might cause us to want to recompile bits of libgcc.
|
||||
LIBGCC_DEPS = $(GCC_PASSES) $(LANGUAGES) stmp-int-hdrs $(STMP_FIXPROTO) \
|
||||
libgcc.mk $(srcdir)/libgcc1.c $(srcdir)/libgcc2.c $(TCONFIG_H) \
|
||||
$(MACHMODE_H) longlong.h frame.h gbl-ctors.h config.status \
|
||||
stmp-int-hdrs tsystem.h $(FPBIT) $(DPBIT) $(LIB2ADD) $(EXTRA_PARTS)
|
||||
$(MACHMODE_H) longlong.h gbl-ctors.h config.status stmp-int-hdrs \
|
||||
tsystem.h $(FPBIT) $(DPBIT) $(LIB2ADD) $(LIB2ADDEH) $(LIB2ADDEHDEP) \
|
||||
$(EXTRA_PARTS)
|
||||
|
||||
libgcc.a: $(LIBGCC_DEPS)
|
||||
$(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
|
||||
@ -1125,14 +1127,14 @@ stmp-multilib: $(LIBGCC_DEPS)
|
||||
# linked using GCC on systems using COFF or ELF, for the sake of C++
|
||||
# constructors.
|
||||
$(T)crtbegin.o: crtstuff.c $(GCC_PASSES) $(TCONFIG_H) auto-host.h \
|
||||
frame.h gbl-ctors.h stmp-int-hdrs tsystem.h
|
||||
gbl-ctors.h stmp-int-hdrs tsystem.h
|
||||
$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \
|
||||
-finhibit-size-directive -fno-inline-functions \
|
||||
-fno-exceptions $(CRTSTUFF_T_CFLAGS) @inhibit_libc@ \
|
||||
-c $(srcdir)/crtstuff.c -DCRT_BEGIN -o $(T)crtbegin$(objext)
|
||||
|
||||
$(T)crtend.o: crtstuff.c $(GCC_PASSES) $(TCONFIG_H) auto-host.h \
|
||||
frame.h gbl-ctors.h stmp-int-hdrs tsystem.h
|
||||
gbl-ctors.h stmp-int-hdrs tsystem.h
|
||||
$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \
|
||||
-finhibit-size-directive -fno-inline-functions \
|
||||
-fno-exceptions $(CRTSTUFF_T_CFLAGS) @inhibit_libc@ \
|
||||
@ -1140,7 +1142,7 @@ $(T)crtend.o: crtstuff.c $(GCC_PASSES) $(TCONFIG_H) auto-host.h \
|
||||
|
||||
# These are versions of crtbegin and crtend for shared libraries.
|
||||
$(T)crtbeginS.o: crtstuff.c $(GCC_PASSES) $(TCONFIG_H) auto-host.h \
|
||||
frame.h gbl-ctors.h stmp-int-hdrs tsystem.h
|
||||
gbl-ctors.h stmp-int-hdrs tsystem.h
|
||||
$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \
|
||||
-finhibit-size-directive -fno-inline-functions \
|
||||
-fno-exceptions $(CRTSTUFF_T_CFLAGS_S) @inhibit_libc@ \
|
||||
@ -1148,7 +1150,7 @@ $(T)crtbeginS.o: crtstuff.c $(GCC_PASSES) $(TCONFIG_H) auto-host.h \
|
||||
-o $(T)crtbeginS$(objext)
|
||||
|
||||
$(T)crtendS.o: crtstuff.c $(GCC_PASSES) $(TCONFIG_H) auto-host.h \
|
||||
frame.h gbl-ctors.h stmp-int-hdrs tsystem.h
|
||||
gbl-ctors.h stmp-int-hdrs tsystem.h
|
||||
$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \
|
||||
-finhibit-size-directive -fno-inline-functions \
|
||||
-fno-exceptions $(CRTSTUFF_T_CFLAGS_S) @inhibit_libc@ \
|
||||
@ -1394,8 +1396,9 @@ stmt.o : stmt.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h function.h \
|
||||
insn-config.h hard-reg-set.h $(EXPR_H) except.h \
|
||||
$(LOOP_H) $(RECOG_H) toplev.h output.h varray.h $(GGC_H) $(TM_P_H)
|
||||
except.o : except.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
|
||||
function.h $(EXPR_H) $(REGS_H) hard-reg-set.h \
|
||||
insn-config.h $(RECOG_H) output.h except.h toplev.h intl.h $(GGC_H) $(TM_P_H)
|
||||
except.h function.h $(EXPR_H) integrate.h \
|
||||
insn-config.h hard-reg-set.h $(BASIC_BLOCK_H) output.h \
|
||||
dwarf2asm.h dwarf2out.h toplev.h $(HASHTAB_H) intl.h $(GGC_H)
|
||||
expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h function.h \
|
||||
$(REGS_H) $(EXPR_H) insn-config.h $(RECOG_H) \
|
||||
output.h typeclass.h hard-reg-set.h toplev.h hard-reg-set.h except.h \
|
||||
@ -1414,7 +1417,7 @@ explow.o : explow.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
|
||||
toplev.h function.h $(TM_P_H)
|
||||
optabs.o : optabs.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
|
||||
insn-config.h $(EXPR_H) $(RECOG_H) reload.h \
|
||||
toplev.h $(GGC_H) real.h $(TM_P_H)
|
||||
toplev.h $(GGC_H) real.h $(TM_P_H) except.h
|
||||
dbxout.o : dbxout.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(RTL_H) flags.h $(REGS_H) \
|
||||
insn-config.h reload.h gstab.h xcoffout.h output.h dbxout.h toplev.h \
|
||||
$(TM_P_H)
|
||||
|
@ -174,14 +174,12 @@ typedef struct basic_block_def {
|
||||
|
||||
/* The index of this block. */
|
||||
int index;
|
||||
/* The loop depth of this block plus one. */
|
||||
|
||||
/* The loop depth of this block. */
|
||||
int loop_depth;
|
||||
|
||||
/* The active eh region before head and after end. */
|
||||
int eh_beg, eh_end;
|
||||
|
||||
int count; /* Expected number of executions: calculated in
|
||||
profile.c */
|
||||
/* Expected number of executions: calculated in profile.c. */
|
||||
int count;
|
||||
} *basic_block;
|
||||
|
||||
/* Number of basic blocks in the current function. */
|
||||
|
@ -92,7 +92,6 @@
|
||||
#include "flags.h"
|
||||
#include "output.h"
|
||||
#include "function.h"
|
||||
#include "except.h"
|
||||
#include "toplev.h"
|
||||
#include "recog.h"
|
||||
#include "expr.h"
|
||||
@ -395,8 +394,6 @@ make_reorder_chain_1 (bb, prev)
|
||||
taken = probability > REG_BR_PROB_BASE / 2;
|
||||
|
||||
/* Find the normal taken edge and the normal fallthru edge.
|
||||
Note that there may in fact be other edges due to
|
||||
flag_non_call_exceptions.
|
||||
|
||||
Note, conditional jumps with other side effects may not
|
||||
be fully optimized. In this case it is possible for
|
||||
@ -1356,17 +1353,6 @@ reorder_basic_blocks ()
|
||||
if (n_basic_blocks <= 1)
|
||||
return;
|
||||
|
||||
/* We do not currently handle correct re-placement of EH notes.
|
||||
But that does not matter unless we intend to use them. */
|
||||
if (flag_exceptions)
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
{
|
||||
edge e;
|
||||
for (e = BASIC_BLOCK (i)->succ; e ; e = e->succ_next)
|
||||
if (e->flags & EDGE_EH)
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
BASIC_BLOCK (i)->aux = xcalloc (1, sizeof (struct reorder_block_def));
|
||||
|
||||
|
@ -3605,9 +3605,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
||||
return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
|
||||
case BUILT_IN_EH_RETURN:
|
||||
expand_builtin_eh_return (TREE_VALUE (arglist),
|
||||
TREE_VALUE (TREE_CHAIN (arglist)),
|
||||
TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))));
|
||||
TREE_VALUE (TREE_CHAIN (arglist)));
|
||||
return const0_rtx;
|
||||
#ifdef EH_RETURN_DATA_REGNO
|
||||
case BUILT_IN_EH_RETURN_DATA_REGNO:
|
||||
return expand_builtin_eh_return_data_regno (arglist);
|
||||
#endif
|
||||
case BUILT_IN_VARARGS_START:
|
||||
return expand_builtin_va_start (0, arglist);
|
||||
case BUILT_IN_STDARG_START:
|
||||
|
@ -97,6 +97,7 @@ DEF_BUILTIN(BUILT_IN_INIT_DWARF_REG_SIZES)
|
||||
DEF_BUILTIN(BUILT_IN_FROB_RETURN_ADDR)
|
||||
DEF_BUILTIN(BUILT_IN_EXTRACT_RETURN_ADDR)
|
||||
DEF_BUILTIN(BUILT_IN_EH_RETURN)
|
||||
DEF_BUILTIN(BUILT_IN_EH_RETURN_DATA_REGNO)
|
||||
|
||||
DEF_BUILTIN(BUILT_IN_VARARGS_START)
|
||||
DEF_BUILTIN(BUILT_IN_STDARG_START)
|
||||
|
@ -3146,6 +3146,11 @@ c_common_nodes_and_builtins ()
|
||||
builtin_function ("__builtin_frame_address", ptr_ftype_unsigned,
|
||||
BUILT_IN_FRAME_ADDRESS, BUILT_IN_NORMAL, NULL_PTR);
|
||||
|
||||
#ifdef EH_RETURN_DATA_REGNO
|
||||
builtin_function ("__builtin_eh_return_data_regno", int_ftype_int,
|
||||
BUILT_IN_EH_RETURN_DATA_REGNO, BUILT_IN_NORMAL, NULL_PTR);
|
||||
#endif
|
||||
|
||||
builtin_function ("__builtin_alloca", ptr_ftype_sizetype,
|
||||
BUILT_IN_ALLOCA, BUILT_IN_NORMAL, "alloca");
|
||||
builtin_function_2 ("__builtin_ffs", "ffs",
|
||||
|
@ -3084,12 +3084,11 @@ init_decl_processing ()
|
||||
builtin_function
|
||||
("__builtin_eh_return",
|
||||
build_function_type (void_type_node,
|
||||
tree_cons (NULL_TREE, ptr_type_node,
|
||||
tree_cons (NULL_TREE,
|
||||
type_for_mode (ptr_mode, 0),
|
||||
tree_cons (NULL_TREE,
|
||||
type_for_mode (ptr_mode, 0),
|
||||
tree_cons (NULL_TREE,
|
||||
ptr_type_node,
|
||||
endlink)))),
|
||||
ptr_type_node,
|
||||
endlink))),
|
||||
BUILT_IN_EH_RETURN, BUILT_IN_NORMAL, NULL_PTR);
|
||||
|
||||
pedantic_lvalues = pedantic;
|
||||
|
25
gcc/calls.c
25
gcc/calls.c
@ -204,7 +204,6 @@ static void compute_argument_addresses PARAMS ((struct arg_data *,
|
||||
static rtx rtx_for_function_call PARAMS ((tree, tree));
|
||||
static void load_register_parameters PARAMS ((struct arg_data *,
|
||||
int, rtx *, int));
|
||||
static int libfunc_nothrow PARAMS ((rtx));
|
||||
static rtx emit_library_call_value_1 PARAMS ((int, rtx, rtx,
|
||||
enum libcall_type,
|
||||
enum machine_mode,
|
||||
@ -3444,22 +3443,6 @@ expand_call (exp, target, ignore)
|
||||
return target;
|
||||
}
|
||||
|
||||
/* Returns nonzero if FUN is the symbol for a library function which can
|
||||
not throw. */
|
||||
|
||||
static int
|
||||
libfunc_nothrow (fun)
|
||||
rtx fun;
|
||||
{
|
||||
if (fun == throw_libfunc
|
||||
|| fun == rethrow_libfunc
|
||||
|| fun == sjthrow_libfunc
|
||||
|| fun == sjpopnthrow_libfunc)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Output a library call to function FUN (a SYMBOL_REF rtx).
|
||||
The RETVAL parameter specifies whether return value needs to be saved, other
|
||||
parameters are documented in the emit_library_call function bellow. */
|
||||
@ -3501,7 +3484,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
|
||||
rtx valreg;
|
||||
int pcc_struct_value = 0;
|
||||
int struct_value_size = 0;
|
||||
int flags = 0;
|
||||
int flags;
|
||||
int reg_parm_stack_space = 0;
|
||||
int needed;
|
||||
rtx before_call;
|
||||
@ -3525,6 +3508,9 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* No library functions can throw. */
|
||||
flags = ECF_NOTHROW;
|
||||
|
||||
if (fn_type == LCT_CONST_MAKE_BLOCK)
|
||||
flags |= ECF_CONST;
|
||||
else if (fn_type == LCT_PURE_MAKE_BLOCK)
|
||||
@ -3533,9 +3519,6 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
|
||||
flags |= ECF_NORETURN;
|
||||
fun = orgfun;
|
||||
|
||||
if (libfunc_nothrow (fun))
|
||||
flags |= ECF_NOTHROW;
|
||||
|
||||
#ifdef PREFERRED_STACK_BOUNDARY
|
||||
/* Ensure current function's preferred stack boundary is at least
|
||||
what we need. */
|
||||
|
@ -1,3 +1,59 @@
|
||||
2001-03-28 Richard Henderson <rth@redhat.com>
|
||||
|
||||
IA-64 ABI Exception Handling:
|
||||
* cp-tree.def (EH_SPEC_BLOCK): New.
|
||||
(MUST_NOT_THROW_EXPR): New.
|
||||
* cp-tree.h: Update changed function declarations.
|
||||
(CPTI_PUSH_EXCEPTION_IDENTIFIER): Remove.
|
||||
(CPTI_CALL_UNEXPECTED): New.
|
||||
(struct cp_language_function): Rename x_eh_spec_try_block
|
||||
to x_eh_spec_block.
|
||||
(EH_SPEC_STMTS, EH_SPEC_RAISES): New.
|
||||
* decl.c (current_binding_level): If no current function
|
||||
bindings, revert to scope_chain.
|
||||
(initialize_predefined_identifiers): Remove __cp_push_exception.
|
||||
(store_parm_decls): Use begin_eh_spec_block.
|
||||
(finish_function): Use finish_eh_spec_block.
|
||||
(mark_lang_function): Update for name changes.
|
||||
* decl2.c (finish_file): No mark_all_runtime_matches.
|
||||
* dump.c (cp_dump_tree): Handle new tree codes.
|
||||
* error.c (dump_expr) [BIND_EXPR]: Fix typo.
|
||||
* except.c (catch_language_init, catch_language): Remove.
|
||||
(init_exception_processing): Don't set language code.
|
||||
Initialize call_unexpected_node, protect_cleanup_actions,
|
||||
eh_personality_libfunc, lang_eh_runtime_type.
|
||||
(call_eh_info, push_eh_info, get_eh_info, get_eh_value): Remove.
|
||||
(get_eh_type, get_eh_caught, get_eh_handlers): Remove.
|
||||
(prepare_eh_type): Split out type canonicalizations ...
|
||||
(build_eh_type_type): ... from here.
|
||||
(build_eh_type_type_ref): Remove.
|
||||
(mark_all_runtime_matches): Remove.
|
||||
(build_exc_ptr): New.
|
||||
(do_begin_catch, do_end_catch): New.
|
||||
(do_pop_exception): Remove.
|
||||
(build_terminate_handler): Remove.
|
||||
(choose_personality_routine): Split out language choice from ...
|
||||
(initialize_handler_parm): ... here.
|
||||
Use MUST_NOT_THROW_EXPR.
|
||||
(expand_start_catch_block): Use do_begin_catch. Simplify Java
|
||||
exception object handling.
|
||||
(expand_start_eh_spec, expand_end_eh_spec): Remove.
|
||||
(expand_exception_blocks, alloc_eh_object): Remove.
|
||||
(begin_eh_spec_block, finish_eh_spec_block): New.
|
||||
(do_allocate_exception, do_free_exception): New.
|
||||
(expand_throw): Merge into ...
|
||||
(build_throw): ... here. Update for abi.
|
||||
* expr.c (cplus_expand_expr): No expand_internal_throw.
|
||||
Handle MUST_NOT_THROW_EXPR.
|
||||
* pt.c (tsubst_expr): Handle EH_SPEC_BLOCK.
|
||||
* semantics.c (*) Update for except.h name changes.
|
||||
(genrtl_try_block): No protect_with_terminate.
|
||||
(genrtl_eh_spec_block): New.
|
||||
(genrtl_handler): Don't emit the goto here.
|
||||
(cp_expand_stmt): Handle EH_SPEC_BLOCK.
|
||||
(genrtl_finish_function): Don't expand_exception_blocks.
|
||||
* tree.c (cp_statement_code_p): Handle EH_SPEC_BLOCK.
|
||||
|
||||
2001-03-28 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* decl.c (struct named_label_list): Rename eh_region to
|
||||
|
@ -236,8 +236,13 @@ DEFTREECODE (START_CATCH_STMT, "start_catch_stmt", 'e', 0)
|
||||
DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
|
||||
DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
|
||||
DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2)
|
||||
DEFTREECODE (EH_SPEC_BLOCK, "eh_spec_block", 'e', 2)
|
||||
DEFTREECODE (HANDLER, "handler", 'e', 2)
|
||||
|
||||
/* A MUST_NOT_THROW_EXPR wraps an expression that may not
|
||||
throw, and must call terminate if it does. */
|
||||
DEFTREECODE (MUST_NOT_THROW_EXPR, "must_not_throw_expr", 'e', 1)
|
||||
|
||||
DEFTREECODE (TAG_DEFN, "tag_defn", 'e', 0)
|
||||
|
||||
/* And some codes for expressing conversions for overload resolution. */
|
||||
|
@ -616,7 +616,6 @@ enum cp_tree_index
|
||||
CPTI_PFN_IDENTIFIER,
|
||||
CPTI_PFN_OR_DELTA2_IDENTIFIER,
|
||||
CPTI_VPTR_IDENTIFIER,
|
||||
CPTI_PUSH_EXCEPTION_IDENTIFIER,
|
||||
CPTI_STD_IDENTIFIER,
|
||||
|
||||
CPTI_LANG_NAME_C,
|
||||
@ -627,6 +626,7 @@ enum cp_tree_index
|
||||
CPTI_NULL,
|
||||
CPTI_JCLASS,
|
||||
CPTI_TERMINATE,
|
||||
CPTI_CALL_UNEXPECTED,
|
||||
CPTI_ATEXIT,
|
||||
CPTI_DSO_HANDLE,
|
||||
CPTI_DCAST,
|
||||
@ -740,9 +740,6 @@ extern tree cp_global_trees[CPTI_MAX];
|
||||
#define pfn_identifier cp_global_trees[CPTI_PFN_IDENTIFIER]
|
||||
#define pfn_or_delta2_identifier cp_global_trees[CPTI_PFN_OR_DELTA2_IDENTIFIER]
|
||||
#define vptr_identifier cp_global_trees[CPTI_VPTR_IDENTIFIER]
|
||||
/* The name of the function to call to push an exception onto the
|
||||
exception stack. */
|
||||
#define cp_push_exception_identifier cp_global_trees[CPTI_PUSH_EXCEPTION_IDENTIFIER]
|
||||
/* The name of the std namespace. */
|
||||
#define std_identifier cp_global_trees[CPTI_STD_IDENTIFIER]
|
||||
#define lang_name_c cp_global_trees[CPTI_LANG_NAME_C]
|
||||
@ -761,6 +758,9 @@ extern tree cp_global_trees[CPTI_MAX];
|
||||
/* The declaration for `std::terminate'. */
|
||||
#define terminate_node cp_global_trees[CPTI_TERMINATE]
|
||||
|
||||
/* The declaration for "__cxa_call_unexpected". */
|
||||
#define call_unexpected_node cp_global_trees[CPTI_CALL_UNEXPECTED]
|
||||
|
||||
/* A pointer to `std::atexit'. */
|
||||
#define atexit_node cp_global_trees[CPTI_ATEXIT]
|
||||
|
||||
@ -872,7 +872,7 @@ struct cp_language_function
|
||||
tree x_dtor_label;
|
||||
tree x_current_class_ptr;
|
||||
tree x_current_class_ref;
|
||||
tree x_eh_spec_try_block;
|
||||
tree x_eh_spec_block;
|
||||
tree x_in_charge_parm;
|
||||
tree x_vtt_parm;
|
||||
|
||||
@ -916,10 +916,10 @@ struct cp_language_function
|
||||
#define current_class_ref \
|
||||
(cfun ? cp_function_chain->x_current_class_ref : NULL_TREE)
|
||||
|
||||
/* The TRY_BLOCK for the exception-specifiers for the current
|
||||
/* The EH_SPEC_BLOCK for the exception-specifiers for the current
|
||||
function, if any. */
|
||||
|
||||
#define current_eh_spec_try_block cp_function_chain->x_eh_spec_try_block
|
||||
#define current_eh_spec_block cp_function_chain->x_eh_spec_block
|
||||
|
||||
/* The `__in_chrg' parameter for the current function. Only used for
|
||||
constructors and destructors. */
|
||||
@ -3035,6 +3035,9 @@ extern int flag_new_for_scope;
|
||||
#define TRY_STMTS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 0)
|
||||
#define TRY_HANDLERS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 1)
|
||||
|
||||
#define EH_SPEC_STMTS(NODE) TREE_OPERAND (EH_SPEC_BLOCK_CHECK (NODE), 0)
|
||||
#define EH_SPEC_RAISES(NODE) TREE_OPERAND (EH_SPEC_BLOCK_CHECK (NODE), 1)
|
||||
|
||||
/* Nonzero if this try block is a function try block. */
|
||||
#define FN_TRY_BLOCK_P(NODE) TREE_LANG_FLAG_3 (TRY_BLOCK_CHECK (NODE))
|
||||
#define HANDLER_PARMS(NODE) TREE_OPERAND (HANDLER_CHECK (NODE), 0)
|
||||
@ -4000,9 +4003,9 @@ extern void init_exception_processing PARAMS ((void));
|
||||
extern tree expand_start_catch_block PARAMS ((tree));
|
||||
extern void expand_end_catch_block PARAMS ((tree));
|
||||
extern void expand_builtin_throw PARAMS ((void));
|
||||
extern tree expand_start_eh_spec PARAMS ((void));
|
||||
extern void expand_end_eh_spec PARAMS ((tree, tree));
|
||||
extern void expand_eh_spec_block PARAMS ((tree));
|
||||
extern void expand_exception_blocks PARAMS ((void));
|
||||
extern tree build_exc_ptr PARAMS ((void));
|
||||
extern tree build_throw PARAMS ((tree));
|
||||
extern void mark_all_runtime_matches PARAMS ((void));
|
||||
extern int nothrow_libfn_p PARAMS ((tree));
|
||||
@ -4256,6 +4259,8 @@ extern tree finish_case_label PARAMS ((tree, tree));
|
||||
extern tree finish_goto_stmt PARAMS ((tree));
|
||||
extern tree begin_try_block PARAMS ((void));
|
||||
extern void finish_try_block PARAMS ((tree));
|
||||
extern tree begin_eh_spec_block PARAMS ((void));
|
||||
extern void finish_eh_spec_block PARAMS ((tree, tree));
|
||||
extern void finish_handler_sequence PARAMS ((tree));
|
||||
extern tree begin_function_try_block PARAMS ((void));
|
||||
extern void finish_function_try_block PARAMS ((tree));
|
||||
|
@ -478,7 +478,7 @@ struct binding_level
|
||||
/* The binding level currently in effect. */
|
||||
|
||||
#define current_binding_level \
|
||||
(cfun \
|
||||
(cfun && cp_function_chain->bindings \
|
||||
? cp_function_chain->bindings \
|
||||
: scope_chain->bindings)
|
||||
|
||||
@ -6306,7 +6306,6 @@ initialize_predefined_identifiers ()
|
||||
{ VTABLE_PFN_NAME, &pfn_identifier, 0 },
|
||||
{ "__pfn_or_delta2", &pfn_or_delta2_identifier, 0 },
|
||||
{ "_vptr", &vptr_identifier, 0 },
|
||||
{ "__cp_push_exception", &cp_push_exception_identifier, 0 },
|
||||
{ "__vtt_parm", &vtt_parm_identifier, 0 },
|
||||
{ "std", &std_identifier, 0 },
|
||||
{ NULL, NULL, 0 }
|
||||
@ -13721,7 +13720,7 @@ store_parm_decls (current_function_parms)
|
||||
if (flag_exceptions && !processing_template_decl
|
||||
&& flag_enforce_eh_specs
|
||||
&& TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
|
||||
current_eh_spec_try_block = expand_start_eh_spec ();
|
||||
current_eh_spec_block = begin_eh_spec_block ();
|
||||
}
|
||||
|
||||
|
||||
@ -13966,9 +13965,9 @@ finish_function (flags)
|
||||
if (flag_exceptions && !processing_template_decl
|
||||
&& flag_enforce_eh_specs
|
||||
&& TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
|
||||
expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS
|
||||
(TREE_TYPE (current_function_decl)),
|
||||
current_eh_spec_try_block);
|
||||
finish_eh_spec_block (TYPE_RAISES_EXCEPTIONS
|
||||
(TREE_TYPE (current_function_decl)),
|
||||
current_eh_spec_block);
|
||||
}
|
||||
|
||||
/* If we're saving up tree structure, tie off the function now. */
|
||||
@ -14395,7 +14394,7 @@ mark_lang_function (p)
|
||||
ggc_mark_tree (p->x_dtor_label);
|
||||
ggc_mark_tree (p->x_current_class_ptr);
|
||||
ggc_mark_tree (p->x_current_class_ref);
|
||||
ggc_mark_tree (p->x_eh_spec_try_block);
|
||||
ggc_mark_tree (p->x_eh_spec_block);
|
||||
ggc_mark_tree_varray (p->x_local_names);
|
||||
|
||||
mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
|
||||
|
@ -3621,10 +3621,6 @@ finish_file ()
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark all functions that might deal with exception-handling as
|
||||
referenced. */
|
||||
mark_all_runtime_matches ();
|
||||
|
||||
/* We lie to the back-end, pretending that some functions are
|
||||
not defined when they really are. This keeps these functions
|
||||
from being put out unnecessarily. But, we must stop lying
|
||||
|
@ -188,6 +188,13 @@ cp_dump_tree (di, t)
|
||||
dump_next_stmt (di, t);
|
||||
break;
|
||||
|
||||
case EH_SPEC_BLOCK:
|
||||
dump_stmt (di, t);
|
||||
dump_child ("body", EH_SPEC_STMTS (t));
|
||||
dump_child ("raises", EH_SPEC_RAISES (t));
|
||||
dump_next_stmt (di, t);
|
||||
break;
|
||||
|
||||
case PTRMEM_CST:
|
||||
dump_child ("clas", PTRMEM_CST_CLASS (t));
|
||||
dump_child ("mbr", PTRMEM_CST_MEMBER (t));
|
||||
@ -227,6 +234,12 @@ cp_dump_tree (di, t)
|
||||
dump_next_stmt (di, t);
|
||||
break;
|
||||
|
||||
case MUST_NOT_THROW_EXPR:
|
||||
dump_stmt (di, t);
|
||||
dump_child ("body", TREE_OPERAND (t, 0));
|
||||
dump_next_stmt (di, t);
|
||||
break;
|
||||
|
||||
case SUBOBJECT:
|
||||
dump_stmt (di, t);
|
||||
dump_child ("clnp", TREE_OPERAND (t, 0));
|
||||
|
@ -2104,7 +2104,7 @@ dump_expr (t, flags)
|
||||
break;
|
||||
|
||||
case BIND_EXPR:
|
||||
output_add_character (scratch_buffer, '}');
|
||||
output_add_character (scratch_buffer, '{');
|
||||
dump_expr (TREE_OPERAND (t, 1), flags & ~TFF_EXPR_IN_PARENS);
|
||||
output_add_character (scratch_buffer, '}');
|
||||
break;
|
||||
|
996
gcc/cp/except.c
996
gcc/cp/except.c
File diff suppressed because it is too large
Load Diff
@ -88,6 +88,7 @@ cplus_expand_expr (exp, target, tmode, modifier)
|
||||
tree type = TREE_TYPE (exp);
|
||||
register enum machine_mode mode = TYPE_MODE (type);
|
||||
register enum tree_code code = TREE_CODE (exp);
|
||||
rtx ret;
|
||||
|
||||
/* No sense saving up arithmetic to be done
|
||||
if it's all in the wrong mode to form part of an address.
|
||||
@ -103,16 +104,19 @@ cplus_expand_expr (exp, target, tmode, modifier)
|
||||
target, tmode, modifier);
|
||||
|
||||
case OFFSET_REF:
|
||||
{
|
||||
return expand_expr (default_conversion (resolve_offset_ref (exp)),
|
||||
target, tmode, EXPAND_NORMAL);
|
||||
}
|
||||
return expand_expr (default_conversion (resolve_offset_ref (exp)),
|
||||
target, tmode, EXPAND_NORMAL);
|
||||
|
||||
case THROW_EXPR:
|
||||
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
|
||||
expand_internal_throw ();
|
||||
return NULL;
|
||||
|
||||
case MUST_NOT_THROW_EXPR:
|
||||
expand_eh_region_start ();
|
||||
ret = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
|
||||
expand_eh_region_end_must_not_throw (build_call (terminate_node, 0));
|
||||
return ret;
|
||||
|
||||
case EMPTY_CLASS_EXPR:
|
||||
/* We don't need to generate any code for an empty class. */
|
||||
return const0_rtx;
|
||||
|
@ -51,6 +51,7 @@ static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
|
||||
static void deferred_type_access_control PARAMS ((void));
|
||||
static void emit_associated_thunks PARAMS ((tree));
|
||||
static void genrtl_try_block PARAMS ((tree));
|
||||
static void genrtl_eh_spec_block PARAMS ((tree));
|
||||
static void genrtl_handler PARAMS ((tree));
|
||||
static void genrtl_catch_block PARAMS ((tree));
|
||||
static void genrtl_ctor_stmt PARAMS ((tree));
|
||||
@ -575,14 +576,14 @@ genrtl_try_block (t)
|
||||
{
|
||||
expand_eh_region_start ();
|
||||
expand_stmt (TRY_STMTS (t));
|
||||
expand_eh_region_end (protect_with_terminate (TRY_HANDLERS (t)));
|
||||
expand_eh_region_end_cleanup (TRY_HANDLERS (t));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!FN_TRY_BLOCK_P (t))
|
||||
emit_line_note (input_filename, lineno);
|
||||
expand_start_try_stmts ();
|
||||
|
||||
expand_eh_region_start ();
|
||||
expand_stmt (TRY_STMTS (t));
|
||||
|
||||
if (FN_TRY_BLOCK_P (t))
|
||||
@ -603,6 +604,21 @@ genrtl_try_block (t)
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate the RTL for T, which is an EH_SPEC_BLOCK. */
|
||||
|
||||
static void
|
||||
genrtl_eh_spec_block (t)
|
||||
tree t;
|
||||
{
|
||||
expand_eh_region_start ();
|
||||
expand_stmt (EH_SPEC_STMTS (t));
|
||||
expand_eh_region_end_allowed (EH_SPEC_RAISES (t),
|
||||
build_call (call_unexpected_node,
|
||||
tree_cons (NULL_TREE,
|
||||
build_exc_ptr (),
|
||||
NULL_TREE)));
|
||||
}
|
||||
|
||||
/* Begin a try-block. Returns a newly-created TRY_BLOCK if
|
||||
appropriate. */
|
||||
|
||||
@ -706,13 +722,7 @@ genrtl_handler (t)
|
||||
genrtl_do_pushlevel ();
|
||||
expand_stmt (HANDLER_BODY (t));
|
||||
if (!processing_template_decl)
|
||||
{
|
||||
/* 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));
|
||||
end_catch_handler ();
|
||||
}
|
||||
expand_end_catch ();
|
||||
}
|
||||
|
||||
/* Begin a handler. Returns a HANDLER if appropriate. */
|
||||
@ -757,13 +767,13 @@ finish_handler_parms (decl, handler)
|
||||
return blocks;
|
||||
}
|
||||
|
||||
/* Generate the RTL for a CATCH_BLOCK. */
|
||||
/* Generate the RTL for a START_CATCH_STMT. */
|
||||
|
||||
static void
|
||||
genrtl_catch_block (type)
|
||||
tree type;
|
||||
{
|
||||
start_catch_handler (type);
|
||||
expand_start_catch (type);
|
||||
}
|
||||
|
||||
/* Note the beginning of a handler for TYPE. This function is called
|
||||
@ -2209,6 +2219,10 @@ cp_expand_stmt (t)
|
||||
genrtl_try_block (t);
|
||||
break;
|
||||
|
||||
case EH_SPEC_BLOCK:
|
||||
genrtl_eh_spec_block (t);
|
||||
break;
|
||||
|
||||
case HANDLER:
|
||||
genrtl_handler (t);
|
||||
break;
|
||||
@ -2615,9 +2629,6 @@ genrtl_finish_function (fn)
|
||||
&& ! DECL_NAME (DECL_RESULT (current_function_decl)))
|
||||
no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
|
||||
|
||||
if (flag_exceptions)
|
||||
expand_exception_blocks ();
|
||||
|
||||
/* If this function is supposed to return a value, ensure that
|
||||
we do not fall into the cleanups by mistake. The end of our
|
||||
function will look like this:
|
||||
|
@ -1037,6 +1037,7 @@ cp_statement_code_p (code)
|
||||
case RETURN_INIT:
|
||||
case TRY_BLOCK:
|
||||
case HANDLER:
|
||||
case EH_SPEC_BLOCK:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
|
@ -60,15 +60,15 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "auto-host.h"
|
||||
#include "tconfig.h"
|
||||
#include "tsystem.h"
|
||||
#include "frame.h"
|
||||
#include "unwind-dw2-fde.h"
|
||||
|
||||
#ifndef CRT_CALL_STATIC_FUNCTION
|
||||
# define CRT_CALL_STATIC_FUNCTION(func) func ()
|
||||
#endif
|
||||
|
||||
/* We do not want to add the weak attribute to the declarations of these
|
||||
routines in frame.h because that will cause the definition of these
|
||||
symbols to be weak as well.
|
||||
routines in unwind-dw2-fde.h because that will cause the definition of
|
||||
these symbols to be weak as well.
|
||||
|
||||
This exposes a core issue, how to handle creating weak references vs
|
||||
how to create weak definitions. Either we have to have the definition
|
||||
|
30
gcc/dwarf2.h
30
gcc/dwarf2.h
@ -501,9 +501,14 @@ enum dwarf_call_frame_info
|
||||
DW_CFA_def_cfa_offset = 0x0e,
|
||||
DW_CFA_def_cfa_expression = 0x0f,
|
||||
DW_CFA_expression = 0x10,
|
||||
/* Dwarf 2.1 */
|
||||
DW_CFA_offset_extended_sf = 0x11,
|
||||
DW_CFA_def_cfa_sf = 0x12,
|
||||
DW_CFA_def_cfa_offset_sf = 0x13,
|
||||
|
||||
/* SGI/MIPS specific */
|
||||
DW_CFA_MIPS_advance_loc8 = 0x1d,
|
||||
|
||||
|
||||
/* GNU extensions */
|
||||
DW_CFA_GNU_window_save = 0x2d,
|
||||
DW_CFA_GNU_args_size = 0x2e,
|
||||
@ -554,3 +559,26 @@ enum dwarf_macinfo_record_type
|
||||
DW_MACINFO_end_file = 4,
|
||||
DW_MACINFO_vendor_ext = 255
|
||||
};
|
||||
|
||||
|
||||
/* @@@ For use with GNU frame unwind information. */
|
||||
|
||||
#define DW_EH_PE_absptr 0x00
|
||||
#define DW_EH_PE_omit 0xff
|
||||
|
||||
#define DW_EH_PE_uleb128 0x01
|
||||
#define DW_EH_PE_udata2 0x02
|
||||
#define DW_EH_PE_udata4 0x03
|
||||
#define DW_EH_PE_udata8 0x04
|
||||
#define DW_EH_PE_sleb128 0x09
|
||||
#define DW_EH_PE_sdata2 0x0A
|
||||
#define DW_EH_PE_sdata4 0x0B
|
||||
#define DW_EH_PE_sdata8 0x0C
|
||||
#define DW_EH_PE_signed 0x08
|
||||
|
||||
#define DW_EH_PE_pcrel 0x10
|
||||
#define DW_EH_PE_textrel 0x20
|
||||
#define DW_EH_PE_datarel 0x30
|
||||
#define DW_EH_PE_funcrel 0x40
|
||||
|
||||
#define DW_EH_PE_indirect 0x80
|
||||
|
108
gcc/dwarf2out.c
108
gcc/dwarf2out.c
@ -44,6 +44,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "regs.h"
|
||||
#include "insn-config.h"
|
||||
#include "reload.h"
|
||||
#include "function.h"
|
||||
#include "output.h"
|
||||
#include "expr.h"
|
||||
#include "except.h"
|
||||
@ -150,7 +151,9 @@ typedef struct dw_fde_struct
|
||||
const char *dw_fde_current_label;
|
||||
const char *dw_fde_end;
|
||||
dw_cfi_ref dw_fde_cfi;
|
||||
int nothrow;
|
||||
unsigned funcdef_number;
|
||||
unsigned nothrow : 1;
|
||||
unsigned uses_eh_lsda : 1;
|
||||
}
|
||||
dw_fde_node;
|
||||
|
||||
@ -217,7 +220,7 @@ static dw_cfi_ref cie_cfi_head;
|
||||
maximum number of function definitions contained within the current
|
||||
compilation unit. These numbers are used to create unique label id's
|
||||
unique to each function definition. */
|
||||
static unsigned current_funcdef_number = 0;
|
||||
unsigned current_funcdef_number = 0;
|
||||
|
||||
/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram
|
||||
attribute that accelerates the lookup of the FDE associated
|
||||
@ -1684,22 +1687,22 @@ output_call_frame_info (for_eh)
|
||||
register dw_fde_ref fde;
|
||||
register dw_cfi_ref cfi;
|
||||
char l1[20], l2[20];
|
||||
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
|
||||
char ld[20];
|
||||
#endif
|
||||
|
||||
/* Do we want to include a pointer to the exception table? */
|
||||
int eh_ptr = for_eh && exception_table_p ();
|
||||
int any_lsda_needed = 0;
|
||||
char augmentation[6];
|
||||
|
||||
/* If we don't have any functions we'll want to unwind out of, don't
|
||||
emit any EH unwind information. */
|
||||
if (for_eh)
|
||||
{
|
||||
int any_eh_needed = 0;
|
||||
for (i = 0; i < fde_table_in_use; ++i)
|
||||
if (! fde_table[i].nothrow)
|
||||
goto found;
|
||||
return;
|
||||
found:;
|
||||
if (fde_table[i].uses_eh_lsda)
|
||||
any_eh_needed = any_lsda_needed = 1;
|
||||
else if (! fde_table[i].nothrow)
|
||||
any_eh_needed = 1;
|
||||
|
||||
if (! any_eh_needed)
|
||||
return;
|
||||
}
|
||||
|
||||
/* We're going to be generating comments, so turn on app. */
|
||||
@ -1726,14 +1729,8 @@ output_call_frame_info (for_eh)
|
||||
/* Output the CIE. */
|
||||
ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
|
||||
ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
|
||||
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
|
||||
ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, for_eh);
|
||||
dw2_asm_output_offset (for_eh ? 4 : DWARF_OFFSET_SIZE, ld,
|
||||
"Length of Common Information Entry");
|
||||
#else
|
||||
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
|
||||
"Length of Common Information Entry");
|
||||
#endif
|
||||
ASM_OUTPUT_LABEL (asm_out_file, l1);
|
||||
|
||||
/* Now that the CIE pointer is PC-relative for EH,
|
||||
@ -1744,20 +1741,23 @@ output_call_frame_info (for_eh)
|
||||
|
||||
dw2_asm_output_data (1, DW_CIE_VERSION, "CIE Version");
|
||||
|
||||
if (eh_ptr)
|
||||
augmentation[0] = 0;
|
||||
if (for_eh)
|
||||
{
|
||||
/* The CIE contains a pointer to the exception region info for the
|
||||
frame. Make the augmentation string three bytes (including the
|
||||
trailing null) so the pointer is 4-byte aligned. The Solaris ld
|
||||
can't handle unaligned relocs. */
|
||||
dw2_asm_output_nstring ("eh", -1, "CIE Augmentation");
|
||||
dw2_asm_output_addr (DWARF2_ADDR_SIZE, "__EXCEPTION_TABLE__",
|
||||
"pointer to exception region info");
|
||||
}
|
||||
else
|
||||
{
|
||||
dw2_asm_output_data (1, 0, "CIE Augmentation (none)");
|
||||
/* Augmentation:
|
||||
z Indicates that a uleb128 is present to size the
|
||||
augmentation section.
|
||||
R Indicates a pointer encoding for CIE and FDE pointers.
|
||||
P Indicates the presence of a language personality
|
||||
routine in the CIE augmentation and an LSDA in the
|
||||
FDE augmentation. */
|
||||
|
||||
/* ??? Handle pointer encodings. */
|
||||
|
||||
if (any_lsda_needed)
|
||||
strcpy (augmentation, "zP");
|
||||
}
|
||||
dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation");
|
||||
|
||||
dw2_asm_output_data_uleb128 (1, "CIE Code Alignment Factor");
|
||||
|
||||
@ -1766,38 +1766,37 @@ output_call_frame_info (for_eh)
|
||||
|
||||
dw2_asm_output_data (1, DWARF_FRAME_RETURN_COLUMN, "CIE RA Column");
|
||||
|
||||
if (augmentation[0])
|
||||
{
|
||||
dw2_asm_output_data_uleb128 (DWARF2_ADDR_SIZE, "Augmentation size");
|
||||
if (eh_personality_libfunc)
|
||||
dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, eh_personality_libfunc,
|
||||
"Personality");
|
||||
else
|
||||
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, "Personality (none)");
|
||||
}
|
||||
|
||||
for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
|
||||
output_cfi (cfi, NULL);
|
||||
|
||||
/* Pad the CIE out to an address sized boundary. */
|
||||
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DWARF2_ADDR_SIZE));
|
||||
ASM_OUTPUT_LABEL (asm_out_file, l2);
|
||||
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
|
||||
ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
|
||||
if (flag_debug_asm)
|
||||
fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START);
|
||||
fputc ('\n', asm_out_file);
|
||||
#endif
|
||||
|
||||
/* Loop through all of the FDE's. */
|
||||
for (i = 0; i < fde_table_in_use; ++i)
|
||||
{
|
||||
fde = &fde_table[i];
|
||||
|
||||
/* Don't emit EH unwind info for leaf functions. */
|
||||
if (for_eh && fde->nothrow)
|
||||
/* Don't emit EH unwind info for leaf functions that don't need it. */
|
||||
if (for_eh && fde->nothrow && ! fde->uses_eh_lsda)
|
||||
continue;
|
||||
|
||||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, FDE_LABEL, for_eh + i * 2);
|
||||
ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i * 2);
|
||||
ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i * 2);
|
||||
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
|
||||
ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i * 2);
|
||||
dw2_asm_output_offset (for_eh ? 4 : DWARF_OFFSET_SIZE, ld, "FDE Length");
|
||||
#else
|
||||
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
|
||||
"FDE Length");
|
||||
#endif
|
||||
ASM_OUTPUT_LABEL (asm_out_file, l1);
|
||||
|
||||
/* ??? This always emits a 4 byte offset when for_eh is true, but it
|
||||
@ -1821,6 +1820,21 @@ output_call_frame_info (for_eh)
|
||||
dw2_asm_output_delta (DWARF2_ADDR_SIZE, fde->dw_fde_end,
|
||||
fde->dw_fde_begin, "FDE address range");
|
||||
|
||||
if (augmentation[0])
|
||||
{
|
||||
dw2_asm_output_data_uleb128 (DWARF2_ADDR_SIZE, "Augmentation size");
|
||||
|
||||
if (fde->uses_eh_lsda)
|
||||
{
|
||||
ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA", fde->funcdef_number);
|
||||
dw2_asm_output_offset (DWARF2_ADDR_SIZE, l1,
|
||||
"Language Specific Data Area");
|
||||
}
|
||||
else
|
||||
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
|
||||
"Language Specific Data Area (none)");
|
||||
}
|
||||
|
||||
/* Loop through the Call Frame Instructions associated with
|
||||
this FDE. */
|
||||
fde->dw_fde_current_label = fde->dw_fde_begin;
|
||||
@ -1830,12 +1844,6 @@ output_call_frame_info (for_eh)
|
||||
/* Pad the FDE out to an address sized boundary. */
|
||||
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DWARF2_ADDR_SIZE));
|
||||
ASM_OUTPUT_LABEL (asm_out_file, l2);
|
||||
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
|
||||
ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
|
||||
if (flag_debug_asm)
|
||||
fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START);
|
||||
fputc ('\n', asm_out_file);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef EH_FRAME_SECTION
|
||||
@ -1888,7 +1896,9 @@ dwarf2out_begin_prologue ()
|
||||
fde->dw_fde_current_label = NULL;
|
||||
fde->dw_fde_end = NULL;
|
||||
fde->dw_fde_cfi = NULL;
|
||||
fde->funcdef_number = current_funcdef_number;
|
||||
fde->nothrow = current_function_nothrow;
|
||||
fde->uses_eh_lsda = cfun->uses_eh_lsda;
|
||||
|
||||
args_size = old_args_size = 0;
|
||||
}
|
||||
|
@ -41,3 +41,5 @@ extern void debug_dwarf_die PARAMS ((struct die_struct *));
|
||||
extern void dwarf2out_set_demangle_name_func PARAMS ((const char *(*) (const char *)));
|
||||
extern void dwarf2out_abstract_function PARAMS ((tree));
|
||||
extern void dwarf2out_add_library_unit_info PARAMS ((const char *, const char *));
|
||||
|
||||
extern unsigned current_funcdef_number;
|
||||
|
162
gcc/eh-common.h
162
gcc/eh-common.h
@ -1,162 +0,0 @@
|
||||
/* EH stuff
|
||||
Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
|
||||
/* This file contains the structures required for the language
|
||||
independent exception handling model. Both the static compiler and
|
||||
the runtime library share this file. */
|
||||
|
||||
/* The runtime flag flag_new_exceptions is used to determine whether the
|
||||
compiler supports the new runtime typechecking mechanism or not. Under
|
||||
the new model, runtime info is contained in the exception table, and
|
||||
the __throw() library routine determines which handler to call based
|
||||
on the results of a call to a matching function provided by the expcetion
|
||||
thrower. Otherwise the old scheme of calling any handler which matches
|
||||
an exception range is used, and the handler is responsible for all
|
||||
checking of runtime conditions. If the handler wasn't suppose to
|
||||
get the exception, it performs a re-throw. */
|
||||
|
||||
|
||||
/* The handler_label field MUST be the first field in this structure. The
|
||||
__throw() library routine expects uses __eh_stub() from except.c, which
|
||||
simply dereferences the context pointer to get the handler.
|
||||
The routine get_dynamic_handler_chain() also has a dependancy on
|
||||
the location of 'dynamic_handler_chain'. If its location is changed,
|
||||
that routine must be modified as well. */
|
||||
#ifndef EH_ALLOC_SIZE
|
||||
/* 192 bytes means the entire eh_context plus malloc overhead fits in 256
|
||||
bytes (assuming 8 byte pointers). 192 bytes gives an eh_info and object
|
||||
size limit of 96 bytes. This should be sufficient for throwing bad_alloc. */
|
||||
#define EH_ALLOC_SIZE 192
|
||||
#endif
|
||||
#ifndef EH_ALLOC_ALIGN
|
||||
/* We can't use BIGGEST_ALIGNMENT, because on some systems, that expands to
|
||||
a check on a compile time switch like
|
||||
'target_flags & MASK_ALIGN_DOUBLE ? 64 : 32'. There's no macro for
|
||||
'largest alignment for any code this compiler can build for', which is
|
||||
really what is needed. */
|
||||
#define EH_ALLOC_ALIGN 16
|
||||
#endif
|
||||
|
||||
struct eh_context
|
||||
{
|
||||
void *handler_label;
|
||||
void **dynamic_handler_chain;
|
||||
/* This is language dependent part of the eh context. */
|
||||
void *info;
|
||||
/* This is used to remember where we threw for re-throws */
|
||||
void *table_index; /* address of exception table entry to rethrow from */
|
||||
/* emergency fallback space, if malloc fails during handling */
|
||||
char alloc_buffer[EH_ALLOC_SIZE]
|
||||
__attribute__((__aligned__(EH_ALLOC_ALIGN)));
|
||||
unsigned alloc_mask;
|
||||
};
|
||||
|
||||
#ifndef EH_TABLE_LOOKUP
|
||||
|
||||
typedef struct old_exception_table
|
||||
{
|
||||
void *start_region;
|
||||
void *end_region;
|
||||
void *exception_handler;
|
||||
} old_exception_table;
|
||||
|
||||
typedef struct exception_table
|
||||
{
|
||||
void *start_region;
|
||||
void *end_region;
|
||||
void *exception_handler;
|
||||
void *match_info; /* runtime type info */
|
||||
} exception_table;
|
||||
|
||||
|
||||
/* The language identifying portion of an exception table */
|
||||
|
||||
typedef struct exception_lang_info
|
||||
{
|
||||
short language;
|
||||
short version;
|
||||
} exception_lang_info;
|
||||
|
||||
/* This value in the first field of the exception descriptor
|
||||
identifies the descriptor as the new model format. This value would never
|
||||
be present in this location under the old model */
|
||||
|
||||
#define NEW_EH_RUNTIME ((void *) -2)
|
||||
|
||||
/* Each function has an exception_descriptor which contains the
|
||||
language info, and a table of exception ranges and handlers */
|
||||
|
||||
typedef struct exception_descriptor
|
||||
{
|
||||
void *runtime_id_field;
|
||||
exception_lang_info lang;
|
||||
exception_table table[1];
|
||||
} exception_descriptor;
|
||||
|
||||
struct __eh_info; /* forward declaration */
|
||||
|
||||
/* A pointer to a matching function is initialized at runtime by the
|
||||
specific language if run-time exceptions are supported.
|
||||
The function takes 3 parameters
|
||||
1 - runtime exception that has been thrown info. (__eh_info *)
|
||||
2 - Match info pointer from the region being considered (void *)
|
||||
3 - exception table region is in (exception descriptor *)
|
||||
*/
|
||||
|
||||
typedef void * (*__eh_matcher) PARAMS ((struct __eh_info *, void *,
|
||||
struct exception_descriptor *));
|
||||
|
||||
/* This value is to be checked as a 'match all' case in the runtime field. */
|
||||
|
||||
#define CATCH_ALL_TYPE ((void *) -1)
|
||||
|
||||
/* This is the runtime exception information. This forms the minimum required
|
||||
information for an exception info pointer in an eh_context structure. */
|
||||
|
||||
|
||||
typedef struct __eh_info
|
||||
{
|
||||
__eh_matcher match_function;
|
||||
short language;
|
||||
short version;
|
||||
} __eh_info;
|
||||
|
||||
/* Convienient language codes for ID the originating language. Similar
|
||||
to the codes in dwarf2.h. */
|
||||
|
||||
enum exception_source_language
|
||||
{
|
||||
EH_LANG_C89 = 0x0001,
|
||||
EH_LANG_C = 0x0002,
|
||||
EH_LANG_Ada83 = 0x0003,
|
||||
EH_LANG_C_plus_plus = 0x0004,
|
||||
EH_LANG_Cobol74 = 0x0005,
|
||||
EH_LANG_Cobol85 = 0x0006,
|
||||
EH_LANG_Fortran77 = 0x0007,
|
||||
EH_LANG_Fortran90 = 0x0008,
|
||||
EH_LANG_Pascal83 = 0x0009,
|
||||
EH_LANG_Modula2 = 0x000a,
|
||||
EH_LANG_Java = 0x000b,
|
||||
EH_LANG_Mips_Assembler = 0x8001
|
||||
};
|
||||
|
||||
#endif /* EH_TABLE_LOOKUP */
|
||||
|
||||
|
6363
gcc/except.c
6363
gcc/except.c
File diff suppressed because it is too large
Load Diff
567
gcc/except.h
567
gcc/except.h
@ -19,516 +19,187 @@ 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. */
|
||||
|
||||
#if !defined(NULL_RTX) && !defined(rtx)
|
||||
typedef struct rtx_def *_except_rtx;
|
||||
#define rtx _except_rtx
|
||||
|
||||
#ifndef TREE_CODE
|
||||
union tree_node;
|
||||
#define tree union tree_node *
|
||||
#endif
|
||||
|
||||
#ifdef TREE_CODE
|
||||
|
||||
/* A stack of labels. CHAIN points to the next entry in the stack. */
|
||||
|
||||
struct label_node {
|
||||
union {
|
||||
rtx rlabel;
|
||||
tree tlabel;
|
||||
} u;
|
||||
struct label_node *chain;
|
||||
};
|
||||
|
||||
/* An eh_entry is used to describe one exception handling region.
|
||||
|
||||
OUTER_CONTEXT is the label used for rethrowing into the outer context.
|
||||
|
||||
EXCEPTION_HANDLER_LABEL is the label corresponding to the handler
|
||||
for this region.
|
||||
|
||||
LABEL_USED indicates whether a CATCH block has already used this
|
||||
label or not. New ones are needed for additional catch blocks if
|
||||
it has.
|
||||
|
||||
FALSE_LABEL is used when either setjmp/longjmp exceptions are in
|
||||
use, or old style table exceptions. It contains the label for
|
||||
branching to the next runtime type check as handlers are processed.
|
||||
|
||||
FINALIZATION is the tree codes for the handler, or is NULL_TREE if
|
||||
one hasn't been generated yet, or is integer_zero_node to mark the
|
||||
end of a group of try blocks. */
|
||||
|
||||
struct eh_entry {
|
||||
rtx outer_context;
|
||||
rtx exception_handler_label;
|
||||
tree finalization;
|
||||
int label_used;
|
||||
rtx false_label;
|
||||
rtx rethrow_label;
|
||||
/* If non-zero, this entry is for a handler created when we left an
|
||||
exception-region via goto. */
|
||||
unsigned goto_entry_p : 1;
|
||||
};
|
||||
#else
|
||||
struct label_node;
|
||||
struct eh_entry;
|
||||
#ifndef RTX_CODE
|
||||
struct rtx_def;
|
||||
#define rtx struct rtx_def *
|
||||
#endif
|
||||
|
||||
/* A list of EH_ENTRYs. ENTRY is the entry; CHAIN points to the next
|
||||
entry in the list, or is NULL if this is the last entry. */
|
||||
|
||||
struct eh_node {
|
||||
struct eh_entry *entry;
|
||||
struct eh_node *chain;
|
||||
};
|
||||
|
||||
/* A stack of EH_ENTRYs. TOP is the topmost entry on the stack. TOP is
|
||||
NULL if the stack is empty. */
|
||||
|
||||
struct eh_stack {
|
||||
struct eh_node *top;
|
||||
};
|
||||
|
||||
/* A queue of EH_ENTRYs. HEAD is the front of the queue; TAIL is the
|
||||
end (the latest entry). HEAD and TAIL are NULL if the queue is
|
||||
empty. */
|
||||
|
||||
struct eh_queue {
|
||||
struct eh_node *head;
|
||||
struct eh_node *tail;
|
||||
struct eh_queue *next;
|
||||
};
|
||||
|
||||
/* Used to save exception handling status for each function. */
|
||||
struct eh_status
|
||||
{
|
||||
/* A stack used for keeping track of the currently active exception
|
||||
handling region. As each exception region is started, an entry
|
||||
describing the region is pushed onto this stack. The current
|
||||
region can be found by looking at the top of the stack, and as we
|
||||
exit regions, the corresponding entries are popped.
|
||||
|
||||
Entries cannot overlap; they can be nested. So there is only one
|
||||
entry at most that corresponds to the current instruction, and that
|
||||
is the entry on the top of the stack. */
|
||||
struct eh_stack x_ehstack;
|
||||
/* This stack is used to represent what the current eh region is
|
||||
for the catch blocks beings processed */
|
||||
struct eh_stack x_catchstack;
|
||||
/* A queue used for tracking which exception regions have closed.
|
||||
As we exit a region, we enqueue a new entry. The entries are then
|
||||
dequeued during expand_leftover_cleanups and
|
||||
expand_start_all_catch. */
|
||||
struct eh_queue *x_ehqueue;
|
||||
/* Insns for all of the exception handlers for the current function.
|
||||
They are currently emitted by the frontend code. */
|
||||
rtx x_catch_clauses;
|
||||
/* End of exception handler insn sequence. */
|
||||
rtx x_catch_clauses_last;
|
||||
/* A random data area for the front end's own use. */
|
||||
struct label_node *x_false_label_stack;
|
||||
/* Keeps track of the label to resume to should one want to resume
|
||||
normal control flow out of a handler (instead of, say, returning to
|
||||
the caller of the current function or exiting the program). */
|
||||
struct label_node *x_caught_return_label_stack;
|
||||
/* A stack (TREE_LIST) of lists of handlers. The TREE_VALUE of each
|
||||
node is itself a TREE_CHAINed list of handlers for regions that
|
||||
are not yet closed. The TREE_VALUE of each entry contains the
|
||||
handler for the corresponding entry on the ehstack. */
|
||||
union tree_node *x_protect_list;
|
||||
/* The EH context. Nonzero if the function has already
|
||||
fetched a pointer to the EH context for exception handling. */
|
||||
rtx ehc;
|
||||
/* The label generated by expand_builtin_eh_return. */
|
||||
rtx x_eh_return_stub_label;
|
||||
};
|
||||
|
||||
#define ehstack (cfun->eh->x_ehstack)
|
||||
#define catchstack (cfun->eh->x_catchstack)
|
||||
#define ehqueue (cfun->eh->x_ehqueue)
|
||||
#define catch_clauses (cfun->eh->x_catch_clauses)
|
||||
#define catch_clauses_last (cfun->eh->x_catch_clauses_last)
|
||||
#define false_label_stack (cfun->eh->x_false_label_stack)
|
||||
#define caught_return_label_stack (cfun->eh->x_caught_return_label_stack)
|
||||
#define protect_list (cfun->eh->x_protect_list)
|
||||
#define current_function_ehc (cfun->eh->ehc)
|
||||
#define eh_return_stub_label (cfun->eh->x_eh_return_stub_label)
|
||||
|
||||
#ifdef TREE_CODE
|
||||
/* Start an exception handling region. All instructions emitted after
|
||||
this point are considered to be part of the region until
|
||||
expand_eh_region_end () is invoked. */
|
||||
|
||||
extern void expand_eh_region_start PARAMS ((void));
|
||||
|
||||
/* Just like expand_eh_region_start, except if a cleanup action is
|
||||
entered on the cleanup chain, the TREE_PURPOSE of the element put
|
||||
on the chain is DECL. DECL should be the associated VAR_DECL, if
|
||||
any, otherwise it should be NULL_TREE. */
|
||||
|
||||
extern void expand_eh_region_start_for_decl PARAMS ((tree));
|
||||
|
||||
/* Start an exception handling region for the given cleanup action.
|
||||
All instructions emitted after this point are considered to be part
|
||||
of the region until expand_eh_region_end () is invoked. CLEANUP is
|
||||
the cleanup action to perform. The return value is true if the
|
||||
exception region was optimized away. If that case,
|
||||
expand_eh_region_end does not need to be called for this cleanup,
|
||||
nor should it be.
|
||||
|
||||
This routine notices one particular common case in C++ code
|
||||
generation, and optimizes it so as to not need the exception
|
||||
region. */
|
||||
|
||||
extern int expand_eh_region_start_tree PARAMS ((tree, tree));
|
||||
|
||||
/* End an exception handling region. The information about the region
|
||||
is found on the top of ehstack.
|
||||
|
||||
HANDLER is either the cleanup for the exception region, or if we're
|
||||
marking the end of a try block, HANDLER is integer_zero_node.
|
||||
|
||||
HANDLER will be transformed to rtl when expand_leftover_cleanups ()
|
||||
is invoked. */
|
||||
|
||||
extern void expand_eh_region_end PARAMS ((tree));
|
||||
|
||||
/* Push RLABEL or TLABEL onto LABELSTACK. Only one of RLABEL or TLABEL
|
||||
should be set; the other must be NULL. */
|
||||
|
||||
extern void push_label_entry PARAMS ((struct label_node **labelstack,
|
||||
rtx rlabel, tree tlabel));
|
||||
|
||||
/* Pop the topmost entry from LABELSTACK and return its value as an
|
||||
rtx node. If LABELSTACK is empty, return NULL. */
|
||||
|
||||
extern rtx pop_label_entry PARAMS ((struct label_node **labelstack));
|
||||
|
||||
/* Return the topmost entry of LABELSTACK as a tree node, or return
|
||||
NULL_TREE if LABELSTACK is empty. */
|
||||
|
||||
extern tree top_label_entry PARAMS ((struct label_node **labelstack));
|
||||
|
||||
#ifndef _VARRAY_H_
|
||||
struct varray_head_tag;
|
||||
#define varray_type struct varray_head_tag *
|
||||
#endif
|
||||
|
||||
/* Test: is exception handling turned on? */
|
||||
|
||||
/* Per-function EH data. Used only in except.c, but GC and others
|
||||
manipulate pointers to the opaque type. */
|
||||
struct eh_status;
|
||||
|
||||
/* Internal structure describing a region. */
|
||||
struct eh_region;
|
||||
|
||||
/* Test: is exception handling turned on? */
|
||||
extern int doing_eh PARAMS ((int));
|
||||
|
||||
/* Toplevel initialization for EH. */
|
||||
/* Start an exception handling region. All instructions emitted after
|
||||
this point are considered to be part of the region until an
|
||||
expand_eh_region_end variant is invoked. */
|
||||
extern void expand_eh_region_start PARAMS ((void));
|
||||
|
||||
void set_exception_lang_code PARAMS ((int));
|
||||
void set_exception_version_code PARAMS ((int));
|
||||
|
||||
/* A list of handlers asocciated with an exception region. HANDLER_LABEL
|
||||
is the the label that control should be transfered to if the data
|
||||
in TYPE_INFO matches an exception. a value of NULL_TREE for TYPE_INFO
|
||||
means This is a cleanup, and must always be called. A value of
|
||||
CATCH_ALL_TYPE works like a cleanup, but a call to the runtime matcher
|
||||
is still performed to avoid being caught by a different language
|
||||
exception. NEXT is a pointer to the next handler for this region.
|
||||
NULL means there are no more. */
|
||||
|
||||
typedef struct handler_info
|
||||
{
|
||||
rtx handler_label;
|
||||
int handler_number;
|
||||
void *type_info;
|
||||
struct handler_info *next;
|
||||
} handler_info;
|
||||
|
||||
|
||||
/* Add new handler information to an exception range. The first parameter
|
||||
specifies the range number (returned from new_eh_entry()). The second
|
||||
parameter specifies the handler. By default the handler is inserted at
|
||||
the end of the list. A handler list may contain only ONE NULL_TREE
|
||||
typeinfo entry. Regardless where it is positioned, a NULL_TREE entry
|
||||
is always output as the LAST handler in the exception table for a region. */
|
||||
|
||||
void add_new_handler PARAMS ((int, struct handler_info *));
|
||||
|
||||
/* Remove a handler label. The handler label is being deleted, so all
|
||||
regions which reference this handler should have it removed from their
|
||||
list of possible handlers. Any region which has the final handler
|
||||
removed can be deleted. */
|
||||
|
||||
void remove_handler PARAMS ((rtx));
|
||||
|
||||
/* Create a new handler structure initialized with the handler label and
|
||||
typeinfo fields passed in. */
|
||||
|
||||
struct handler_info *get_new_handler PARAMS ((rtx, void *));
|
||||
|
||||
/* Make a duplicate of an exception region by copying all the handlers
|
||||
for an exception region. Return the new handler index. */
|
||||
|
||||
int duplicate_eh_handlers PARAMS ((int, int, rtx (*)(rtx)));
|
||||
|
||||
/* map symbol refs for rethrow */
|
||||
|
||||
rtx rethrow_symbol_map PARAMS ((rtx, rtx (*)(rtx)));
|
||||
|
||||
/* Is the rethrow label for a region used? */
|
||||
|
||||
int rethrow_used PARAMS ((int));
|
||||
|
||||
/* Update the rethrow references to reflect rethrows which have been
|
||||
optimized away. */
|
||||
|
||||
void update_rethrow_references PARAMS ((void));
|
||||
|
||||
/* Get a pointer to the first handler in an exception region's list. */
|
||||
|
||||
struct handler_info *get_first_handler PARAMS ((int));
|
||||
|
||||
/* Find all the runtime handlers type matches currently referenced */
|
||||
|
||||
int find_all_handler_type_matches PARAMS ((void ***));
|
||||
|
||||
/* The eh_nesting_info structure is used to find a list of valid handlers
|
||||
for any arbitrary exception region. When init_eh_nesting_info is called,
|
||||
the information is all pre-calculated and entered in this structure.
|
||||
REGION_INDEX is a vector over all possible region numbers. Since the
|
||||
number of regions is typically much smaller than the range of block
|
||||
numbers, this is a sparse vector and the other data structures are
|
||||
represented as dense vectors. Indexed with an exception region number, this
|
||||
returns the index to use in the other data structures to retreive the
|
||||
correct information.
|
||||
HANDLERS is an array of vectors which point to handler_info structures.
|
||||
when indexed, it gives the list of all possible handlers which can
|
||||
be reached by a throw from this exception region.
|
||||
NUM_HANDLERS is the equivilent array indicating how many handler
|
||||
pointers there are in the HANDLERS vector.
|
||||
OUTER_INDEX indicates which index represents the information for the
|
||||
outer block. 0 indicates there is no outer context.
|
||||
REGION_COUNT is the number of regions. */
|
||||
|
||||
typedef struct eh_nesting
|
||||
{
|
||||
int *region_index;
|
||||
handler_info ***handlers;
|
||||
int *num_handlers;
|
||||
int *outer_index;
|
||||
int region_count;
|
||||
} eh_nesting_info;
|
||||
|
||||
/* Initialize the eh_nesting_info structure. */
|
||||
|
||||
eh_nesting_info *init_eh_nesting_info PARAMS ((void));
|
||||
|
||||
/* Get a list of handlers reachable from a an exception region/insn. */
|
||||
|
||||
int reachable_handlers PARAMS ((int, eh_nesting_info *, rtx,
|
||||
handler_info ***handlers));
|
||||
|
||||
/* Free the eh_nesting_info structure. */
|
||||
|
||||
void free_eh_nesting_info PARAMS ((eh_nesting_info *));
|
||||
|
||||
extern void init_eh PARAMS ((void));
|
||||
|
||||
/* Initialization for the per-function EH data. */
|
||||
|
||||
extern void init_eh_for_function PARAMS ((void));
|
||||
|
||||
/* Generate an exception label. Use instead of gen_label_rtx */
|
||||
|
||||
extern rtx gen_exception_label PARAMS ((void));
|
||||
|
||||
/* Adds an EH table entry for EH entry number N. Called from
|
||||
final_scan_insn for NOTE_INSN_EH_REGION_BEG. */
|
||||
|
||||
extern void add_eh_table_entry PARAMS ((int n));
|
||||
|
||||
/* Start a catch clause, triggered by runtime value paramter. */
|
||||
|
||||
#ifdef TREE_CODE
|
||||
extern void start_catch_handler PARAMS ((tree));
|
||||
#endif
|
||||
|
||||
/* End an individual catch clause. */
|
||||
|
||||
extern void end_catch_handler PARAMS ((void));
|
||||
|
||||
/* Returns a non-zero value if we need to output an exception table. */
|
||||
|
||||
extern int exception_table_p PARAMS ((void));
|
||||
|
||||
/* Outputs the exception table if we have one. */
|
||||
|
||||
extern void output_exception_table PARAMS ((void));
|
||||
extern void output_exception_table_data PARAMS ((void));
|
||||
|
||||
/* Free the exception table. */
|
||||
|
||||
extern void free_exception_table PARAMS((void));
|
||||
|
||||
/* Used by the ia64 unwind format to output data for an individual
|
||||
function. */
|
||||
|
||||
extern void output_function_exception_table PARAMS((void));
|
||||
|
||||
/* Given a return address in ADDR, determine the address we should use
|
||||
to find the corresponding EH region. */
|
||||
|
||||
extern rtx eh_outer_context PARAMS ((rtx addr));
|
||||
|
||||
/* Called at the start of a block of try statements for which there is
|
||||
a supplied catch handler. */
|
||||
|
||||
extern void expand_start_try_stmts PARAMS ((void));
|
||||
|
||||
/* Called at the start of a block of catch statements. It terminates the
|
||||
previous set of try statements. */
|
||||
/* End an exception handling region for a cleanup. HANDLER is an
|
||||
expression to expand for the cleanup. */
|
||||
extern void expand_eh_region_end_cleanup PARAMS ((tree));
|
||||
|
||||
/* End an exception handling region for a try block, and prepares
|
||||
for subsequent calls to expand_start_catch. */
|
||||
extern void expand_start_all_catch PARAMS ((void));
|
||||
|
||||
/* Called at the end of a block of catch statements. */
|
||||
/* Begin a catch clause. TYPE is an object to be matched by the
|
||||
runtime, or null if this is a catch-all clause. */
|
||||
extern void expand_start_catch PARAMS ((tree));
|
||||
|
||||
/* End a catch clause. Control will resume after the try/catch block. */
|
||||
extern void expand_end_catch PARAMS ((void));
|
||||
|
||||
/* End a sequence of catch handlers for a try block. */
|
||||
extern void expand_end_all_catch PARAMS ((void));
|
||||
|
||||
/* End an exception region for an exception type filter. ALLOWED is a
|
||||
TREE_LIST of TREE_VALUE objects to be matched by the runtime.
|
||||
FAILURE is a function to invoke if a mismatch ocurrs. */
|
||||
extern void expand_eh_region_end_allowed PARAMS ((tree, tree));
|
||||
|
||||
/* End an exception region for a must-not-throw filter. FAILURE is a
|
||||
function to invoke if an uncaught exception propagates this far. */
|
||||
extern void expand_eh_region_end_must_not_throw PARAMS ((tree));
|
||||
|
||||
/* End an exception region for a throw. No handling goes on here,
|
||||
but it's the easiest way for the front-end to indicate what type
|
||||
is being thrown. */
|
||||
extern void expand_eh_region_end_throw PARAMS ((tree));
|
||||
|
||||
/* End a fixup region. Within this region the cleanups for the immediately
|
||||
enclosing region are _not_ run. This is used for goto cleanup to avoid
|
||||
destroying an object twice. */
|
||||
extern void expand_eh_region_end_fixup PARAMS ((tree));
|
||||
|
||||
/* Begin a region that will contain entries created with
|
||||
add_partial_entry. */
|
||||
|
||||
extern void begin_protect_partials PARAMS ((void));
|
||||
|
||||
#ifdef TREE_CODE
|
||||
/* Create a new exception region and add the handler for the region
|
||||
onto a list. These regions will be ended (and their handlers
|
||||
emitted) when end_protect_partials is invoked. */
|
||||
|
||||
extern void add_partial_entry PARAMS ((tree handler));
|
||||
#endif
|
||||
onto a list. These regions will be ended (and their handlers emitted)
|
||||
when end_protect_partials is invoked. */
|
||||
extern void add_partial_entry PARAMS ((tree));
|
||||
|
||||
/* End all of the pending exception regions that have handlers added with
|
||||
push_protect_entry (). */
|
||||
|
||||
add_partial_entry. */
|
||||
extern void end_protect_partials PARAMS ((void));
|
||||
|
||||
/* An internal throw. */
|
||||
|
||||
extern void expand_internal_throw PARAMS ((void));
|
||||
|
||||
/* Called from expand_exception_blocks and expand_end_catch_block to
|
||||
expand and pending handlers. */
|
||||
|
||||
extern void expand_leftover_cleanups PARAMS ((void));
|
||||
|
||||
/* If necessary, emit insns to get EH context for the current
|
||||
function. */
|
||||
|
||||
extern void emit_eh_context PARAMS ((void));
|
||||
|
||||
/* Builds a list of handler labels and puts them in the global
|
||||
variable exception_handler_labels. */
|
||||
|
||||
extern void find_exception_handler_labels PARAMS ((void));
|
||||
|
||||
/* Determine if an arbitrary label is an exception label */
|
||||
|
||||
extern int is_exception_handler_label PARAMS ((int));
|
||||
|
||||
/* Performs sanity checking on the check_exception_handler_labels
|
||||
list. */
|
||||
|
||||
extern void check_exception_handler_labels PARAMS ((void));
|
||||
|
||||
/* Keeps track of the label used as the context of a throw to rethrow an
|
||||
exception to the outer exception region. */
|
||||
|
||||
extern struct label_node *outer_context_label_stack;
|
||||
|
||||
/* A list of labels used for exception handlers. It is created by
|
||||
find_exception_handler_labels for the optimization passes. */
|
||||
|
||||
/* A list of labels used for exception handlers. */
|
||||
extern rtx exception_handler_labels;
|
||||
|
||||
/* Determine if the given INSN can throw an exception. */
|
||||
|
||||
extern int can_throw_internal PARAMS ((rtx));
|
||||
extern bool can_throw_internal PARAMS ((rtx));
|
||||
extern bool can_throw_external PARAMS ((rtx));
|
||||
|
||||
/* Return nonzero if nothing in this function can throw. */
|
||||
extern bool nothrow_function_p PARAMS ((void));
|
||||
|
||||
extern int nothrow_function_p PARAMS ((void));
|
||||
/* After initial rtl generation, call back to finish generating
|
||||
exception support code. */
|
||||
extern void finish_eh_generation PARAMS ((void));
|
||||
|
||||
/* Performs optimizations for exception handling, such as removing
|
||||
unnecessary exception regions. Invoked from jump_optimize (). */
|
||||
extern void init_eh PARAMS ((void));
|
||||
extern void init_eh_for_function PARAMS ((void));
|
||||
|
||||
extern void exception_optimize PARAMS ((void));
|
||||
extern rtx reachable_handlers PARAMS ((rtx));
|
||||
extern void maybe_remove_eh_handler PARAMS ((rtx));
|
||||
|
||||
/* Return EH context (and set it up once per fn). */
|
||||
extern rtx get_eh_context PARAMS ((void));
|
||||
extern void convert_from_eh_region_ranges PARAMS ((void));
|
||||
extern void convert_to_eh_region_ranges PARAMS ((void));
|
||||
extern void find_exception_handler_labels PARAMS ((void));
|
||||
extern void output_function_exception_table PARAMS ((void));
|
||||
|
||||
/* Get the dynamic handler chain. */
|
||||
extern rtx get_dynamic_handler_chain PARAMS ((void));
|
||||
extern void expand_builtin_unwind_init PARAMS ((void));
|
||||
extern rtx expand_builtin_eh_return_data_regno PARAMS ((tree));
|
||||
extern rtx expand_builtin_extract_return_addr PARAMS ((tree));
|
||||
extern rtx expand_builtin_frob_return_addr PARAMS ((tree));
|
||||
extern void expand_builtin_eh_return PARAMS ((tree, tree));
|
||||
extern void expand_eh_return PARAMS ((void));
|
||||
|
||||
/* Get the dynamic cleanup chain. */
|
||||
extern rtx get_dynamic_cleanup_chain PARAMS ((void));
|
||||
extern rtx get_exception_pointer PARAMS ((void));
|
||||
|
||||
/* Throw an exception. */
|
||||
struct function;
|
||||
struct inline_remap;
|
||||
extern int duplicate_eh_regions PARAMS ((struct function *,
|
||||
struct inline_remap *));
|
||||
|
||||
extern void emit_throw PARAMS ((void));
|
||||
extern void sjlj_emit_function_exit_after PARAMS ((rtx));
|
||||
|
||||
/* Save away the current ehqueue. */
|
||||
extern void push_ehqueue PARAMS ((void));
|
||||
|
||||
/* Restore a previously pushed ehqueue. */
|
||||
extern void pop_ehqueue PARAMS ((void));
|
||||
/* Nonzero to protect cleanup actions with must-not-throw regions. */
|
||||
extern tree protect_cleanup_actions;
|
||||
|
||||
/* One to protect cleanup actions with a handler that calls
|
||||
__terminate, zero otherwise. */
|
||||
/* Return true if type A catches type B. */
|
||||
int (*lang_eh_type_covers) PARAMS ((tree a, tree b));
|
||||
|
||||
extern int protect_cleanup_actions_with_terminate;
|
||||
/* Map a type to a runtime object to match type. */
|
||||
tree (*lang_eh_runtime_type) PARAMS ((tree));
|
||||
|
||||
#ifdef TREE_CODE
|
||||
extern tree protect_with_terminate PARAMS ((tree));
|
||||
#ifndef TREE_CODE
|
||||
#undef tree
|
||||
#endif
|
||||
|
||||
extern void expand_fixup_region_start PARAMS ((void));
|
||||
#ifdef TREE_CODE
|
||||
extern void expand_fixup_region_end PARAMS ((tree));
|
||||
#endif
|
||||
|
||||
/* Various hooks for the DWARF 2 __throw routine. */
|
||||
|
||||
void expand_builtin_unwind_init PARAMS ((void));
|
||||
rtx expand_builtin_dwarf_fp_regnum PARAMS ((void));
|
||||
#ifdef TREE_CODE
|
||||
rtx expand_builtin_frob_return_addr PARAMS ((tree));
|
||||
rtx expand_builtin_extract_return_addr PARAMS ((tree));
|
||||
void expand_builtin_init_dwarf_reg_sizes PARAMS ((tree));
|
||||
void expand_builtin_eh_return PARAMS ((tree, tree, tree));
|
||||
#endif
|
||||
void expand_eh_return PARAMS ((void));
|
||||
|
||||
|
||||
/* Checking whether 2 instructions are within the same exception region. */
|
||||
|
||||
int in_same_eh_region PARAMS ((rtx, rtx));
|
||||
void free_insn_eh_region PARAMS ((void));
|
||||
void init_insn_eh_region PARAMS ((rtx, int));
|
||||
|
||||
#ifdef rtx
|
||||
#ifndef RTX_CODE
|
||||
#undef rtx
|
||||
#endif
|
||||
|
||||
#ifndef _VARRAY_H_
|
||||
#undef varray_type
|
||||
#endif
|
||||
|
||||
|
||||
/* Just because the user configured --with-sjlj-exceptions=no doesn't
|
||||
mean that we can use call frame exceptions. Detect that the target
|
||||
has appropriate support. */
|
||||
|
||||
#if !defined (EH_RETURN_DATA_REGNO) \
|
||||
|| !defined(EH_RETURN_STACKADJ_RTX) \
|
||||
|| ! (defined(EH_RETURN_HANDLER_RTX) \
|
||||
|| defined(HAVE_eh_return)) \
|
||||
|| ! (defined(DWARF2_UNWIND_INFO) \
|
||||
|| defined(IA64_UNWIND_INFO))
|
||||
#define MUST_USE_SJLJ_EXCEPTIONS 1
|
||||
#else
|
||||
#define MUST_USE_SJLJ_EXCEPTIONS 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SJLJ_EXCEPTIONS
|
||||
# if CONFIG_SJLJ_EXCEPTIONS == 1
|
||||
# define USING_SJLJ_EXCEPTIONS 1
|
||||
# endif
|
||||
# if CONFIG_SJLJ_EXCEPTIONS == 0
|
||||
# define USING_SJLJ_EXCEPTIONS 0
|
||||
# ifndef EH_RETURN_DATA_REGNO
|
||||
#error "EH_RETURN_DATA_REGNO required"
|
||||
# endif
|
||||
# ifndef EH_RETURN_STACKADJ_RTX
|
||||
#error "EH_RETURN_STACKADJ_RTX required"
|
||||
# endif
|
||||
# if !defined(EH_RETURN_HANDLER_RTX) && !defined(HAVE_eh_return)
|
||||
#error "EH_RETURN_HANDLER_RTX or eh_return required"
|
||||
# endif
|
||||
# if !defined(DWARF2_UNWIND_INFO) && !defined(IA64_UNWIND_INFO)
|
||||
#error "{DWARF2,IA64}_UNWIND_INFO required"
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
# ifdef IA64_UNWIND_INFO
|
||||
# define USING_SJLJ_EXCEPTIONS (!IA64_UNWIND_INFO)
|
||||
# else
|
||||
# ifdef DWARF2_UNWIND_INFO
|
||||
# define USING_SJLJ_EXCEPTIONS (!DWARF2_UNWIND_INFO)
|
||||
# endif
|
||||
# endif
|
||||
# define USING_SJLJ_EXCEPTIONS MUST_USE_SJLJ_EXCEPTIONS
|
||||
#endif
|
||||
|
19
gcc/expr.c
19
gcc/expr.c
@ -8741,7 +8741,7 @@ expand_expr (exp, target, tmode, modifier)
|
||||
|
||||
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
|
||||
|
||||
expand_eh_region_end (handler);
|
||||
expand_eh_region_end_cleanup (handler);
|
||||
|
||||
return op0;
|
||||
}
|
||||
@ -8788,23 +8788,12 @@ expand_expr (exp, target, tmode, modifier)
|
||||
return const0_rtx;
|
||||
}
|
||||
|
||||
case POPDCC_EXPR:
|
||||
{
|
||||
rtx dcc = get_dynamic_cleanup_chain ();
|
||||
emit_move_insn (dcc, validize_mem (gen_rtx_MEM (Pmode, dcc)));
|
||||
return const0_rtx;
|
||||
}
|
||||
|
||||
case POPDHC_EXPR:
|
||||
{
|
||||
rtx dhc = get_dynamic_handler_chain ();
|
||||
emit_move_insn (dhc, validize_mem (gen_rtx_MEM (Pmode, dhc)));
|
||||
return const0_rtx;
|
||||
}
|
||||
|
||||
case VA_ARG_EXPR:
|
||||
return expand_builtin_va_arg (TREE_OPERAND (exp, 0), type);
|
||||
|
||||
case EXC_PTR_EXPR:
|
||||
return get_exception_pointer ();
|
||||
|
||||
default:
|
||||
return (*lang_expand_expr) (exp, original_target, tmode, modifier);
|
||||
}
|
||||
|
21
gcc/expr.h
21
gcc/expr.h
@ -495,14 +495,12 @@ enum libfunc_index
|
||||
LTI_memset,
|
||||
LTI_bzero,
|
||||
|
||||
LTI_throw,
|
||||
LTI_rethrow,
|
||||
LTI_sjthrow,
|
||||
LTI_sjpopnthrow,
|
||||
LTI_terminate,
|
||||
LTI_unwind_resume,
|
||||
LTI_eh_personality,
|
||||
LTI_setjmp,
|
||||
LTI_longjmp,
|
||||
LTI_eh_rtime_match,
|
||||
LTI_unwind_sjlj_register,
|
||||
LTI_unwind_sjlj_unregister,
|
||||
|
||||
LTI_eqhf2,
|
||||
LTI_nehf2,
|
||||
@ -628,14 +626,13 @@ extern rtx libfunc_table[LTI_MAX];
|
||||
#define memset_libfunc (libfunc_table[LTI_memset])
|
||||
#define bzero_libfunc (libfunc_table[LTI_bzero])
|
||||
|
||||
#define throw_libfunc (libfunc_table[LTI_throw])
|
||||
#define rethrow_libfunc (libfunc_table[LTI_rethrow])
|
||||
#define sjthrow_libfunc (libfunc_table[LTI_sjthrow])
|
||||
#define sjpopnthrow_libfunc (libfunc_table[LTI_sjpopnthrow])
|
||||
#define terminate_libfunc (libfunc_table[LTI_terminate])
|
||||
#define unwind_resume_libfunc (libfunc_table[LTI_unwind_resume])
|
||||
#define eh_personality_libfunc (libfunc_table[LTI_eh_personality])
|
||||
#define setjmp_libfunc (libfunc_table[LTI_setjmp])
|
||||
#define longjmp_libfunc (libfunc_table[LTI_longjmp])
|
||||
#define eh_rtime_match_libfunc (libfunc_table[LTI_eh_rtime_match])
|
||||
#define unwind_sjlj_register_libfunc (libfunc_table[LTI_unwind_sjlj_register])
|
||||
#define unwind_sjlj_unregister_libfunc \
|
||||
(libfunc_table[LTI_unwind_sjlj_unregister])
|
||||
|
||||
#define eqhf2_libfunc (libfunc_table[LTI_eqhf2])
|
||||
#define nehf2_libfunc (libfunc_table[LTI_nehf2])
|
||||
|
26
gcc/final.c
26
gcc/final.c
@ -1945,8 +1945,6 @@ final (first, file, optimize, prescan)
|
||||
last_ignored_compare = 0;
|
||||
new_block = 1;
|
||||
|
||||
check_exception_handler_labels ();
|
||||
|
||||
/* Make a map indicating which line numbers appear in this function.
|
||||
When producing SDB debugging info, delete troublesome line number
|
||||
notes from inlined functions in other files as well as duplicate
|
||||
@ -2003,10 +2001,6 @@ final (first, file, optimize, prescan)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Initialize insn_eh_region table if eh is being used. */
|
||||
|
||||
init_insn_eh_region (first, max_uid);
|
||||
|
||||
init_recog ();
|
||||
|
||||
CC_STATUS_INIT;
|
||||
@ -2040,7 +2034,6 @@ final (first, file, optimize, prescan)
|
||||
if (profile_block_flag && new_block)
|
||||
add_bb (file);
|
||||
|
||||
free_insn_eh_region ();
|
||||
free (line_note_exists);
|
||||
line_note_exists = NULL;
|
||||
}
|
||||
@ -2126,24 +2119,13 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
|
||||
break;
|
||||
|
||||
case NOTE_INSN_EH_REGION_BEG:
|
||||
if (! USING_SJLJ_EXCEPTIONS)
|
||||
{
|
||||
ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_EH_HANDLER (insn));
|
||||
#ifdef ASM_OUTPUT_EH_REGION_BEG
|
||||
ASM_OUTPUT_EH_REGION_BEG (file, NOTE_EH_HANDLER (insn));
|
||||
#endif
|
||||
}
|
||||
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB",
|
||||
NOTE_EH_HANDLER (insn));
|
||||
break;
|
||||
|
||||
case NOTE_INSN_EH_REGION_END:
|
||||
if (! USING_SJLJ_EXCEPTIONS)
|
||||
{
|
||||
ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_EH_HANDLER (insn));
|
||||
add_eh_table_entry (NOTE_EH_HANDLER (insn));
|
||||
#ifdef ASM_OUTPUT_EH_REGION_END
|
||||
ASM_OUTPUT_EH_REGION_END (file, NOTE_EH_HANDLER (insn));
|
||||
#endif
|
||||
}
|
||||
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE",
|
||||
NOTE_EH_HANDLER (insn));
|
||||
break;
|
||||
|
||||
case NOTE_INSN_PROLOGUE_END:
|
||||
|
413
gcc/flow.c
413
gcc/flow.c
@ -204,7 +204,6 @@ struct basic_block_def entry_exit_blocks[2]
|
||||
NULL, /* aux */
|
||||
ENTRY_BLOCK, /* index */
|
||||
0, /* loop_depth */
|
||||
-1, -1, /* eh_beg, eh_end */
|
||||
0 /* count */
|
||||
},
|
||||
{
|
||||
@ -219,7 +218,6 @@ struct basic_block_def entry_exit_blocks[2]
|
||||
NULL, /* aux */
|
||||
EXIT_BLOCK, /* index */
|
||||
0, /* loop_depth */
|
||||
-1, -1, /* eh_beg, eh_end */
|
||||
0 /* count */
|
||||
}
|
||||
};
|
||||
@ -368,16 +366,12 @@ static void clear_edges PARAMS ((void));
|
||||
static void make_edges PARAMS ((rtx));
|
||||
static void make_label_edge PARAMS ((sbitmap *, basic_block,
|
||||
rtx, int));
|
||||
static void make_eh_edge PARAMS ((sbitmap *, eh_nesting_info *,
|
||||
basic_block, rtx, int));
|
||||
static void make_eh_edge PARAMS ((sbitmap *, basic_block, rtx));
|
||||
static void mark_critical_edges PARAMS ((void));
|
||||
static void move_stray_eh_region_notes PARAMS ((void));
|
||||
static void record_active_eh_regions PARAMS ((rtx));
|
||||
|
||||
static void commit_one_edge_insertion PARAMS ((edge));
|
||||
|
||||
static void delete_unreachable_blocks PARAMS ((void));
|
||||
static void delete_eh_regions PARAMS ((void));
|
||||
static int can_delete_note_p PARAMS ((rtx));
|
||||
static void expunge_block PARAMS ((basic_block));
|
||||
static int can_delete_label_p PARAMS ((rtx));
|
||||
@ -537,7 +531,6 @@ find_basic_blocks (f, nregs, file)
|
||||
compute_bb_for_insn (max_uid);
|
||||
|
||||
/* Discover the edges of our cfg. */
|
||||
record_active_eh_regions (f);
|
||||
make_edges (label_value_list);
|
||||
|
||||
/* Do very simple cleanup now, for the benefit of code that runs between
|
||||
@ -599,46 +592,45 @@ count_basic_blocks (f)
|
||||
register rtx insn;
|
||||
register RTX_CODE prev_code;
|
||||
register int count = 0;
|
||||
int eh_region = 0;
|
||||
int call_had_abnormal_edge = 0;
|
||||
int saw_abnormal_edge = 0;
|
||||
|
||||
prev_code = JUMP_INSN;
|
||||
for (insn = f; insn; insn = NEXT_INSN (insn))
|
||||
{
|
||||
register RTX_CODE code = GET_CODE (insn);
|
||||
enum rtx_code code = GET_CODE (insn);
|
||||
|
||||
if (code == CODE_LABEL
|
||||
|| (GET_RTX_CLASS (code) == 'i'
|
||||
&& (prev_code == JUMP_INSN
|
||||
|| prev_code == BARRIER
|
||||
|| (prev_code == CALL_INSN && call_had_abnormal_edge))))
|
||||
count++;
|
||||
|| saw_abnormal_edge)))
|
||||
{
|
||||
saw_abnormal_edge = 0;
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Record whether this call created an edge. */
|
||||
/* Record whether this insn created an edge. */
|
||||
if (code == CALL_INSN)
|
||||
{
|
||||
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
|
||||
int region = (note ? INTVAL (XEXP (note, 0)) : 1);
|
||||
rtx note;
|
||||
|
||||
call_had_abnormal_edge = 0;
|
||||
/* If there is a nonlocal goto label and the specified
|
||||
region number isn't -1, we have an edge. */
|
||||
if (nonlocal_goto_handler_labels
|
||||
&& ((note = find_reg_note (insn, REG_EH_REGION, NULL_RTX)) == 0
|
||||
|| INTVAL (XEXP (note, 0)) >= 0))
|
||||
saw_abnormal_edge = 1;
|
||||
|
||||
/* If there is an EH region or rethrow, we have an edge. */
|
||||
if ((eh_region && region > 0)
|
||||
|| find_reg_note (insn, REG_EH_RETHROW, NULL_RTX))
|
||||
call_had_abnormal_edge = 1;
|
||||
else if (nonlocal_goto_handler_labels && region >= 0)
|
||||
/* If there is a nonlocal goto label and the specified
|
||||
region number isn't -1, we have an edge. (0 means
|
||||
no throw, but might have a nonlocal goto). */
|
||||
call_had_abnormal_edge = 1;
|
||||
else if (can_throw_internal (insn))
|
||||
saw_abnormal_edge = 1;
|
||||
}
|
||||
else if (flag_non_call_exceptions
|
||||
&& code == INSN
|
||||
&& can_throw_internal (insn))
|
||||
saw_abnormal_edge = 1;
|
||||
|
||||
if (code != NOTE)
|
||||
prev_code = code;
|
||||
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
|
||||
++eh_region;
|
||||
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
|
||||
--eh_region;
|
||||
}
|
||||
|
||||
/* The rest of the compiler works a bit smoother when we don't have to
|
||||
@ -672,9 +664,6 @@ find_label_refs (f, lvl)
|
||||
Make a special exception for labels followed by an ADDR*VEC,
|
||||
as this would be a part of the tablejump setup code.
|
||||
|
||||
Make a special exception for the eh_return_stub_label, which
|
||||
we know isn't part of any otherwise visible control flow.
|
||||
|
||||
Make a special exception to registers loaded with label
|
||||
values just before jump insns that use them. */
|
||||
|
||||
@ -683,9 +672,7 @@ find_label_refs (f, lvl)
|
||||
{
|
||||
rtx lab = XEXP (note, 0), next;
|
||||
|
||||
if (lab == eh_return_stub_label)
|
||||
;
|
||||
else if ((next = next_nonnote_insn (lab)) != NULL
|
||||
if ((next = next_nonnote_insn (lab)) != NULL
|
||||
&& GET_CODE (next) == JUMP_INSN
|
||||
&& (GET_CODE (PATTERN (next)) == ADDR_VEC
|
||||
|| GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
|
||||
@ -815,7 +802,6 @@ find_basic_blocks_1 (f)
|
||||
register rtx insn, next;
|
||||
int i = 0;
|
||||
rtx bb_note = NULL_RTX;
|
||||
rtx eh_list = NULL_RTX;
|
||||
rtx lvl = NULL_RTX;
|
||||
rtx trll = NULL_RTX;
|
||||
rtx head = NULL_RTX;
|
||||
@ -839,22 +825,11 @@ find_basic_blocks_1 (f)
|
||||
{
|
||||
int kind = NOTE_LINE_NUMBER (insn);
|
||||
|
||||
/* Keep a LIFO list of the currently active exception notes. */
|
||||
if (kind == NOTE_INSN_EH_REGION_BEG)
|
||||
eh_list = alloc_INSN_LIST (insn, eh_list);
|
||||
else if (kind == NOTE_INSN_EH_REGION_END)
|
||||
{
|
||||
rtx t = eh_list;
|
||||
|
||||
eh_list = XEXP (eh_list, 1);
|
||||
free_INSN_LIST_node (t);
|
||||
}
|
||||
|
||||
/* Look for basic block notes with which to keep the
|
||||
basic_block_info pointers stable. Unthread the note now;
|
||||
we'll put it back at the right place in create_basic_block.
|
||||
Or not at all if we've already found a note in this block. */
|
||||
else if (kind == NOTE_INSN_BASIC_BLOCK)
|
||||
if (kind == NOTE_INSN_BASIC_BLOCK)
|
||||
{
|
||||
if (bb_note == NULL_RTX)
|
||||
bb_note = insn;
|
||||
@ -938,8 +913,7 @@ find_basic_blocks_1 (f)
|
||||
{
|
||||
/* Record whether this call created an edge. */
|
||||
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
|
||||
int region = (note ? INTVAL (XEXP (note, 0)) : 1);
|
||||
int call_has_abnormal_edge = 0;
|
||||
int region = (note ? INTVAL (XEXP (note, 0)) : 0);
|
||||
|
||||
if (GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
|
||||
{
|
||||
@ -952,19 +926,10 @@ find_basic_blocks_1 (f)
|
||||
trll = alloc_EXPR_LIST (0, XEXP (PATTERN (insn), 3), trll);
|
||||
}
|
||||
|
||||
/* If there is an EH region or rethrow, we have an edge. */
|
||||
if ((eh_list && region > 0)
|
||||
|| find_reg_note (insn, REG_EH_RETHROW, NULL_RTX))
|
||||
call_has_abnormal_edge = 1;
|
||||
else if (nonlocal_goto_handler_labels && region >= 0)
|
||||
/* If there is a nonlocal goto label and the specified
|
||||
region number isn't -1, we have an edge. (0 means
|
||||
no throw, but might have a nonlocal goto). */
|
||||
call_has_abnormal_edge = 1;
|
||||
|
||||
/* A basic block ends at a call that can either throw or
|
||||
do a non-local goto. */
|
||||
if (call_has_abnormal_edge)
|
||||
if ((nonlocal_goto_handler_labels && region >= 0)
|
||||
|| can_throw_internal (insn))
|
||||
{
|
||||
new_bb_inclusive:
|
||||
if (head == NULL_RTX)
|
||||
@ -980,18 +945,21 @@ find_basic_blocks_1 (f)
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
default:
|
||||
if (GET_RTX_CLASS (code) == 'i')
|
||||
{
|
||||
if (head == NULL_RTX)
|
||||
head = insn;
|
||||
end = insn;
|
||||
}
|
||||
case INSN:
|
||||
/* Non-call exceptions generate new blocks just like calls. */
|
||||
if (flag_non_call_exceptions && can_throw_internal (insn))
|
||||
goto new_bb_inclusive;
|
||||
|
||||
if (head == NULL_RTX)
|
||||
head = insn;
|
||||
end = insn;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (GET_RTX_CLASS (code) == 'i'
|
||||
&& GET_CODE (insn) != JUMP_INSN)
|
||||
if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
|
||||
{
|
||||
rtx note;
|
||||
|
||||
@ -1000,9 +968,6 @@ find_basic_blocks_1 (f)
|
||||
Make a special exception for labels followed by an ADDR*VEC,
|
||||
as this would be a part of the tablejump setup code.
|
||||
|
||||
Make a special exception for the eh_return_stub_label, which
|
||||
we know isn't part of any otherwise visible control flow.
|
||||
|
||||
Make a special exception to registers loaded with label
|
||||
values just before jump insns that use them. */
|
||||
|
||||
@ -1011,9 +976,7 @@ find_basic_blocks_1 (f)
|
||||
{
|
||||
rtx lab = XEXP (note, 0), next;
|
||||
|
||||
if (lab == eh_return_stub_label)
|
||||
;
|
||||
else if ((next = next_nonnote_insn (lab)) != NULL
|
||||
if ((next = next_nonnote_insn (lab)) != NULL
|
||||
&& GET_CODE (next) == JUMP_INSN
|
||||
&& (GET_CODE (PATTERN (next)) == ADDR_VEC
|
||||
|| GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
|
||||
@ -1047,8 +1010,6 @@ void
|
||||
cleanup_cfg ()
|
||||
{
|
||||
delete_unreachable_blocks ();
|
||||
move_stray_eh_region_notes ();
|
||||
record_active_eh_regions (get_insns ());
|
||||
try_merge_blocks ();
|
||||
mark_critical_edges ();
|
||||
|
||||
@ -1201,7 +1162,6 @@ make_edges (label_value_list)
|
||||
rtx label_value_list;
|
||||
{
|
||||
int i;
|
||||
eh_nesting_info *eh_nest_info = init_eh_nesting_info ();
|
||||
sbitmap *edge_cache = NULL;
|
||||
|
||||
/* Assume no computed jump; revise as we create edges. */
|
||||
@ -1241,9 +1201,13 @@ make_edges (label_value_list)
|
||||
{
|
||||
rtx tmp;
|
||||
|
||||
/* Recognize exception handling placeholders. */
|
||||
if (GET_CODE (PATTERN (insn)) == RESX)
|
||||
make_eh_edge (edge_cache, bb, insn);
|
||||
|
||||
/* Recognize a non-local goto as a branch outside the
|
||||
current function. */
|
||||
if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
|
||||
else if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
|
||||
;
|
||||
|
||||
/* ??? Recognize a tablejump and do the right thing. */
|
||||
@ -1318,37 +1282,15 @@ make_edges (label_value_list)
|
||||
EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
|
||||
|
||||
/* If this is a CALL_INSN, then mark it as reaching the active EH
|
||||
handler for this CALL_INSN. If we're handling asynchronous
|
||||
handler for this CALL_INSN. If we're handling non-call
|
||||
exceptions then any insn can reach any of the active handlers.
|
||||
|
||||
Also mark the CALL_INSN as reaching any nonlocal goto handler. */
|
||||
|
||||
else if (code == CALL_INSN || flag_non_call_exceptions)
|
||||
{
|
||||
/* Add any appropriate EH edges. We do this unconditionally
|
||||
since there may be a REG_EH_REGION or REG_EH_RETHROW note
|
||||
on the call, and this needn't be within an EH region. */
|
||||
make_eh_edge (edge_cache, eh_nest_info, bb, insn, bb->eh_end);
|
||||
|
||||
/* If we have asynchronous exceptions, do the same for *all*
|
||||
exception regions active in the block. */
|
||||
if (flag_non_call_exceptions
|
||||
&& bb->eh_beg != bb->eh_end)
|
||||
{
|
||||
if (bb->eh_beg >= 0)
|
||||
make_eh_edge (edge_cache, eh_nest_info, bb,
|
||||
NULL_RTX, bb->eh_beg);
|
||||
|
||||
for (x = bb->head; x != bb->end; x = NEXT_INSN (x))
|
||||
if (GET_CODE (x) == NOTE
|
||||
&& (NOTE_LINE_NUMBER (x) == NOTE_INSN_EH_REGION_BEG
|
||||
|| NOTE_LINE_NUMBER (x) == NOTE_INSN_EH_REGION_END))
|
||||
{
|
||||
int region = NOTE_EH_HANDLER (x);
|
||||
make_eh_edge (edge_cache, eh_nest_info, bb,
|
||||
NULL_RTX, region);
|
||||
}
|
||||
}
|
||||
/* Add any appropriate EH edges. */
|
||||
make_eh_edge (edge_cache, bb, insn);
|
||||
|
||||
if (code == CALL_INSN && nonlocal_goto_handler_labels)
|
||||
{
|
||||
@ -1369,14 +1311,6 @@ make_edges (label_value_list)
|
||||
}
|
||||
}
|
||||
|
||||
/* We know something about the structure of the function __throw in
|
||||
libgcc2.c. It is the only function that ever contains eh_stub
|
||||
labels. It modifies its return address so that the last block
|
||||
returns to one of the eh_stub labels within it. So we have to
|
||||
make additional edges in the flow graph. */
|
||||
if (i + 1 == n_basic_blocks && eh_return_stub_label != 0)
|
||||
make_label_edge (edge_cache, bb, eh_return_stub_label, EDGE_EH);
|
||||
|
||||
/* Find out if we can drop through to the next block. */
|
||||
insn = next_nonnote_insn (insn);
|
||||
if (!insn || (i + 1 == n_basic_blocks && force_fallthru))
|
||||
@ -1391,7 +1325,6 @@ make_edges (label_value_list)
|
||||
}
|
||||
}
|
||||
|
||||
free_eh_nesting_info (eh_nest_info);
|
||||
if (edge_cache)
|
||||
sbitmap_vector_free (edge_cache);
|
||||
}
|
||||
@ -1479,115 +1412,21 @@ make_label_edge (edge_cache, src, label, flags)
|
||||
/* Create the edges generated by INSN in REGION. */
|
||||
|
||||
static void
|
||||
make_eh_edge (edge_cache, eh_nest_info, src, insn, region)
|
||||
make_eh_edge (edge_cache, src, insn)
|
||||
sbitmap *edge_cache;
|
||||
eh_nesting_info *eh_nest_info;
|
||||
basic_block src;
|
||||
rtx insn;
|
||||
int region;
|
||||
{
|
||||
handler_info **handler_list;
|
||||
int num, is_call;
|
||||
int is_call = (GET_CODE (insn) == CALL_INSN ? EDGE_ABNORMAL_CALL : 0);
|
||||
rtx handlers, i;
|
||||
|
||||
is_call = (insn && GET_CODE (insn) == CALL_INSN ? EDGE_ABNORMAL_CALL : 0);
|
||||
num = reachable_handlers (region, eh_nest_info, insn, &handler_list);
|
||||
while (--num >= 0)
|
||||
{
|
||||
make_label_edge (edge_cache, src, handler_list[num]->handler_label,
|
||||
EDGE_ABNORMAL | EDGE_EH | is_call);
|
||||
}
|
||||
}
|
||||
handlers = reachable_handlers (insn);
|
||||
|
||||
/* EH_REGION notes appearing between basic blocks is ambiguous, and even
|
||||
dangerous if we intend to move basic blocks around. Move such notes
|
||||
into the following block. */
|
||||
for (i = handlers; i; i = XEXP (i, 1))
|
||||
make_label_edge (edge_cache, src, XEXP (i, 0),
|
||||
EDGE_ABNORMAL | EDGE_EH | is_call);
|
||||
|
||||
static void
|
||||
move_stray_eh_region_notes ()
|
||||
{
|
||||
int i;
|
||||
basic_block b1, b2;
|
||||
|
||||
if (n_basic_blocks < 2)
|
||||
return;
|
||||
|
||||
b2 = BASIC_BLOCK (n_basic_blocks - 1);
|
||||
for (i = n_basic_blocks - 2; i >= 0; --i, b2 = b1)
|
||||
{
|
||||
rtx insn, next, list = NULL_RTX;
|
||||
|
||||
b1 = BASIC_BLOCK (i);
|
||||
for (insn = NEXT_INSN (b1->end); insn != b2->head; insn = next)
|
||||
{
|
||||
next = NEXT_INSN (insn);
|
||||
if (GET_CODE (insn) == NOTE
|
||||
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
|
||||
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
|
||||
{
|
||||
/* Unlink from the insn chain. */
|
||||
NEXT_INSN (PREV_INSN (insn)) = next;
|
||||
PREV_INSN (next) = PREV_INSN (insn);
|
||||
|
||||
/* Queue it. */
|
||||
NEXT_INSN (insn) = list;
|
||||
list = insn;
|
||||
}
|
||||
}
|
||||
|
||||
if (list == NULL_RTX)
|
||||
continue;
|
||||
|
||||
/* Find where to insert these things. */
|
||||
insn = b2->head;
|
||||
if (GET_CODE (insn) == CODE_LABEL)
|
||||
insn = NEXT_INSN (insn);
|
||||
|
||||
while (list)
|
||||
{
|
||||
next = NEXT_INSN (list);
|
||||
add_insn_after (list, insn);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Recompute eh_beg/eh_end for each basic block. */
|
||||
|
||||
static void
|
||||
record_active_eh_regions (f)
|
||||
rtx f;
|
||||
{
|
||||
rtx insn, eh_list = NULL_RTX;
|
||||
int i = 0;
|
||||
basic_block bb = BASIC_BLOCK (0);
|
||||
|
||||
for (insn = f; insn; insn = NEXT_INSN (insn))
|
||||
{
|
||||
if (bb->head == insn)
|
||||
bb->eh_beg = (eh_list ? NOTE_EH_HANDLER (XEXP (eh_list, 0)) : -1);
|
||||
|
||||
if (GET_CODE (insn) == NOTE)
|
||||
{
|
||||
int kind = NOTE_LINE_NUMBER (insn);
|
||||
if (kind == NOTE_INSN_EH_REGION_BEG)
|
||||
eh_list = alloc_INSN_LIST (insn, eh_list);
|
||||
else if (kind == NOTE_INSN_EH_REGION_END)
|
||||
{
|
||||
rtx t = XEXP (eh_list, 1);
|
||||
free_INSN_LIST_node (eh_list);
|
||||
eh_list = t;
|
||||
}
|
||||
}
|
||||
|
||||
if (bb->end == insn)
|
||||
{
|
||||
bb->eh_end = (eh_list ? NOTE_EH_HANDLER (XEXP (eh_list, 0)) : -1);
|
||||
i += 1;
|
||||
if (i == n_basic_blocks)
|
||||
break;
|
||||
bb = BASIC_BLOCK (i);
|
||||
}
|
||||
}
|
||||
free_INSN_LIST_list (&handlers);
|
||||
}
|
||||
|
||||
/* Identify critical edges and set the bits appropriately. */
|
||||
@ -2223,7 +2062,6 @@ static void
|
||||
delete_unreachable_blocks ()
|
||||
{
|
||||
basic_block *worklist, *tos;
|
||||
int deleted_handler;
|
||||
edge e;
|
||||
int i, n;
|
||||
|
||||
@ -2261,10 +2099,9 @@ delete_unreachable_blocks ()
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete all unreachable basic blocks. Count down so that we don't
|
||||
interfere with the block renumbering that happens in flow_delete_block. */
|
||||
|
||||
deleted_handler = 0;
|
||||
/* Delete all unreachable basic blocks. Count down so that we
|
||||
don't interfere with the block renumbering that happens in
|
||||
flow_delete_block. */
|
||||
|
||||
for (i = n - 1; i >= 0; --i)
|
||||
{
|
||||
@ -2274,46 +2111,14 @@ delete_unreachable_blocks ()
|
||||
/* This block was found. Tidy up the mark. */
|
||||
b->aux = NULL;
|
||||
else
|
||||
deleted_handler |= flow_delete_block (b);
|
||||
flow_delete_block (b);
|
||||
}
|
||||
|
||||
tidy_fallthru_edges ();
|
||||
|
||||
/* If we deleted an exception handler, we may have EH region begin/end
|
||||
blocks to remove as well. */
|
||||
if (deleted_handler)
|
||||
delete_eh_regions ();
|
||||
|
||||
free (worklist);
|
||||
}
|
||||
|
||||
/* Find EH regions for which there is no longer a handler, and delete them. */
|
||||
|
||||
static void
|
||||
delete_eh_regions ()
|
||||
{
|
||||
rtx insn;
|
||||
|
||||
update_rethrow_references ();
|
||||
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
if (GET_CODE (insn) == NOTE)
|
||||
{
|
||||
if ((NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
|
||||
|| (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
|
||||
{
|
||||
int num = NOTE_EH_HANDLER (insn);
|
||||
/* A NULL handler indicates a region is no longer needed,
|
||||
as long as its rethrow label isn't used. */
|
||||
if (get_first_handler (num) == NULL && ! rethrow_used (num))
|
||||
{
|
||||
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
||||
NOTE_SOURCE_FILE (insn) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true if NOTE is not one of the ones that must be kept paired,
|
||||
so that we may simply delete them. */
|
||||
|
||||
@ -2387,26 +2192,7 @@ flow_delete_block (b)
|
||||
never_reached_warning (insn);
|
||||
|
||||
if (GET_CODE (insn) == CODE_LABEL)
|
||||
{
|
||||
rtx x, *prev = &exception_handler_labels;
|
||||
|
||||
for (x = exception_handler_labels; x; x = XEXP (x, 1))
|
||||
{
|
||||
if (XEXP (x, 0) == insn)
|
||||
{
|
||||
/* Found a match, splice this label out of the EH label list. */
|
||||
*prev = XEXP (x, 1);
|
||||
XEXP (x, 1) = NULL_RTX;
|
||||
XEXP (x, 0) = NULL_RTX;
|
||||
|
||||
/* Remove the handler from all regions */
|
||||
remove_handler (insn);
|
||||
deleted_handler = 1;
|
||||
break;
|
||||
}
|
||||
prev = &XEXP (x, 1);
|
||||
}
|
||||
}
|
||||
maybe_remove_eh_handler (insn);
|
||||
|
||||
/* Include any jump table following the basic block. */
|
||||
end = b->end;
|
||||
@ -2804,7 +2590,6 @@ merge_blocks (e, b, c)
|
||||
else
|
||||
{
|
||||
edge tmp_edge;
|
||||
basic_block d;
|
||||
int c_has_outgoing_fallthru;
|
||||
int b_has_incoming_fallthru;
|
||||
|
||||
@ -2832,37 +2617,22 @@ merge_blocks (e, b, c)
|
||||
break;
|
||||
b_has_incoming_fallthru = (tmp_edge != NULL);
|
||||
|
||||
/* If B does not have an incoming fallthru, and the exception regions
|
||||
match, then it can be moved immediately before C without introducing
|
||||
or modifying jumps.
|
||||
|
||||
C can not be the first block, so we do not have to worry about
|
||||
/* If B does not have an incoming fallthru, then it can be moved
|
||||
immediately before C without introducing or modifying jumps.
|
||||
C cannot be the first block, so we do not have to worry about
|
||||
accessing a non-existent block. */
|
||||
d = BASIC_BLOCK (c->index - 1);
|
||||
if (! b_has_incoming_fallthru
|
||||
&& d->eh_end == b->eh_beg
|
||||
&& b->eh_end == c->eh_beg)
|
||||
if (! b_has_incoming_fallthru)
|
||||
return merge_blocks_move_predecessor_nojumps (b, c);
|
||||
|
||||
/* Otherwise, we're going to try to move C after B. Make sure the
|
||||
exception regions match.
|
||||
/* Otherwise, we're going to try to move C after B. If C does
|
||||
not have an outgoing fallthru, then it can be moved
|
||||
immediately after B without introducing or modifying jumps. */
|
||||
if (! c_has_outgoing_fallthru)
|
||||
return merge_blocks_move_successor_nojumps (b, c);
|
||||
|
||||
If B is the last basic block, then we must not try to access the
|
||||
block structure for block B + 1. Luckily in that case we do not
|
||||
need to worry about matching exception regions. */
|
||||
d = (b->index + 1 < n_basic_blocks ? BASIC_BLOCK (b->index + 1) : NULL);
|
||||
if (b->eh_end == c->eh_beg
|
||||
&& (d == NULL || c->eh_end == d->eh_beg))
|
||||
{
|
||||
/* If C does not have an outgoing fallthru, then it can be moved
|
||||
immediately after B without introducing or modifying jumps. */
|
||||
if (! c_has_outgoing_fallthru)
|
||||
return merge_blocks_move_successor_nojumps (b, c);
|
||||
|
||||
/* Otherwise, we'll need to insert an extra jump, and possibly
|
||||
a new block to contain it. */
|
||||
/* ??? Not implemented yet. */
|
||||
}
|
||||
/* Otherwise, we'll need to insert an extra jump, and possibly
|
||||
a new block to contain it. */
|
||||
/* ??? Not implemented yet. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3502,14 +3272,44 @@ mark_regs_live_at_end (set)
|
||||
if (global_regs[i] || EPILOGUE_USES (i))
|
||||
SET_REGNO_REG_SET (set, i);
|
||||
|
||||
/* Mark all call-saved registers that we actaully used. */
|
||||
if (HAVE_epilogue && reload_completed)
|
||||
{
|
||||
/* Mark all call-saved registers that we actually used. */
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||
if (regs_ever_live[i] && ! call_used_regs[i] && ! LOCAL_REGNO (i))
|
||||
SET_REGNO_REG_SET (set, i);
|
||||
}
|
||||
|
||||
#ifdef EH_RETURN_DATA_REGNO
|
||||
/* Mark the registers that will contain data for the handler. */
|
||||
if (reload_completed && current_function_calls_eh_return)
|
||||
for (i = 0; ; ++i)
|
||||
{
|
||||
unsigned regno = EH_RETURN_DATA_REGNO(i);
|
||||
if (regno == INVALID_REGNUM)
|
||||
break;
|
||||
SET_REGNO_REG_SET (set, regno);
|
||||
}
|
||||
#endif
|
||||
#ifdef EH_RETURN_STACKADJ_RTX
|
||||
if ((! HAVE_epilogue || ! reload_completed)
|
||||
&& current_function_calls_eh_return)
|
||||
{
|
||||
rtx tmp = EH_RETURN_STACKADJ_RTX;
|
||||
if (tmp && REG_P (tmp))
|
||||
mark_reg (tmp, set);
|
||||
}
|
||||
#endif
|
||||
#ifdef EH_RETURN_HANDLER_RTX
|
||||
if ((! HAVE_epilogue || ! reload_completed)
|
||||
&& current_function_calls_eh_return)
|
||||
{
|
||||
rtx tmp = EH_RETURN_HANDLER_RTX;
|
||||
if (tmp && REG_P (tmp))
|
||||
mark_reg (tmp, set);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Mark function return value. */
|
||||
diddle_return_value (mark_reg, set);
|
||||
}
|
||||
@ -4249,7 +4049,8 @@ init_propagate_block_info (bb, live, local_set, cond_local_set, flags)
|
||||
&& (flags & PROP_SCAN_DEAD_CODE)
|
||||
&& (bb->succ == NULL
|
||||
|| (bb->succ->succ_next == NULL
|
||||
&& bb->succ->dest == EXIT_BLOCK_PTR)))
|
||||
&& bb->succ->dest == EXIT_BLOCK_PTR
|
||||
&& ! current_function_calls_eh_return)))
|
||||
{
|
||||
rtx insn, set;
|
||||
for (insn = bb->end; insn != bb->head; insn = PREV_INSN (insn))
|
||||
@ -6631,8 +6432,6 @@ dump_bb (bb, outf)
|
||||
|
||||
fprintf (outf, ";; Basic block %d, loop depth %d, count %d",
|
||||
bb->index, bb->loop_depth, bb->count);
|
||||
if (bb->eh_beg != -1 || bb->eh_end != -1)
|
||||
fprintf (outf, ", eh regions %d/%d", bb->eh_beg, bb->eh_end);
|
||||
putc ('\n', outf);
|
||||
|
||||
fputs (";; Predecessors: ", outf);
|
||||
|
@ -1,778 +0,0 @@
|
||||
/* Subroutines needed for unwinding DWARF 2 format stack frame info
|
||||
for exception handling. */
|
||||
/* Compile this one with gcc. */
|
||||
/* Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
Contributed by Jason Merrill <jason@cygnus.com>.
|
||||
|
||||
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.
|
||||
|
||||
In addition to the permissions in the GNU General Public License, the
|
||||
Free Software Foundation gives you unlimited permission to link the
|
||||
compiled version of this file into combinations with other programs,
|
||||
and to distribute those combinations without any restriction coming
|
||||
from the use of this file. (The General Public License restrictions
|
||||
do apply in other respects; for example, they cover modification of
|
||||
the file, and distribution when not linked into a combine
|
||||
executable.)
|
||||
|
||||
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. */
|
||||
|
||||
/* It is incorrect to include config.h here, because this file is being
|
||||
compiled for the target, and hence definitions concerning only the host
|
||||
do not apply. */
|
||||
|
||||
#include "tconfig.h"
|
||||
#include "tsystem.h"
|
||||
|
||||
#ifdef DWARF2_UNWIND_INFO
|
||||
#include "dwarf2.h"
|
||||
#include "frame.h"
|
||||
#include "gthr.h"
|
||||
|
||||
#ifdef __GTHREAD_MUTEX_INIT
|
||||
static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
|
||||
#else
|
||||
static __gthread_mutex_t object_mutex;
|
||||
#endif
|
||||
|
||||
/* Don't use `fancy_abort' here even if config.h says to use it. */
|
||||
#ifdef abort
|
||||
#undef abort
|
||||
#endif
|
||||
|
||||
/* Some types used by the DWARF 2 spec. */
|
||||
|
||||
typedef int sword __attribute__ ((mode (SI)));
|
||||
typedef unsigned int uword __attribute__ ((mode (SI)));
|
||||
typedef unsigned int uaddr __attribute__ ((mode (pointer)));
|
||||
typedef int saddr __attribute__ ((mode (pointer)));
|
||||
typedef unsigned char ubyte;
|
||||
|
||||
/* Terminology:
|
||||
CIE - Common Information Element
|
||||
FDE - Frame Descriptor Element
|
||||
|
||||
There is one per function, and it describes where the function code
|
||||
is located, and what the register lifetimes and stack layout are
|
||||
within the function.
|
||||
|
||||
The data structures are defined in the DWARF specfication, although
|
||||
not in a very readable way (see LITERATURE).
|
||||
|
||||
Every time an exception is thrown, the code needs to locate the FDE
|
||||
for the current function, and starts to look for exception regions
|
||||
from that FDE. This works in a two-level search:
|
||||
a) in a linear search, find the shared image (i.e. DLL) containing
|
||||
the PC
|
||||
b) using the FDE table for that shared object, locate the FDE using
|
||||
binary search (which requires the sorting). */
|
||||
|
||||
/* The first few fields of a CIE. The CIE_id field is 0 for a CIE,
|
||||
to distinguish it from a valid FDE. FDEs are aligned to an addressing
|
||||
unit boundary, but the fields within are unaligned. */
|
||||
|
||||
struct dwarf_cie {
|
||||
uword length;
|
||||
sword CIE_id;
|
||||
ubyte version;
|
||||
char augmentation[0];
|
||||
} __attribute__ ((packed, aligned (__alignof__ (void *))));
|
||||
|
||||
/* The first few fields of an FDE. */
|
||||
|
||||
struct dwarf_fde {
|
||||
uword length;
|
||||
sword CIE_delta;
|
||||
void* pc_begin;
|
||||
uaddr pc_range;
|
||||
} __attribute__ ((packed, aligned (__alignof__ (void *))));
|
||||
|
||||
typedef struct dwarf_fde fde;
|
||||
|
||||
/* Objects to be searched for frame unwind info. */
|
||||
|
||||
static struct object *objects;
|
||||
|
||||
/* The information we care about from a CIE. */
|
||||
|
||||
struct cie_info {
|
||||
char *augmentation;
|
||||
void *eh_ptr;
|
||||
int code_align;
|
||||
int data_align;
|
||||
unsigned ra_regno;
|
||||
};
|
||||
|
||||
/* The current unwind state, plus a saved copy for DW_CFA_remember_state. */
|
||||
|
||||
struct frame_state_internal
|
||||
{
|
||||
struct frame_state s;
|
||||
struct frame_state_internal *saved_state;
|
||||
};
|
||||
|
||||
/* This is undefined below if we need it to be an actual function. */
|
||||
#define init_object_mutex_once()
|
||||
|
||||
#if __GTHREADS
|
||||
#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
|
||||
|
||||
/* Helper for init_object_mutex_once. */
|
||||
|
||||
static void
|
||||
init_object_mutex (void)
|
||||
{
|
||||
__GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
|
||||
}
|
||||
|
||||
/* Call this to arrange to initialize the object mutex. */
|
||||
|
||||
#undef init_object_mutex_once
|
||||
static void
|
||||
init_object_mutex_once (void)
|
||||
{
|
||||
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
|
||||
__gthread_once (&once, init_object_mutex);
|
||||
}
|
||||
|
||||
#endif /* __GTHREAD_MUTEX_INIT_FUNCTION */
|
||||
#endif /* __GTHREADS */
|
||||
|
||||
/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
|
||||
by R, and return the new value of BUF. */
|
||||
|
||||
static void *
|
||||
decode_uleb128 (unsigned char *buf, unsigned *r)
|
||||
{
|
||||
unsigned shift = 0;
|
||||
unsigned result = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
unsigned byte = *buf++;
|
||||
result |= (byte & 0x7f) << shift;
|
||||
if ((byte & 0x80) == 0)
|
||||
break;
|
||||
shift += 7;
|
||||
}
|
||||
*r = result;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Decode the signed LEB128 constant at BUF into the variable pointed to
|
||||
by R, and return the new value of BUF. */
|
||||
|
||||
static void *
|
||||
decode_sleb128 (unsigned char *buf, int *r)
|
||||
{
|
||||
unsigned shift = 0;
|
||||
unsigned result = 0;
|
||||
unsigned byte;
|
||||
|
||||
while (1)
|
||||
{
|
||||
byte = *buf++;
|
||||
result |= (byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
if ((byte & 0x80) == 0)
|
||||
break;
|
||||
}
|
||||
if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
|
||||
result |= - (1 << shift);
|
||||
|
||||
*r = result;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Read unaligned data from the instruction buffer. */
|
||||
|
||||
union unaligned {
|
||||
void *p;
|
||||
unsigned b2 __attribute__ ((mode (HI)));
|
||||
unsigned b4 __attribute__ ((mode (SI)));
|
||||
unsigned b8 __attribute__ ((mode (DI)));
|
||||
} __attribute__ ((packed));
|
||||
static inline void *
|
||||
read_pointer (void *p)
|
||||
{ union unaligned *up = p; return up->p; }
|
||||
static inline unsigned
|
||||
read_1byte (void *p)
|
||||
{ return *(unsigned char *)p; }
|
||||
static inline unsigned
|
||||
read_2byte (void *p)
|
||||
{ union unaligned *up = p; return up->b2; }
|
||||
static inline unsigned
|
||||
read_4byte (void *p)
|
||||
{ union unaligned *up = p; return up->b4; }
|
||||
static inline unsigned long
|
||||
read_8byte (void *p)
|
||||
{ union unaligned *up = p; return up->b8; }
|
||||
|
||||
/* Ordering function for FDEs. Functions can't overlap, so we just compare
|
||||
their starting addresses. */
|
||||
|
||||
static inline saddr
|
||||
fde_compare (fde *x, fde *y)
|
||||
{
|
||||
return (saddr)x->pc_begin - (saddr)y->pc_begin;
|
||||
}
|
||||
|
||||
/* Return the address of the FDE after P. */
|
||||
|
||||
static inline fde *
|
||||
next_fde (fde *p)
|
||||
{
|
||||
return (fde *)(((char *)p) + p->length + sizeof (p->length));
|
||||
}
|
||||
|
||||
#include "frame.c"
|
||||
|
||||
static size_t
|
||||
count_fdes (fde *this_fde)
|
||||
{
|
||||
size_t count;
|
||||
|
||||
for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs and linked once FDE entries. */
|
||||
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
|
||||
continue;
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr)
|
||||
{
|
||||
void *pc_begin = *beg_ptr;
|
||||
void *pc_end = *end_ptr;
|
||||
|
||||
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs and linked once FDE entries. */
|
||||
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
|
||||
continue;
|
||||
|
||||
fde_insert (accu, this_fde);
|
||||
|
||||
if (this_fde->pc_begin < pc_begin)
|
||||
pc_begin = this_fde->pc_begin;
|
||||
if (this_fde->pc_begin + this_fde->pc_range > pc_end)
|
||||
pc_end = this_fde->pc_begin + this_fde->pc_range;
|
||||
}
|
||||
|
||||
*beg_ptr = pc_begin;
|
||||
*end_ptr = pc_end;
|
||||
}
|
||||
|
||||
/* search this fde table for the one containing the pc */
|
||||
static fde *
|
||||
search_fdes (fde *this_fde, void *pc)
|
||||
{
|
||||
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs and linked once FDE entries. */
|
||||
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
|
||||
continue;
|
||||
|
||||
if ((uaddr)((char *)pc - (char *)this_fde->pc_begin) < this_fde->pc_range)
|
||||
return this_fde;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set up a sorted array of pointers to FDEs for a loaded object. We
|
||||
count up the entries before allocating the array because it's likely to
|
||||
be faster. We can be called multiple times, should we have failed to
|
||||
allocate a sorted fde array on a previous occasion. */
|
||||
|
||||
static void
|
||||
frame_init (struct object* ob)
|
||||
{
|
||||
size_t count;
|
||||
fde_accumulator accu;
|
||||
void *pc_begin, *pc_end;
|
||||
fde **array;
|
||||
|
||||
if (ob->pc_begin)
|
||||
count = ob->count;
|
||||
else if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
for (count = 0; *p; ++p)
|
||||
count += count_fdes (*p);
|
||||
}
|
||||
else
|
||||
count = count_fdes (ob->fde_begin);
|
||||
ob->count = count;
|
||||
|
||||
if (!start_fde_sort (&accu, count) && ob->pc_begin)
|
||||
return;
|
||||
|
||||
pc_begin = (void*)(uaddr)-1;
|
||||
pc_end = 0;
|
||||
|
||||
if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
for (; *p; ++p)
|
||||
add_fdes (*p, &accu, &pc_begin, &pc_end);
|
||||
}
|
||||
else
|
||||
add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end);
|
||||
|
||||
array = end_fde_sort (&accu, count);
|
||||
if (array)
|
||||
ob->fde_array = array;
|
||||
ob->pc_begin = pc_begin;
|
||||
ob->pc_end = pc_end;
|
||||
}
|
||||
|
||||
/* Return a pointer to the FDE for the function containing PC. */
|
||||
|
||||
static fde *
|
||||
find_fde (void *pc)
|
||||
{
|
||||
struct object *ob;
|
||||
size_t lo, hi;
|
||||
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
|
||||
/* Linear search through the objects, to find the one containing the pc. */
|
||||
for (ob = objects; ob; ob = ob->next)
|
||||
{
|
||||
if (ob->pc_begin == 0)
|
||||
frame_init (ob);
|
||||
if (pc >= ob->pc_begin && pc < ob->pc_end)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ob == 0)
|
||||
{
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ob->fde_array || (void *)ob->fde_array == (void *)ob->fde_begin)
|
||||
frame_init (ob);
|
||||
|
||||
if (ob->fde_array && (void *)ob->fde_array != (void *)ob->fde_begin)
|
||||
{
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
|
||||
/* Standard binary search algorithm. */
|
||||
for (lo = 0, hi = ob->count; lo < hi; )
|
||||
{
|
||||
size_t i = (lo + hi) / 2;
|
||||
fde *f = ob->fde_array[i];
|
||||
|
||||
if (pc < f->pc_begin)
|
||||
hi = i;
|
||||
else if (pc >= f->pc_begin + f->pc_range)
|
||||
lo = i + 1;
|
||||
else
|
||||
return f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Long slow labourious linear search, cos we've no memory. */
|
||||
fde *f;
|
||||
|
||||
if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
|
||||
do
|
||||
{
|
||||
f = search_fdes (*p, pc);
|
||||
if (f)
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
while (*p);
|
||||
}
|
||||
else
|
||||
f = search_fdes (ob->fde_begin, pc);
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct dwarf_cie *
|
||||
get_cie (fde *f)
|
||||
{
|
||||
return ((void *)&f->CIE_delta) - f->CIE_delta;
|
||||
}
|
||||
|
||||
/* Extract any interesting information from the CIE for the translation
|
||||
unit F belongs to. */
|
||||
|
||||
static void *
|
||||
extract_cie_info (fde *f, struct cie_info *c)
|
||||
{
|
||||
void *p;
|
||||
int i;
|
||||
|
||||
c->augmentation = get_cie (f)->augmentation;
|
||||
|
||||
if (strcmp (c->augmentation, "") != 0
|
||||
&& strcmp (c->augmentation, "eh") != 0
|
||||
&& c->augmentation[0] != 'z')
|
||||
return 0;
|
||||
|
||||
p = c->augmentation + strlen (c->augmentation) + 1;
|
||||
|
||||
if (strcmp (c->augmentation, "eh") == 0)
|
||||
{
|
||||
c->eh_ptr = read_pointer (p);
|
||||
p += sizeof (void *);
|
||||
}
|
||||
else
|
||||
c->eh_ptr = 0;
|
||||
|
||||
p = decode_uleb128 (p, &c->code_align);
|
||||
p = decode_sleb128 (p, &c->data_align);
|
||||
c->ra_regno = *(unsigned char *)p++;
|
||||
|
||||
/* If the augmentation starts with 'z', we now see the length of the
|
||||
augmentation fields. */
|
||||
if (c->augmentation[0] == 'z')
|
||||
{
|
||||
p = decode_uleb128 (p, &i);
|
||||
p += i;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Decode a DW_OP stack operation. */
|
||||
|
||||
static void *
|
||||
decode_stack_op (unsigned char *buf, struct frame_state *state)
|
||||
{
|
||||
enum dwarf_location_atom op;
|
||||
int offset;
|
||||
|
||||
op = *buf++;
|
||||
switch (op)
|
||||
{
|
||||
case DW_OP_reg0:
|
||||
case DW_OP_reg1:
|
||||
case DW_OP_reg2:
|
||||
case DW_OP_reg3:
|
||||
case DW_OP_reg4:
|
||||
case DW_OP_reg5:
|
||||
case DW_OP_reg6:
|
||||
case DW_OP_reg7:
|
||||
case DW_OP_reg8:
|
||||
case DW_OP_reg9:
|
||||
case DW_OP_reg10:
|
||||
case DW_OP_reg11:
|
||||
case DW_OP_reg12:
|
||||
case DW_OP_reg13:
|
||||
case DW_OP_reg14:
|
||||
case DW_OP_reg15:
|
||||
case DW_OP_reg16:
|
||||
case DW_OP_reg17:
|
||||
case DW_OP_reg18:
|
||||
case DW_OP_reg19:
|
||||
case DW_OP_reg20:
|
||||
case DW_OP_reg21:
|
||||
case DW_OP_reg22:
|
||||
case DW_OP_reg23:
|
||||
case DW_OP_reg24:
|
||||
case DW_OP_reg25:
|
||||
case DW_OP_reg26:
|
||||
case DW_OP_reg27:
|
||||
case DW_OP_reg28:
|
||||
case DW_OP_reg29:
|
||||
case DW_OP_reg30:
|
||||
case DW_OP_reg31:
|
||||
state->cfa_reg = op - DW_OP_reg0;
|
||||
break;
|
||||
case DW_OP_regx:
|
||||
buf = decode_sleb128 (buf, &offset);
|
||||
state->cfa_reg = offset;
|
||||
break;
|
||||
case DW_OP_breg0:
|
||||
case DW_OP_breg1:
|
||||
case DW_OP_breg2:
|
||||
case DW_OP_breg3:
|
||||
case DW_OP_breg4:
|
||||
case DW_OP_breg5:
|
||||
case DW_OP_breg6:
|
||||
case DW_OP_breg7:
|
||||
case DW_OP_breg8:
|
||||
case DW_OP_breg9:
|
||||
case DW_OP_breg10:
|
||||
case DW_OP_breg11:
|
||||
case DW_OP_breg12:
|
||||
case DW_OP_breg13:
|
||||
case DW_OP_breg14:
|
||||
case DW_OP_breg15:
|
||||
case DW_OP_breg16:
|
||||
case DW_OP_breg17:
|
||||
case DW_OP_breg18:
|
||||
case DW_OP_breg19:
|
||||
case DW_OP_breg20:
|
||||
case DW_OP_breg21:
|
||||
case DW_OP_breg22:
|
||||
case DW_OP_breg23:
|
||||
case DW_OP_breg24:
|
||||
case DW_OP_breg25:
|
||||
case DW_OP_breg26:
|
||||
case DW_OP_breg27:
|
||||
case DW_OP_breg28:
|
||||
case DW_OP_breg29:
|
||||
case DW_OP_breg30:
|
||||
case DW_OP_breg31:
|
||||
state->cfa_reg = op - DW_OP_breg0;
|
||||
buf = decode_sleb128 (buf, &offset);
|
||||
state->base_offset = offset;
|
||||
break;
|
||||
case DW_OP_bregx:
|
||||
buf = decode_sleb128 (buf, &offset);
|
||||
state->cfa_reg = offset;
|
||||
buf = decode_sleb128 (buf, &offset);
|
||||
state->base_offset = offset;
|
||||
break;
|
||||
case DW_OP_deref:
|
||||
state->indirect = 1;
|
||||
break;
|
||||
case DW_OP_plus_uconst:
|
||||
buf = decode_uleb128 (buf, &offset);
|
||||
state->cfa_offset = offset;
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
/* Decode one instruction's worth of DWARF 2 call frame information.
|
||||
Used by __frame_state_for. Takes pointers P to the instruction to
|
||||
decode, STATE to the current register unwind information, INFO to the
|
||||
current CIE information, and PC to the current PC value. Returns a
|
||||
pointer to the next instruction. */
|
||||
|
||||
static void *
|
||||
execute_cfa_insn (void *p, struct frame_state_internal *state,
|
||||
struct cie_info *info, void **pc)
|
||||
{
|
||||
unsigned insn = *(unsigned char *)p++;
|
||||
unsigned reg;
|
||||
int offset;
|
||||
|
||||
if (insn & DW_CFA_advance_loc)
|
||||
*pc += ((insn & 0x3f) * info->code_align);
|
||||
else if (insn & DW_CFA_offset)
|
||||
{
|
||||
reg = (insn & 0x3f);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
if (reg == state->s.cfa_reg)
|
||||
/* Don't record anything about this register; it's only used to
|
||||
reload SP in the epilogue. We don't want to copy in SP
|
||||
values for outer frames; we handle restoring SP specially. */;
|
||||
else
|
||||
{
|
||||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = offset;
|
||||
}
|
||||
}
|
||||
else if (insn & DW_CFA_restore)
|
||||
{
|
||||
reg = (insn & 0x3f);
|
||||
state->s.saved[reg] = REG_UNSAVED;
|
||||
}
|
||||
else switch (insn)
|
||||
{
|
||||
case DW_CFA_set_loc:
|
||||
*pc = read_pointer (p);
|
||||
p += sizeof (void *);
|
||||
break;
|
||||
case DW_CFA_advance_loc1:
|
||||
*pc += read_1byte (p);
|
||||
p += 1;
|
||||
break;
|
||||
case DW_CFA_advance_loc2:
|
||||
*pc += read_2byte (p);
|
||||
p += 2;
|
||||
break;
|
||||
case DW_CFA_advance_loc4:
|
||||
*pc += read_4byte (p);
|
||||
p += 4;
|
||||
break;
|
||||
|
||||
case DW_CFA_offset_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
if (reg == state->s.cfa_reg)
|
||||
/* Don't record anything; see above. */;
|
||||
else
|
||||
{
|
||||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = offset;
|
||||
}
|
||||
break;
|
||||
case DW_CFA_restore_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
state->s.saved[reg] = REG_UNSAVED;
|
||||
break;
|
||||
|
||||
case DW_CFA_undefined:
|
||||
case DW_CFA_same_value:
|
||||
case DW_CFA_nop:
|
||||
break;
|
||||
|
||||
case DW_CFA_register:
|
||||
{
|
||||
unsigned reg2;
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, ®2);
|
||||
state->s.saved[reg] = REG_SAVED_REG;
|
||||
state->s.reg_or_offset[reg] = reg2;
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_CFA_def_cfa:
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.cfa_reg = reg;
|
||||
state->s.cfa_offset = offset;
|
||||
break;
|
||||
case DW_CFA_def_cfa_register:
|
||||
p = decode_uleb128 (p, ®);
|
||||
state->s.cfa_reg = reg;
|
||||
break;
|
||||
case DW_CFA_def_cfa_offset:
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.cfa_offset = offset;
|
||||
break;
|
||||
case DW_CFA_def_cfa_expression:
|
||||
{
|
||||
void *end;
|
||||
state->s.cfa_reg = 0;
|
||||
state->s.cfa_offset = 0;
|
||||
state->s.base_offset = 0;
|
||||
state->s.indirect = 0;
|
||||
|
||||
p = decode_uleb128 (p, &offset);
|
||||
end = p + offset;
|
||||
while (p < end)
|
||||
p = decode_stack_op (p, &(state->s));
|
||||
break;
|
||||
}
|
||||
|
||||
case DW_CFA_remember_state:
|
||||
{
|
||||
struct frame_state_internal *save =
|
||||
(struct frame_state_internal *)
|
||||
malloc (sizeof (struct frame_state_internal));
|
||||
memcpy (save, state, sizeof (struct frame_state_internal));
|
||||
state->saved_state = save;
|
||||
}
|
||||
break;
|
||||
case DW_CFA_restore_state:
|
||||
{
|
||||
struct frame_state_internal *save = state->saved_state;
|
||||
memcpy (state, save, sizeof (struct frame_state_internal));
|
||||
free (save);
|
||||
}
|
||||
break;
|
||||
|
||||
/* FIXME: Hardcoded for SPARC register window configuration. */
|
||||
case DW_CFA_GNU_window_save:
|
||||
for (reg = 16; reg < 32; ++reg)
|
||||
{
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_CFA_GNU_args_size:
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.args_size = offset;
|
||||
break;
|
||||
|
||||
case DW_CFA_GNU_negative_offset_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = -offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Called from __throw to find the registers to restore for a given
|
||||
PC_TARGET. The caller should allocate a local variable of `struct
|
||||
frame_state' (declared in frame.h) and pass its address to STATE_IN. */
|
||||
|
||||
struct frame_state *
|
||||
__frame_state_for (void *pc_target, struct frame_state *state_in)
|
||||
{
|
||||
fde *f;
|
||||
void *insn, *end, *pc;
|
||||
struct cie_info info;
|
||||
struct frame_state_internal state;
|
||||
|
||||
f = find_fde (pc_target);
|
||||
if (f == 0)
|
||||
return 0;
|
||||
|
||||
insn = extract_cie_info (f, &info);
|
||||
if (insn == 0)
|
||||
return 0;
|
||||
|
||||
memset (&state, 0, sizeof (state));
|
||||
state.s.retaddr_column = info.ra_regno;
|
||||
state.s.eh_ptr = info.eh_ptr;
|
||||
|
||||
/* First decode all the insns in the CIE. */
|
||||
end = next_fde ((fde*) get_cie (f));
|
||||
while (insn < end)
|
||||
insn = execute_cfa_insn (insn, &state, &info, 0);
|
||||
|
||||
insn = ((fde *)f) + 1;
|
||||
|
||||
if (info.augmentation[0] == 'z')
|
||||
{
|
||||
int i;
|
||||
insn = decode_uleb128 (insn, &i);
|
||||
insn += i;
|
||||
}
|
||||
|
||||
/* Then the insns in the FDE up to our target PC. */
|
||||
end = next_fde (f);
|
||||
pc = f->pc_begin;
|
||||
while (insn < end && pc <= pc_target)
|
||||
insn = execute_cfa_insn (insn, &state, &info, &pc);
|
||||
|
||||
memcpy (state_in, &state.s, sizeof (state.s));
|
||||
return state_in;
|
||||
}
|
||||
#endif /* DWARF2_UNWIND_INFO */
|
287
gcc/frame.h
287
gcc/frame.h
@ -1,287 +0,0 @@
|
||||
/* Header file for unwinding stack frames for exception handling. */
|
||||
/* Compile this one with gcc. */
|
||||
/* Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
Contributed by Jason Merrill <jason@cygnus.com>.
|
||||
|
||||
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. */
|
||||
|
||||
|
||||
#ifndef DWARF_FRAME_REGISTERS
|
||||
#define DWARF_FRAME_REGISTERS FIRST_PSEUDO_REGISTER
|
||||
#endif
|
||||
|
||||
typedef struct frame_state
|
||||
{
|
||||
void *cfa;
|
||||
void *eh_ptr;
|
||||
long cfa_offset;
|
||||
long args_size;
|
||||
long reg_or_offset[DWARF_FRAME_REGISTERS+1];
|
||||
unsigned short cfa_reg;
|
||||
unsigned short retaddr_column;
|
||||
char saved[DWARF_FRAME_REGISTERS+1];
|
||||
long base_offset;
|
||||
char indirect;
|
||||
} frame_state;
|
||||
|
||||
/* Values for 'saved' above. */
|
||||
#define REG_UNSAVED 0
|
||||
#define REG_SAVED_OFFSET 1
|
||||
#define REG_SAVED_REG 2
|
||||
|
||||
/* The representation for an "object" to be searched for frame unwind info.
|
||||
For targets with named sections, one object is an executable or shared
|
||||
library; for other targets, one object is one translation unit.
|
||||
|
||||
A copy of this structure declaration is printed by collect2.c;
|
||||
keep the copies synchronized! */
|
||||
|
||||
struct object {
|
||||
#ifdef IA64_UNWIND_INFO
|
||||
void *pc_base; /* This field will be set by find_fde. */
|
||||
#endif
|
||||
void *pc_begin;
|
||||
void *pc_end;
|
||||
struct dwarf_fde *fde_begin;
|
||||
#ifdef IA64_UNWIND_INFO
|
||||
struct dwarf_fde *fde_end;
|
||||
#endif
|
||||
struct dwarf_fde **fde_array;
|
||||
size_t count;
|
||||
struct object *next;
|
||||
};
|
||||
|
||||
/* Note the following routines are exported interfaces from libgcc; do not
|
||||
change these interfaces. Instead create new interfaces. Also note
|
||||
references to these functions may be made weak in files where they
|
||||
are referenced. */
|
||||
|
||||
extern void __register_frame (void * );
|
||||
extern void __register_frame_table (void *);
|
||||
extern void __deregister_frame (void *);
|
||||
|
||||
/* Called either from crtbegin.o or a static constructor to register the
|
||||
unwind info for an object or translation unit, respectively. */
|
||||
|
||||
extern void __register_frame_info (void *, struct object *);
|
||||
|
||||
/* Similar, but BEGIN is actually a pointer to a table of unwind entries
|
||||
for different translation units. Called from the file generated by
|
||||
collect2. */
|
||||
extern void __register_frame_info_table (void *, struct object *);
|
||||
|
||||
/* Called from crtend.o to deregister the unwind info for an object. */
|
||||
|
||||
extern void *__deregister_frame_info (void *);
|
||||
|
||||
/* Called from __throw to find the registers to restore for a given
|
||||
PC_TARGET. The caller should allocate a local variable of `struct
|
||||
frame_state' (declared in frame.h) and pass its address to STATE_IN.
|
||||
Returns NULL on failure, otherwise returns STATE_IN. */
|
||||
|
||||
extern struct frame_state *__frame_state_for (void *, struct frame_state *);
|
||||
|
||||
#ifdef IA64_UNWIND_INFO
|
||||
|
||||
/* This is the information required for unwind records in an ia64
|
||||
object file. This is required by GAS and the compiler runtime. */
|
||||
|
||||
/* These are the starting point masks for the various types of
|
||||
unwind records. To create a record of type R3 for instance, one
|
||||
starts by using the value UNW_R3 and or-ing in any other required values.
|
||||
These values are also unique (in context), so they can be used to identify
|
||||
the various record types as well. UNW_Bx and some UNW_Px do have the
|
||||
same value, but Px can only occur in a prologue context, and Bx in
|
||||
a body context. */
|
||||
|
||||
#define UNW_R1 0x00
|
||||
#define UNW_R2 0x40
|
||||
#define UNW_R3 0x60
|
||||
#define UNW_P1 0x80
|
||||
#define UNW_P2 0xA0
|
||||
#define UNW_P3 0xB0
|
||||
#define UNW_P4 0xB8
|
||||
#define UNW_P5 0xB9
|
||||
#define UNW_P6 0xC0
|
||||
#define UNW_P7 0xE0
|
||||
#define UNW_P8 0xF0
|
||||
#define UNW_P9 0xF1
|
||||
#define UNW_P10 0xFF
|
||||
#define UNW_X1 0xF9
|
||||
#define UNW_X2 0xFA
|
||||
#define UNW_X3 0xFB
|
||||
#define UNW_X4 0xFC
|
||||
#define UNW_B1 0x80
|
||||
#define UNW_B2 0xC0
|
||||
#define UNW_B3 0xE0
|
||||
#define UNW_B4 0xF0
|
||||
|
||||
/* These are all the various types of unwind records. */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
prologue, prologue_gr, body, mem_stack_f, mem_stack_v, psp_gr, psp_sprel,
|
||||
rp_when, rp_gr, rp_br, rp_psprel, rp_sprel, pfs_when, pfs_gr, pfs_psprel,
|
||||
pfs_sprel, preds_when, preds_gr, preds_psprel, preds_sprel,
|
||||
fr_mem, frgr_mem, gr_gr, gr_mem, br_mem, br_gr, spill_base, spill_mask,
|
||||
unat_when, unat_gr, unat_psprel, unat_sprel, lc_when, lc_gr, lc_psprel,
|
||||
lc_sprel, fpsr_when, fpsr_gr, fpsr_psprel, fpsr_sprel,
|
||||
priunat_when_gr, priunat_when_mem, priunat_gr, priunat_psprel,
|
||||
priunat_sprel, bsp_when, bsp_gr, bsp_psprel, bsp_sprel, bspstore_when,
|
||||
bspstore_gr, bspstore_psprel, bspstore_sprel, rnat_when, rnat_gr,
|
||||
rnat_psprel, rnat_sprel, epilogue, label_state, copy_state,
|
||||
spill_psprel, spill_sprel, spill_reg, spill_psprel_p, spill_sprel_p,
|
||||
spill_reg_p
|
||||
} unw_record_type;
|
||||
|
||||
|
||||
/* These structures declare the fields that can be used in each of the
|
||||
4 record formats, R, P, B and X. */
|
||||
|
||||
typedef struct unw_r_record
|
||||
{
|
||||
unsigned long rlen;
|
||||
unsigned short mask;
|
||||
unsigned short grsave;
|
||||
} unw_r_record;
|
||||
|
||||
typedef struct unw_p_record
|
||||
{
|
||||
void *imask;
|
||||
unsigned long t;
|
||||
unsigned long size;
|
||||
unsigned long spoff;
|
||||
unsigned long br;
|
||||
unsigned long pspoff;
|
||||
unsigned short gr;
|
||||
unsigned short rmask;
|
||||
unsigned short grmask;
|
||||
unsigned long frmask;
|
||||
unsigned short brmask;
|
||||
} unw_p_record;
|
||||
|
||||
typedef struct unw_b_record
|
||||
{
|
||||
unsigned long t;
|
||||
unsigned long label;
|
||||
unsigned short ecount;
|
||||
} unw_b_record;
|
||||
|
||||
typedef struct unw_x_record
|
||||
{
|
||||
unsigned long t;
|
||||
unsigned long spoff;
|
||||
unsigned long pspoff;
|
||||
unsigned short reg;
|
||||
unsigned short treg;
|
||||
unsigned short qp;
|
||||
unsigned short xy; /* Value of the XY field.. */
|
||||
} unw_x_record;
|
||||
|
||||
/* This structure is used to determine the specific record type and
|
||||
its fields. */
|
||||
typedef struct unwind_record
|
||||
{
|
||||
unw_record_type type;
|
||||
union {
|
||||
unw_r_record r;
|
||||
unw_p_record p;
|
||||
unw_b_record b;
|
||||
unw_x_record x;
|
||||
} record;
|
||||
} unwind_record;
|
||||
|
||||
#define IA64_UNW_LOC_TYPE_NONE 0
|
||||
#define IA64_UNW_LOC_TYPE_MEM 1
|
||||
#define IA64_UNW_LOC_TYPE_GR 2
|
||||
#define IA64_UNW_LOC_TYPE_FR 3
|
||||
#define IA64_UNW_LOC_TYPE_BR 4
|
||||
#define IA64_UNW_LOC_TYPE_SPOFF 5
|
||||
#define IA64_UNW_LOC_TYPE_PSPOFF 6
|
||||
#define IA64_UNW_LOC_TYPE_OFFSET 7
|
||||
#define IA64_UNW_LOC_TYPE_SPILLBASE 8
|
||||
|
||||
typedef struct ia64_reg_loc
|
||||
{
|
||||
long when; /* PC relative offset from start of function. */
|
||||
union { /* In memory or another register? */
|
||||
void *mem;
|
||||
int regno;
|
||||
int offset;
|
||||
} l;
|
||||
short loc_type; /* Where to find value. */
|
||||
short reg_size;
|
||||
} ia64_reg_loc;
|
||||
|
||||
/* Frame information record. */
|
||||
|
||||
typedef struct ia64_frame_state
|
||||
{
|
||||
ia64_reg_loc gr[4]; /* gr4 to gr7. */
|
||||
ia64_reg_loc fr[20]; /* fr2 to fr5, fr16 to fr31. */
|
||||
ia64_reg_loc br[5]; /* br1 to br5. */
|
||||
ia64_reg_loc rp;
|
||||
ia64_reg_loc fpsr;
|
||||
ia64_reg_loc bsp;
|
||||
ia64_reg_loc bspstore;
|
||||
ia64_reg_loc rnat;
|
||||
ia64_reg_loc pfs;
|
||||
ia64_reg_loc unat;
|
||||
ia64_reg_loc lc;
|
||||
ia64_reg_loc pr;
|
||||
ia64_reg_loc priunat;
|
||||
ia64_reg_loc sp;
|
||||
ia64_reg_loc psp;
|
||||
ia64_reg_loc spill_base;
|
||||
void *my_psp;
|
||||
void *my_sp;
|
||||
void *my_bsp;
|
||||
} ia64_frame_state;
|
||||
|
||||
/* This structure represents the start of an unwind information pointer.
|
||||
'unwind_descriptors' is the beginninng of the unwind descriptors, which
|
||||
use up 'length' bytes of storage. */
|
||||
|
||||
typedef struct unwind_info_ptr
|
||||
{
|
||||
unsigned long header; /* version, flags, & length */
|
||||
unsigned char unwind_descriptors[1];
|
||||
} unwind_info_ptr;
|
||||
|
||||
#define IA64_UNW_HDR_LENGTH(x) ((x) & 0x00000000ffffffffUL)
|
||||
#define IA64_UNW_HDR_FLAGS(x) (((x) >> 32) & 0xffffUL)
|
||||
#define IA64_UNW_HDR_VERSION(x) (((x) >> 48) & 0xffffUL)
|
||||
|
||||
/* Header flag bits, after extraction by IA64_UNW_HDR_FLAGS. */
|
||||
#define IA64_UNW_EHANDLER 0x1
|
||||
#define IA64_UNW_UHANDLER 0x2
|
||||
|
||||
extern void * __ia64_personality_v1 (void *pc, old_exception_table *table);
|
||||
|
||||
extern unwind_info_ptr *__build_ia64_frame_state (unsigned char *,
|
||||
ia64_frame_state *,
|
||||
void *, void *,
|
||||
void **);
|
||||
extern void *__get_real_reg_value (ia64_reg_loc *);
|
||||
extern void *__get_personality (unwind_info_ptr *);
|
||||
extern void *__get_except_table (unwind_info_ptr *);
|
||||
extern void __set_real_reg_value (ia64_reg_loc *, void *);
|
||||
void *__calc_caller_bsp (long, unsigned char *);
|
||||
void __copy_saved_reg_state (ia64_frame_state *, ia64_frame_state *);
|
||||
#endif /* IA64_UNWIND_INFO */
|
||||
|
@ -1580,11 +1580,6 @@ fixup_var_refs (var, promoted_mode, unsignedp, ht)
|
||||
end_sequence ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan the catch clauses for exception handling too. */
|
||||
push_to_full_sequence (catch_clauses, catch_clauses_last);
|
||||
fixup_var_refs_insns (catch_clauses, var, promoted_mode, unsignedp, 0);
|
||||
end_full_sequence (&catch_clauses, &catch_clauses_last);
|
||||
}
|
||||
|
||||
/* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is
|
||||
@ -6315,20 +6310,10 @@ expand_function_start (subr, parms_have_cleanups)
|
||||
else
|
||||
cleanup_label = 0;
|
||||
|
||||
/* Make the label for return statements to jump to, if this machine
|
||||
does not have a one-instruction return and uses an epilogue,
|
||||
or if it returns a structure, or if it has parm cleanups. */
|
||||
#ifdef HAVE_return
|
||||
if (cleanup_label == 0 && HAVE_return
|
||||
&& ! current_function_instrument_entry_exit
|
||||
&& ! current_function_returns_pcc_struct
|
||||
&& ! (current_function_returns_struct && ! optimize))
|
||||
return_label = 0;
|
||||
else
|
||||
return_label = gen_label_rtx ();
|
||||
#else
|
||||
/* Make the label for return statements to jump to. Do not special
|
||||
case machines with special return instructions -- they will be
|
||||
handled later during jump, ifcvt, or epilogue creation. */
|
||||
return_label = gen_label_rtx ();
|
||||
#endif
|
||||
|
||||
/* Initialize rtx used to return the value. */
|
||||
/* Do this before assign_parms so that we copy the struct value address
|
||||
@ -6370,7 +6355,9 @@ expand_function_start (subr, parms_have_cleanups)
|
||||
else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
|
||||
/* If return mode is void, this decl rtl should not be used. */
|
||||
SET_DECL_RTL (DECL_RESULT (subr), NULL_RTX);
|
||||
else if (parms_have_cleanups || current_function_instrument_entry_exit)
|
||||
else if (parms_have_cleanups
|
||||
|| current_function_instrument_entry_exit
|
||||
|| (flag_exceptions && USING_SJLJ_EXCEPTIONS))
|
||||
{
|
||||
/* If function will end with cleanup code for parms,
|
||||
compute the return values into a pseudo reg,
|
||||
@ -6801,27 +6788,6 @@ expand_function_end (filename, line, end_bindings)
|
||||
if (end_bindings)
|
||||
expand_end_bindings (0, 0, 0);
|
||||
|
||||
/* Now handle any leftover exception regions that may have been
|
||||
created for the parameters. */
|
||||
{
|
||||
rtx last = get_last_insn ();
|
||||
rtx label;
|
||||
|
||||
expand_leftover_cleanups ();
|
||||
|
||||
/* If there are any catch_clauses remaining, output them now. */
|
||||
emit_insns (catch_clauses);
|
||||
catch_clauses = catch_clauses_last = NULL_RTX;
|
||||
/* If the above emitted any code, may sure we jump around it. */
|
||||
if (last != get_last_insn ())
|
||||
{
|
||||
label = gen_label_rtx ();
|
||||
last = emit_jump_insn_after (gen_jump (label), last);
|
||||
last = emit_barrier_after (last);
|
||||
emit_label (label);
|
||||
}
|
||||
}
|
||||
|
||||
if (current_function_instrument_entry_exit)
|
||||
{
|
||||
rtx fun = DECL_RTL (current_function_decl);
|
||||
@ -6837,6 +6803,11 @@ expand_function_end (filename, line, end_bindings)
|
||||
Pmode);
|
||||
}
|
||||
|
||||
/* Let except.c know where it should emit the call to unregister
|
||||
the function context for sjlj exceptions. */
|
||||
if (flag_exceptions && USING_SJLJ_EXCEPTIONS)
|
||||
sjlj_emit_function_exit_after (get_last_insn ());
|
||||
|
||||
/* If we had calls to alloca, and this machine needs
|
||||
an accurate stack pointer to exit the function,
|
||||
insert some code to save and restore the stack pointer. */
|
||||
@ -6944,16 +6915,16 @@ expand_function_end (filename, line, end_bindings)
|
||||
current_function_return_rtx = outgoing;
|
||||
}
|
||||
|
||||
/* If this is an implementation of throw, do what's necessary to
|
||||
communicate between __builtin_eh_return and the epilogue. */
|
||||
expand_eh_return ();
|
||||
|
||||
/* ??? This should no longer be necessary since stupid is no longer with
|
||||
us, but there are some parts of the compiler (eg reload_combine, and
|
||||
sh mach_dep_reorg) that still try and compute their own lifetime info
|
||||
instead of using the general framework. */
|
||||
use_return_register ();
|
||||
|
||||
/* If this is an implementation of __throw, do what's necessary to
|
||||
communicate between __builtin_eh_return and the epilogue. */
|
||||
expand_eh_return ();
|
||||
|
||||
/* Output a return insn if we are using one.
|
||||
Otherwise, let the rtl chain end here, to drop through
|
||||
into the epilogue. */
|
||||
|
@ -409,6 +409,9 @@ struct function
|
||||
either as a subroutine or builtin. */
|
||||
unsigned int calls_alloca : 1;
|
||||
|
||||
/* Nonzero if the function calls __builtin_eh_return. */
|
||||
unsigned int calls_eh_return : 1;
|
||||
|
||||
/* Nonzero if function being compiled receives nonlocal gotos
|
||||
from nested functions. */
|
||||
unsigned int has_nonlocal_label : 1;
|
||||
@ -488,6 +491,7 @@ extern struct function *all_functions;
|
||||
#define current_function_calls_setjmp (cfun->calls_setjmp)
|
||||
#define current_function_calls_alloca (cfun->calls_alloca)
|
||||
#define current_function_calls_longjmp (cfun->calls_longjmp)
|
||||
#define current_function_calls_eh_return (cfun->calls_eh_return)
|
||||
#define current_function_has_computed_jump (cfun->has_computed_jump)
|
||||
#define current_function_contains_functions (cfun->contains_functions)
|
||||
#define current_function_is_thunk (cfun->is_thunk)
|
||||
|
11
gcc/ifcvt.c
11
gcc/ifcvt.c
@ -1905,7 +1905,7 @@ find_if_block (test_bb, then_edge, else_edge)
|
||||
/* Make sure IF, THEN, and ELSE, blocks are adjacent. Actually, we
|
||||
get the first condition for free, since we've already asserted that
|
||||
there's a fallthru edge from IF to THEN. */
|
||||
/* ??? As an enhancement, move the ELSE block. Have to deal with EH and
|
||||
/* ??? As an enhancement, move the ELSE block. Have to deal with
|
||||
BLOCK notes, if by no other means than aborting the merge if they
|
||||
exist. Sticky enough I don't want to think about it now. */
|
||||
next_index = then_bb->index;
|
||||
@ -2188,15 +2188,6 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
|
||||
{
|
||||
rtx head, end, jump, earliest, old_dest;
|
||||
|
||||
/* No code movement can occur if we'd be scrogging EH regions.
|
||||
Within MERGE_BB, ensure that we've not got stray EH_BEG or EH_END
|
||||
notes within the block. Between the blocks, checking that the end
|
||||
region numbers match ensures that we won't disrupt the nesting
|
||||
between regions. */
|
||||
if (merge_bb->eh_beg != merge_bb->eh_end
|
||||
|| merge_bb->eh_end != test_bb->eh_end)
|
||||
return FALSE;
|
||||
|
||||
jump = test_bb->end;
|
||||
|
||||
/* Find the extent of the real code in the merge block. */
|
||||
|
@ -81,12 +81,12 @@ static void set_block_abstract_flags PARAMS ((tree, int));
|
||||
static void process_reg_param PARAMS ((struct inline_remap *, rtx,
|
||||
rtx));
|
||||
void set_decl_abstract_flags PARAMS ((tree, int));
|
||||
static rtx expand_inline_function_eh_labelmap PARAMS ((rtx));
|
||||
static void mark_stores PARAMS ((rtx, rtx, void *));
|
||||
static void save_parm_insns PARAMS ((rtx, rtx));
|
||||
static void copy_insn_list PARAMS ((rtx, struct inline_remap *,
|
||||
rtx));
|
||||
static void copy_insn_notes PARAMS ((rtx, struct inline_remap *));
|
||||
static void copy_insn_notes PARAMS ((rtx, struct inline_remap *,
|
||||
int));
|
||||
static int compare_blocks PARAMS ((const PTR, const PTR));
|
||||
static int find_block PARAMS ((const PTR, const PTR));
|
||||
|
||||
@ -152,6 +152,9 @@ function_cannot_inline_p (fndecl)
|
||||
if (current_function_calls_setjmp)
|
||||
return N_("function using setjmp cannot be inline");
|
||||
|
||||
if (current_function_calls_eh_return)
|
||||
return N_("function uses __builtin_eh_return");
|
||||
|
||||
if (current_function_contains_functions)
|
||||
return N_("function with nested functions cannot be inline");
|
||||
|
||||
@ -221,19 +224,6 @@ function_cannot_inline_p (fndecl)
|
||||
if (current_function_has_nonlocal_goto)
|
||||
return N_("function with nonlocal goto cannot be inline");
|
||||
|
||||
/* This is a hack, until the inliner is taught about eh regions at
|
||||
the start of the function. */
|
||||
for (insn = get_insns ();
|
||||
insn
|
||||
&& ! (GET_CODE (insn) == NOTE
|
||||
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG);
|
||||
insn = NEXT_INSN (insn))
|
||||
{
|
||||
if (insn && GET_CODE (insn) == NOTE
|
||||
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
|
||||
return N_("function with complex parameters cannot be inline");
|
||||
}
|
||||
|
||||
/* We can't inline functions that return a PARALLEL rtx. */
|
||||
if (DECL_RTL_SET_P (DECL_RESULT (fndecl)))
|
||||
{
|
||||
@ -548,17 +538,6 @@ process_reg_param (map, loc, copy)
|
||||
map->reg_map[REGNO (loc)] = copy;
|
||||
}
|
||||
|
||||
/* Used by duplicate_eh_handlers to map labels for the exception table */
|
||||
static struct inline_remap *eif_eh_map;
|
||||
|
||||
static rtx
|
||||
expand_inline_function_eh_labelmap (label)
|
||||
rtx label;
|
||||
{
|
||||
int index = CODE_LABEL_NUMBER (label);
|
||||
return get_label_from_map (eif_eh_map, index);
|
||||
}
|
||||
|
||||
/* Compare two BLOCKs for qsort. The key we sort on is the
|
||||
BLOCK_ABSTRACT_ORIGIN of the blocks. */
|
||||
|
||||
@ -634,6 +613,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
|
||||
rtvec arg_vector = (rtvec) inl_f->original_arg_vector;
|
||||
rtx static_chain_value = 0;
|
||||
int inl_max_uid;
|
||||
int eh_region_offset;
|
||||
|
||||
/* The pointer used to track the true location of the memory used
|
||||
for MAP->LABEL_MAP. */
|
||||
@ -1140,8 +1120,14 @@ expand_inline_function (fndecl, parms, target, ignore, type,
|
||||
/* Now copy the insns one by one. */
|
||||
copy_insn_list (insns, map, static_chain_value);
|
||||
|
||||
/* Duplicate the EH regions. This will create an offset from the
|
||||
region numbers in the function we're inlining to the region
|
||||
numbers in the calling function. This must wait until after
|
||||
copy_insn_list, as we need the insn map to be complete. */
|
||||
eh_region_offset = duplicate_eh_regions (inl_f, map);
|
||||
|
||||
/* Now copy the REG_NOTES for those insns. */
|
||||
copy_insn_notes (insns, map);
|
||||
copy_insn_notes (insns, map, eh_region_offset);
|
||||
|
||||
/* If the insn sequence required one, emit the return label. */
|
||||
if (map->local_return_label)
|
||||
@ -1260,12 +1246,6 @@ copy_insn_list (insns, map, static_chain_value)
|
||||
inline_target. */
|
||||
break;
|
||||
|
||||
/* If the inline fn needs eh context, make sure that
|
||||
the current fn has one. */
|
||||
if (GET_CODE (pattern) == USE
|
||||
&& find_reg_note (insn, REG_EH_CONTEXT, 0) != 0)
|
||||
get_eh_context ();
|
||||
|
||||
/* Ignore setting a function value that we don't want to use. */
|
||||
if (map->inline_target == 0
|
||||
&& set != 0
|
||||
@ -1526,31 +1506,9 @@ copy_insn_list (insns, map, static_chain_value)
|
||||
copy = emit_note (NOTE_SOURCE_FILE (insn),
|
||||
NOTE_LINE_NUMBER (insn));
|
||||
if (copy
|
||||
&& (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
|
||||
|| NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END))
|
||||
{
|
||||
rtx label
|
||||
= get_label_from_map (map, NOTE_EH_HANDLER (copy));
|
||||
|
||||
/* We have to duplicate the handlers for the original. */
|
||||
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
|
||||
{
|
||||
/* We need to duplicate the handlers for the EH region
|
||||
and we need to indicate where the label map is */
|
||||
eif_eh_map = map;
|
||||
duplicate_eh_handlers (NOTE_EH_HANDLER (copy),
|
||||
CODE_LABEL_NUMBER (label),
|
||||
expand_inline_function_eh_labelmap);
|
||||
}
|
||||
|
||||
/* We have to forward these both to match the new exception
|
||||
region. */
|
||||
NOTE_EH_HANDLER (copy) = CODE_LABEL_NUMBER (label);
|
||||
}
|
||||
else if (copy
|
||||
&& (NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_BEG
|
||||
|| NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_END)
|
||||
&& NOTE_BLOCK (insn))
|
||||
&& (NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_BEG
|
||||
|| NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_END)
|
||||
&& NOTE_BLOCK (insn))
|
||||
{
|
||||
tree *mapped_block_p;
|
||||
|
||||
@ -1587,9 +1545,10 @@ copy_insn_list (insns, map, static_chain_value)
|
||||
that are valid across the entire function. */
|
||||
|
||||
static void
|
||||
copy_insn_notes (insns, map)
|
||||
copy_insn_notes (insns, map, eh_region_offset)
|
||||
rtx insns;
|
||||
struct inline_remap *map;
|
||||
int eh_region_offset;
|
||||
{
|
||||
rtx insn, new_insn;
|
||||
|
||||
@ -1620,6 +1579,9 @@ copy_insn_notes (insns, map)
|
||||
next = XEXP (note, 1);
|
||||
if (REG_NOTE_KIND (note) == REG_LABEL)
|
||||
remove_note (new_insn, note);
|
||||
else if (REG_NOTE_KIND (note) == REG_EH_REGION)
|
||||
XEXP (note, 0) = GEN_INT (INTVAL (XEXP (note, 0))
|
||||
+ eh_region_offset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1628,8 +1590,12 @@ copy_insn_notes (insns, map)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 3; i++)
|
||||
copy_insn_notes (XEXP (PATTERN (insn), i), map);
|
||||
copy_insn_notes (XEXP (PATTERN (insn), i), map, eh_region_offset);
|
||||
}
|
||||
|
||||
if (GET_CODE (insn) == JUMP_INSN
|
||||
&& GET_CODE (PATTERN (insn)) == RESX)
|
||||
XINT (PATTERN (new_insn), 0) += eh_region_offset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2071,12 +2037,6 @@ copy_rtx_and_substitute (orig, map, for_lhs)
|
||||
copy_rtx_and_substitute (constant, map, for_lhs)),
|
||||
0);
|
||||
}
|
||||
else if (SYMBOL_REF_NEED_ADJUST (orig))
|
||||
{
|
||||
eif_eh_map = map;
|
||||
return rethrow_symbol_map (orig,
|
||||
expand_inline_function_eh_labelmap);
|
||||
}
|
||||
|
||||
return orig;
|
||||
|
||||
|
@ -1,3 +1,34 @@
|
||||
2001-03-28 Richard Henderson <rth@redhat.com>
|
||||
|
||||
IA-64 ABI Exception Handling:
|
||||
* Make-lang.in (except.o): Don't depend on eh-common.h.
|
||||
* check-init.c (check_init): Handle EXC_PTR_EXPR.
|
||||
* decl.c (init_decl_processing) [throw_node]: No _Jv_Sjlj_Throw.
|
||||
[soft_exceptioninfo_call_node]: Remove.
|
||||
[eh_personality_libfunc, lang_eh_runtime_type]: New.
|
||||
(end_java_method): No emit_handlers.
|
||||
* except.c (java_set_exception_lang_code): Remove.
|
||||
(method_init_exceptions): Don't call it.
|
||||
(prepare_eh_table_type): No CATCH_ALL_TYPE.
|
||||
(build_exception_object_ref): New.
|
||||
(expand_end_java_handler): Update for except.h name changes.
|
||||
(emit_handlers, expand_resume_after_catch): Remove.
|
||||
* expr.c (java_lang_expand_expr): Update for except.h name changes.
|
||||
(process_jvm_instruction): Use build_exception_object_ref.
|
||||
* java-tree.h (JTI_SOFT_EXCEPTIONINFO_CALL_NODE): Remove.
|
||||
(soft_exceptioninfo_call_node): Remove.
|
||||
(build_exception_object_ref): Declare.
|
||||
* jcf-write.c (generate_bytecode_insns) [CALL_EXPR]: No
|
||||
soft_exceptioninfo_call_node. Move processing ...
|
||||
[EXC_PTR_EXPR]: ... here.
|
||||
* parse.h (BUILD_ASSIGN_EXCEPTION_INFO): Remove dead code.
|
||||
* parse.y (catch_clause_parameter): Use build_exception_object_ref.
|
||||
(source_end_java_method): No java_set_exception_lang_code or
|
||||
emit_handlers.
|
||||
(build_dot_class_method): Use build_exception_object_ref.
|
||||
(try_reference_assignconv): Check EXC_PTR_EXPR not
|
||||
soft_exceptioninfo_call_node.
|
||||
|
||||
2001-03-28 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* java-tree.h (throw_node): Define as a single member of
|
||||
|
@ -254,7 +254,7 @@ java/decl.o: java/decl.c $(CONFIG_H) $(JAVA_TREE_H) java/jcf.h \
|
||||
toplev.h $(SYSTEM_H) function.h gcc.h
|
||||
java/except.o: java/except.c $(CONFIG_H) $(JAVA_TREE_H) java/jcf.h real.h \
|
||||
$(RTL_H) java/javaop.h java/java-opcodes.h except.h java/java-except.h \
|
||||
eh-common.h toplev.h $(SYSTEM_H) function.h
|
||||
toplev.h $(SYSTEM_H) function.h
|
||||
java/expr.o: java/expr.c $(CONFIG_H) $(JAVA_TREE_H) java/jcf.h real.h \
|
||||
$(RTL_H) $(EXPR_H) java/javaop.h java/java-opcodes.h except.h \
|
||||
java/java-except.h java/java-except.h java/parse.h toplev.h \
|
||||
|
@ -681,6 +681,7 @@ check_init (exp, before)
|
||||
case INTEGER_CST:
|
||||
case REAL_CST:
|
||||
case STRING_CST:
|
||||
case EXC_PTR_EXPR:
|
||||
break;
|
||||
|
||||
case NEW_CLASS_EXPR:
|
||||
|
@ -29,12 +29,14 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "tree.h"
|
||||
#include "rtl.h"
|
||||
#include "toplev.h"
|
||||
#include "flags.h"
|
||||
#include "java-tree.h"
|
||||
#include "jcf.h"
|
||||
#include "toplev.h"
|
||||
#include "function.h"
|
||||
#include "expr.h"
|
||||
#include "except.h"
|
||||
#include "java-except.h"
|
||||
#include "ggc.h"
|
||||
@ -725,13 +727,14 @@ init_decl_processing ()
|
||||
t),
|
||||
0, NOT_BUILT_IN,
|
||||
NULL_PTR);
|
||||
throw_node = builtin_function ((USING_SJLJ_EXCEPTIONS
|
||||
? "_Jv_Throw" : "_Jv_Sjlj_Throw"),
|
||||
|
||||
throw_node = builtin_function ("_Jv_Throw",
|
||||
build_function_type (ptr_type_node, t),
|
||||
0, NOT_BUILT_IN, NULL_PTR);
|
||||
/* Mark throw_nodes as `noreturn' functions with side effects. */
|
||||
TREE_THIS_VOLATILE (throw_node) = 1;
|
||||
TREE_SIDE_EFFECTS (throw_node) = 1;
|
||||
|
||||
t = build_function_type (int_type_node, endlink);
|
||||
soft_monitorenter_node
|
||||
= builtin_function ("_Jv_MonitorEnter", t, 0, NOT_BUILT_IN,
|
||||
@ -834,15 +837,6 @@ init_decl_processing ()
|
||||
build_function_type (double_type_node, t),
|
||||
BUILT_IN_FMOD, BUILT_IN_NORMAL, "fmod");
|
||||
|
||||
soft_exceptioninfo_call_node
|
||||
= build (CALL_EXPR,
|
||||
ptr_type_node,
|
||||
build_address_of
|
||||
(builtin_function ("_Jv_exception_info",
|
||||
build_function_type (ptr_type_node, endlink),
|
||||
0, NOT_BUILT_IN, NULL_PTR)),
|
||||
NULL_TREE, NULL_TREE);
|
||||
TREE_SIDE_EFFECTS (soft_exceptioninfo_call_node) = 1;
|
||||
#if 0
|
||||
t = tree_cons (NULL_TREE, float_type_node,
|
||||
tree_cons (NULL_TREE, float_type_node, endlink));
|
||||
@ -872,6 +866,12 @@ init_decl_processing ()
|
||||
build_function_type (long_type_node, t),
|
||||
0, NOT_BUILT_IN, NULL_PTR);
|
||||
|
||||
/* Initialize variables for except.c. */
|
||||
eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
|
||||
? "__gcj_personality_sj0"
|
||||
: "__gcj_personality_v0");
|
||||
lang_eh_runtime_type = prepare_eh_table_type;
|
||||
|
||||
init_jcf_parse ();
|
||||
|
||||
/* Register nodes with the garbage collector. */
|
||||
@ -1828,8 +1828,6 @@ end_java_method ()
|
||||
|
||||
BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
|
||||
|
||||
emit_handlers ();
|
||||
|
||||
/* Generate rtl for function exit. */
|
||||
expand_function_end (input_filename, lineno, 0);
|
||||
|
||||
|
@ -34,7 +34,6 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
|
||||
#include "function.h"
|
||||
#include "except.h"
|
||||
#include "java-except.h"
|
||||
#include "eh-common.h"
|
||||
#include "toplev.h"
|
||||
|
||||
static void expand_start_java_handler PARAMS ((struct eh_range *));
|
||||
@ -250,14 +249,6 @@ method_init_exceptions ()
|
||||
whole_range.first_child = NULL;
|
||||
whole_range.next_sibling = NULL;
|
||||
cache_range_start = 0xFFFFFF;
|
||||
java_set_exception_lang_code ();
|
||||
}
|
||||
|
||||
void
|
||||
java_set_exception_lang_code ()
|
||||
{
|
||||
set_exception_lang_code (EH_LANG_Java);
|
||||
set_exception_version_code (1);
|
||||
}
|
||||
|
||||
/* Add an exception range. If we already have an exception range
|
||||
@ -339,7 +330,7 @@ prepare_eh_table_type (type)
|
||||
* (which yields a value with low-order bit 1). */
|
||||
|
||||
if (type == NULL_TREE)
|
||||
exp = CATCH_ALL_TYPE;
|
||||
exp = NULL_TREE;
|
||||
else if (is_compiled_class (type))
|
||||
exp = build_class_ref (type);
|
||||
else
|
||||
@ -350,7 +341,27 @@ prepare_eh_table_type (type)
|
||||
return exp;
|
||||
}
|
||||
|
||||
/* if there are any handlers for this range, isssue end of range,
|
||||
|
||||
/* Build a reference to the jthrowable object being carried in the
|
||||
exception header. */
|
||||
|
||||
tree
|
||||
build_exception_object_ref (type)
|
||||
tree type;
|
||||
{
|
||||
tree obj;
|
||||
|
||||
/* Java only passes object via pointer and doesn't require adjusting.
|
||||
The java object is immediately before the generic exception header. */
|
||||
obj = build (EXC_PTR_EXPR, build_pointer_type (type));
|
||||
obj = build (MINUS_EXPR, TREE_TYPE (obj), obj,
|
||||
TYPE_SIZE_UNIT (TREE_TYPE (obj)));
|
||||
obj = build1 (INDIRECT_REF, type, obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* If there are any handlers for this range, isssue end of range,
|
||||
and then all handler blocks */
|
||||
static void
|
||||
expand_end_java_handler (range)
|
||||
@ -361,11 +372,9 @@ expand_end_java_handler (range)
|
||||
expand_start_all_catch ();
|
||||
for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
|
||||
{
|
||||
start_catch_handler (prepare_eh_table_type (TREE_PURPOSE (handler)));
|
||||
/* Push the thrown object on the top of the stack */
|
||||
expand_start_catch (TREE_PURPOSE (handler));
|
||||
expand_goto (TREE_VALUE (handler));
|
||||
expand_resume_after_catch ();
|
||||
end_catch_handler ();
|
||||
expand_end_catch ();
|
||||
}
|
||||
expand_end_all_catch ();
|
||||
#if defined(DEBUG_JAVA_BINDING_LEVELS)
|
||||
@ -432,30 +441,3 @@ maybe_end_try (start_pc, end_pc)
|
||||
current_range = current_range->outer;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit the handler labels and their code */
|
||||
|
||||
void
|
||||
emit_handlers ()
|
||||
{
|
||||
if (catch_clauses)
|
||||
{
|
||||
rtx funcend = gen_label_rtx ();
|
||||
emit_jump (funcend);
|
||||
|
||||
emit_insns (catch_clauses);
|
||||
catch_clauses = catch_clauses_last = NULL_RTX;
|
||||
expand_leftover_cleanups ();
|
||||
|
||||
emit_label (funcend);
|
||||
}
|
||||
}
|
||||
|
||||
/* Resume executing at the statement immediately after the end of an
|
||||
exception region. */
|
||||
|
||||
void
|
||||
expand_resume_after_catch ()
|
||||
{
|
||||
expand_goto (top_label_entry (&caught_return_label_stack));
|
||||
}
|
||||
|
@ -2502,15 +2502,13 @@ java_lang_expand_expr (exp, target, tmode, modifier)
|
||||
for (current = TREE_OPERAND (exp, 1); current;
|
||||
current = TREE_CHAIN (current))
|
||||
{
|
||||
tree type;
|
||||
tree catch = TREE_OPERAND (current, 0);
|
||||
tree decl = BLOCK_EXPR_DECLS (catch);
|
||||
type = (decl ? TREE_TYPE (TREE_TYPE (decl)) : NULL_TREE);
|
||||
start_catch_handler (prepare_eh_table_type (type));
|
||||
expand_expr_stmt (TREE_OPERAND (current, 0));
|
||||
tree type = (decl ? TREE_TYPE (TREE_TYPE (decl)) : NULL_TREE);
|
||||
|
||||
expand_resume_after_catch ();
|
||||
end_catch_handler ();
|
||||
expand_start_catch (type);
|
||||
expand_expr_stmt (TREE_OPERAND (current, 0));
|
||||
expand_end_catch ();
|
||||
}
|
||||
expand_end_all_catch ();
|
||||
return const0_rtx;
|
||||
@ -2812,7 +2810,7 @@ process_jvm_instruction (PC, byte_ops, length)
|
||||
if (instruction_bits [PC] & BCODE_EXCEPTION_TARGET)
|
||||
{
|
||||
tree type = pop_type (ptr_type_node);
|
||||
push_value (build1 (NOP_EXPR, type, soft_exceptioninfo_call_node));
|
||||
push_value (build_exception_object_ref (type));
|
||||
}
|
||||
|
||||
switch (byte_ops[PC++])
|
||||
|
@ -339,7 +339,6 @@ enum java_tree_index
|
||||
JTI_SOFT_GETJNIENVNEWFRAME_NODE,
|
||||
JTI_SOFT_JNIPOPSYSTEMFRAME_NODE,
|
||||
JTI_SOFT_FMOD_NODE,
|
||||
JTI_SOFT_EXCEPTIONINFO_CALL_NODE,
|
||||
JTI_SOFT_IDIV_NODE,
|
||||
JTI_SOFT_IREM_NODE,
|
||||
JTI_SOFT_LDIV_NODE,
|
||||
@ -581,8 +580,6 @@ extern tree java_global_trees[JTI_MAX];
|
||||
java_global_trees[JTI_SOFT_JNIPOPSYSTEMFRAME_NODE]
|
||||
#define soft_fmod_node \
|
||||
java_global_trees[JTI_SOFT_FMOD_NODE]
|
||||
#define soft_exceptioninfo_call_node \
|
||||
java_global_trees[JTI_SOFT_EXCEPTIONINFO_CALL_NODE]
|
||||
#define soft_idiv_node \
|
||||
java_global_trees[JTI_SOFT_IDIV_NODE]
|
||||
#define soft_irem_node \
|
||||
@ -1026,6 +1023,7 @@ extern tree build_instanceof PARAMS ((tree, tree));
|
||||
extern tree create_label_decl PARAMS ((tree));
|
||||
extern void push_labeled_block PARAMS ((tree));
|
||||
extern tree prepare_eh_table_type PARAMS ((tree));
|
||||
extern tree build_exception_object_ref PARAMS ((tree));
|
||||
extern void java_set_exception_lang_code PARAMS ((void));
|
||||
extern tree generate_name PARAMS ((void));
|
||||
extern void pop_labeled_block PARAMS ((void));
|
||||
|
@ -2451,6 +2451,9 @@ generate_bytecode_insns (exp, target, state)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXC_PTR_EXPR:
|
||||
NOTE_PUSH (1); /* Pushed by exception system. */
|
||||
break;
|
||||
case NEW_CLASS_EXPR:
|
||||
{
|
||||
tree class = TREE_TYPE (TREE_TYPE (exp));
|
||||
@ -2527,11 +2530,6 @@ generate_bytecode_insns (exp, target, state)
|
||||
NOTE_POP (1);
|
||||
break;
|
||||
}
|
||||
else if (exp == soft_exceptioninfo_call_node)
|
||||
{
|
||||
NOTE_PUSH (1); /* Pushed by exception system. */
|
||||
break;
|
||||
}
|
||||
for ( ; x != NULL_TREE; x = TREE_CHAIN (x))
|
||||
{
|
||||
generate_bytecode_insns (TREE_VALUE (x), STACK_TARGET, state);
|
||||
|
@ -661,14 +661,6 @@ typedef struct _jdeplist {
|
||||
build_new_invocation (wfl_string_buffer, \
|
||||
(ARG ? build_tree_list (NULL, (ARG)) : NULL_TREE))
|
||||
|
||||
/* For exception handling, build diverse function calls */
|
||||
#define BUILD_ASSIGN_EXCEPTION_INFO(WHERE, TO) \
|
||||
{ \
|
||||
(WHERE) = build (MODIFY_EXPR, void_type_node, (TO), \
|
||||
soft_exceptioninfo_call_node); \
|
||||
TREE_SIDE_EFFECTS (WHERE) = 1; \
|
||||
}
|
||||
|
||||
#define BUILD_THROW(WHERE, WHAT) \
|
||||
{ \
|
||||
(WHERE) = \
|
||||
|
@ -1885,9 +1885,9 @@ catch_clause_parameter:
|
||||
declared initialized by the appropriate function
|
||||
call */
|
||||
tree ccpb = enter_block ();
|
||||
tree init = build_assignment (ASSIGN_TK, $2.location,
|
||||
TREE_PURPOSE ($3),
|
||||
soft_exceptioninfo_call_node);
|
||||
tree init = build_assignment
|
||||
(ASSIGN_TK, $2.location, TREE_PURPOSE ($3),
|
||||
build_exception_object_ref (ptr_type_node));
|
||||
declare_local_variables (0, TREE_VALUE ($3),
|
||||
build_tree_list (TREE_PURPOSE ($3),
|
||||
init));
|
||||
@ -7124,9 +7124,6 @@ source_end_java_method ()
|
||||
java_parser_context_save_global ();
|
||||
lineno = ctxp->last_ccb_indent1;
|
||||
|
||||
/* Set EH language codes */
|
||||
java_set_exception_lang_code ();
|
||||
|
||||
/* Turn function bodies with only a NOP expr null, so they don't get
|
||||
generated at all and we won't get warnings when using the -W
|
||||
-Wall flags. */
|
||||
@ -7148,8 +7145,6 @@ source_end_java_method ()
|
||||
if (! flag_emit_class_files && ! flag_emit_xref)
|
||||
{
|
||||
lineno = DECL_SOURCE_LINE_LAST (fndecl);
|
||||
/* Emit catch-finally clauses */
|
||||
emit_handlers ();
|
||||
expand_function_end (input_filename, lineno, 0);
|
||||
|
||||
/* Run the optimizers and output assembler code for this function. */
|
||||
@ -8405,7 +8400,7 @@ build_dot_class_method (class)
|
||||
|
||||
/* We initialize the variable with the exception handler. */
|
||||
catch = build (MODIFY_EXPR, NULL_TREE, catch_clause_param,
|
||||
soft_exceptioninfo_call_node);
|
||||
build_exception_object_ref (ptr_type_node));
|
||||
add_stmt_to_block (catch_block, NULL_TREE, catch);
|
||||
|
||||
/* We add the statement throwing the new exception */
|
||||
@ -12609,7 +12604,7 @@ try_reference_assignconv (lhs_type, rhs)
|
||||
else if (valid_ref_assignconv_cast_p (rhs_type, lhs_type, 0))
|
||||
new_rhs = rhs;
|
||||
/* This is a magic assignment that we process differently */
|
||||
else if (rhs == soft_exceptioninfo_call_node)
|
||||
else if (TREE_CODE (rhs) == EXC_PTR_EXPR)
|
||||
new_rhs = rhs;
|
||||
}
|
||||
return new_rhs;
|
||||
|
18
gcc/jump.c
18
gcc/jump.c
@ -213,12 +213,6 @@ jump_optimize_1 (f, cross_jump, noop_moves, after_regscan,
|
||||
cross_jump_death_matters = (cross_jump == 2);
|
||||
max_uid = init_label_info (f) + 1;
|
||||
|
||||
/* If we are performing cross jump optimizations, then initialize
|
||||
tables mapping UIDs to EH regions to avoid incorrect movement
|
||||
of insns from one EH region to another. */
|
||||
if (flag_exceptions && cross_jump)
|
||||
init_insn_eh_region (f, max_uid);
|
||||
|
||||
if (! mark_labels_only)
|
||||
delete_barrier_successors (f);
|
||||
|
||||
@ -237,8 +231,6 @@ jump_optimize_1 (f, cross_jump, noop_moves, after_regscan,
|
||||
if (GET_CODE (XEXP (insn, 0)) == CODE_LABEL)
|
||||
LABEL_NUSES (XEXP (insn, 0))++;
|
||||
|
||||
check_exception_handler_labels ();
|
||||
|
||||
/* Keep track of labels used for marking handlers for exception
|
||||
regions; they cannot usually be deleted. */
|
||||
|
||||
@ -251,9 +243,6 @@ jump_optimize_1 (f, cross_jump, noop_moves, after_regscan,
|
||||
if (mark_labels_only)
|
||||
goto end;
|
||||
|
||||
if (! minimal)
|
||||
exception_optimize ();
|
||||
|
||||
last_insn = delete_unreferenced_labels (f);
|
||||
|
||||
if (noop_moves)
|
||||
@ -1444,13 +1433,6 @@ find_cross_jump (e1, e2, minimum, f1, f2)
|
||||
if (i2 == 0 || GET_CODE (i1) != GET_CODE (i2))
|
||||
break;
|
||||
|
||||
/* Avoid moving insns across EH regions if either of the insns
|
||||
can throw. */
|
||||
if (flag_exceptions
|
||||
&& (flag_non_call_exceptions || GET_CODE (i1) == CALL_INSN)
|
||||
&& !in_same_eh_region (i1, i2))
|
||||
break;
|
||||
|
||||
p1 = PATTERN (i1);
|
||||
p2 = PATTERN (i2);
|
||||
|
||||
|
@ -114,28 +114,27 @@ GCC_3.0 {
|
||||
__gcc_bcmp
|
||||
|
||||
# EH symbols
|
||||
__default_terminate
|
||||
_Unwind_DeleteException
|
||||
_Unwind_ForcedUnwind
|
||||
_Unwind_GetGR
|
||||
_Unwind_GetIP
|
||||
_Unwind_GetLanguageSpecificData
|
||||
_Unwind_GetRegionStart
|
||||
_Unwind_RaiseException
|
||||
_Unwind_Resume
|
||||
_Unwind_SetGR
|
||||
_Unwind_SetIP
|
||||
__deregister_frame
|
||||
__deregister_frame_info
|
||||
__eh_alloc
|
||||
__eh_free
|
||||
__eh_rtime_match
|
||||
__frame_state_for
|
||||
__get_dynamic_handler_chain
|
||||
__get_eh_context
|
||||
__get_eh_info
|
||||
__get_eh_table_language
|
||||
__get_eh_table_version
|
||||
__register_frame
|
||||
__register_frame_info
|
||||
__register_frame_info_table
|
||||
__register_frame_table
|
||||
__rethrow
|
||||
__sjpopnthrow
|
||||
__sjthrow
|
||||
__terminate
|
||||
__terminate_set_func
|
||||
__throw
|
||||
__throw_type_match
|
||||
__unwinding_cleanup
|
||||
|
||||
# SjLj EH symbols
|
||||
_Unwind_SjLj_Register
|
||||
_Unwind_SjLj_Unregister
|
||||
_Unwind_SjLj_RaiseException
|
||||
_Unwind_SjLj_ForcedUnwind
|
||||
_Unwind_SjLj_Resume
|
||||
}
|
||||
|
1218
gcc/libgcc2.c
1218
gcc/libgcc2.c
File diff suppressed because it is too large
Load Diff
30
gcc/md.texi
30
gcc/md.texi
@ -2848,26 +2848,24 @@ You will not normally need to define this pattern unless you also define
|
||||
@code{builtin_setjmp_setup}. The single argument is a pointer to the
|
||||
@code{jmp_buf}.
|
||||
|
||||
@cindex @code{eh_epilogue} instruction pattern
|
||||
@item @samp{eh_epilogue}
|
||||
@cindex @code{eh_return} instruction pattern
|
||||
@item @samp{eh_return}
|
||||
This pattern, if defined, affects the way @code{__builtin_eh_return},
|
||||
and thence @code{__throw} are built. It is intended to allow communication
|
||||
between the exception handling machinery and the normal epilogue code
|
||||
for the target.
|
||||
and thence the call frame exception handling library routines, are
|
||||
built. It is intended to handle non-trivial actions needed along
|
||||
the abnormal return path.
|
||||
|
||||
The pattern takes three arguments. The first is the exception context
|
||||
pointer. This will have already been copied to the function return
|
||||
register appropriate for a pointer; normally this can be ignored. The
|
||||
second argument is an offset to be added to the stack pointer. It will
|
||||
have been copied to some arbitrary call-clobbered hard reg so that it
|
||||
will survive until after reload to when the normal epilogue is generated.
|
||||
The final argument is the address of the exception handler to which
|
||||
The pattern takes two arguments. The first is an offset to be applied
|
||||
to the stack pointer. It will have been copied to some appropriate
|
||||
location (typically @code{EH_RETURN_STACKADJ_RTX}) which will survive
|
||||
until after reload to when the normal epilogue is generated.
|
||||
The second argument is the address of the exception handler to which
|
||||
the function should return. This will normally need to copied by the
|
||||
pattern to some special register.
|
||||
pattern to some special register or memory location.
|
||||
|
||||
This pattern must be defined if @code{RETURN_ADDR_RTX} does not yield
|
||||
something that can be reliably and permanently modified, i.e. a fixed
|
||||
hard register or a stack memory reference.
|
||||
This pattern only needs to be defined if call frame exception handling
|
||||
is to be used, and simple moves to @code{EH_RETURN_STACKADJ_RTX} and
|
||||
@code{EH_RETURN_HANDLER_RTX} are not sufficient.
|
||||
|
||||
@cindex @code{prologue} instruction pattern
|
||||
@item @samp{prologue}
|
||||
|
@ -14,8 +14,9 @@
|
||||
# LIB1ASMFUNCS
|
||||
# LIB1FUNCS_EXTRA
|
||||
# LIB2FUNCS
|
||||
# LIB2FUNCS_EH
|
||||
# LIB2ADD
|
||||
# LIB2ADDEH
|
||||
# LIB2ADDEHDEP
|
||||
# FPBIT
|
||||
# FPBIT_FUNCS
|
||||
# DPBIT
|
||||
@ -79,7 +80,7 @@ make_compile='$(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
|
||||
libgcc1_c_dep='stmp-dirs $(srcdir)/libgcc1.c $(CONFIG_H)'
|
||||
|
||||
# Dependancies for libgcc2.c
|
||||
libgcc2_c_dep='stmp-dirs $(srcdir)/libgcc2.c $(CONFIG_H) $(MACHMODE_H) longlong.h frame.h gbl-ctors.h config.status stmp-int-hdrs tsystem.h'
|
||||
libgcc2_c_dep='stmp-dirs $(srcdir)/libgcc2.c $(CONFIG_H) $(MACHMODE_H) longlong.h gbl-ctors.h config.status stmp-int-hdrs tsystem.h'" $LIB2ADDEHDEP"
|
||||
|
||||
# Dependancies for fp-bit.c
|
||||
fpbit_c_dep='stmp-dirs config.status tsystem.h'
|
||||
@ -180,19 +181,6 @@ for name in $LIB2FUNCS; do
|
||||
libgcc2_objs="$libgcc2_objs ${name}${objext}"
|
||||
done
|
||||
|
||||
for name in $LIB2FUNCS_EH; do
|
||||
for ml in $MULTILIBS; do
|
||||
dir=`echo ${ml} | sed -e 's/;.*$//' -e 's/=/$(EQ)/g'`
|
||||
flags=`echo ${ml} | sed -e 's/^[^;]*;//' -e 's/@/ -/g'`;
|
||||
out="libgcc/${dir}/${name}${objext}"
|
||||
|
||||
echo $out: $libgcc2_c_dep
|
||||
echo " $gcc_compile" '$(MAYBE_USE_COLLECT2)' -fexceptions \
|
||||
$flags -DL$name -c '$(srcdir)/libgcc2.c' -o $out
|
||||
done
|
||||
libgcc2_objs="$libgcc2_objs ${name}${objext}"
|
||||
done
|
||||
|
||||
if [ "$FPBIT" ]; then
|
||||
for name in $FPBIT_FUNCS; do
|
||||
for ml in $MULTILIBS; do
|
||||
@ -241,6 +229,24 @@ for file in $LIB2ADD; do
|
||||
libgcc2_objs="$libgcc2_objs ${oname}${objext}"
|
||||
done
|
||||
|
||||
for file in $LIB2ADDEH; do
|
||||
name=`echo $file | sed -e 's/[.][cSo]$//' -e 's/[.]asm$//' -e 's/[.]txt$//'`
|
||||
oname=`echo $name | sed -e 's,.*/,,'`
|
||||
|
||||
for ml in $MULTILIBS; do
|
||||
dir=`echo ${ml} | sed -e 's/;.*$//' -e 's/=/$(EQ)/g'`
|
||||
flags=`echo ${ml} | sed -e 's/^[^;]*;//' -e 's/@/ -/g'`;
|
||||
out="libgcc/${dir}/${oname}${objext}"
|
||||
if [ ${name}.asm = ${file} ]; then
|
||||
flags="$flags -xassembler-with-cpp"
|
||||
fi
|
||||
|
||||
echo $out: stmp-dirs $file
|
||||
echo " $gcc_compile" $flags -fexceptions -c $file -o $out
|
||||
done
|
||||
libgcc2_objs="$libgcc2_objs ${oname}${objext}"
|
||||
done
|
||||
|
||||
# SHLIB_MKMAP
|
||||
# SHLIB_MAPFILES
|
||||
for ml in $MULTILIBS; do
|
||||
|
13
gcc/optabs.c
13
gcc/optabs.c
@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "tm_p.h"
|
||||
#include "flags.h"
|
||||
#include "function.h"
|
||||
#include "except.h"
|
||||
#include "expr.h"
|
||||
#include "recog.h"
|
||||
#include "reload.h"
|
||||
@ -4758,12 +4759,9 @@ init_optabs ()
|
||||
memset_libfunc = init_one_libfunc ("memset");
|
||||
bzero_libfunc = init_one_libfunc ("bzero");
|
||||
|
||||
throw_libfunc = init_one_libfunc ("__throw");
|
||||
rethrow_libfunc = init_one_libfunc ("__rethrow");
|
||||
sjthrow_libfunc = init_one_libfunc ("__sjthrow");
|
||||
sjpopnthrow_libfunc = init_one_libfunc ("__sjpopnthrow");
|
||||
terminate_libfunc = init_one_libfunc ("__terminate");
|
||||
eh_rtime_match_libfunc = init_one_libfunc ("__eh_rtime_match");
|
||||
unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
|
||||
? "_Unwind_SjLj_Resume"
|
||||
: "_Unwind_Resume");
|
||||
#ifndef DONT_USE_BUILTIN_SETJMP
|
||||
setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");
|
||||
longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");
|
||||
@ -4771,6 +4769,9 @@ init_optabs ()
|
||||
setjmp_libfunc = init_one_libfunc ("setjmp");
|
||||
longjmp_libfunc = init_one_libfunc ("longjmp");
|
||||
#endif
|
||||
unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register");
|
||||
unwind_sjlj_unregister_libfunc
|
||||
= init_one_libfunc ("_Unwind_SjLj_Unregister");
|
||||
|
||||
eqhf2_libfunc = init_one_libfunc ("__eqhf2");
|
||||
nehf2_libfunc = init_one_libfunc ("__nehf2");
|
||||
|
@ -547,6 +547,11 @@ DEF_RTL_EXPR(RETURN, "return", "", 'x')
|
||||
For an unconditional trap, make the condition (const_int 1). */
|
||||
DEF_RTL_EXPR(TRAP_IF, "trap_if", "ee", 'x')
|
||||
|
||||
/* Placeholder for _Unwind_Resume before we know if a function call
|
||||
or a branch is needed. Operand 1 is the exception region from
|
||||
which control is flowing. */
|
||||
DEF_RTL_EXPR(RESX, "resx", "i", 'x')
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
Primitive values for use in expressions.
|
||||
---------------------------------------------------------------------- */
|
||||
|
@ -924,10 +924,6 @@ extern const char * const note_insn_name[NOTE_INSN_MAX - NOTE_INSN_BIAS];
|
||||
/* Flag in a SYMBOL_REF for machine-specific purposes. */
|
||||
#define SYMBOL_REF_FLAG(RTX) ((RTX)->volatil)
|
||||
|
||||
/* 1 in a SYMBOL_REF if it represents a symbol which might have to change
|
||||
if its inlined or unrolled. */
|
||||
#define SYMBOL_REF_NEED_ADJUST(RTX) ((RTX)->in_struct)
|
||||
|
||||
/* 1 means a SYMBOL_REF has been the library function in emit_library_call. */
|
||||
#define SYMBOL_REF_USED(RTX) ((RTX)->used)
|
||||
|
||||
|
122
gcc/stmt.c
122
gcc/stmt.c
@ -4072,12 +4072,11 @@ expand_decl_cleanup (decl, cleanup)
|
||||
start_sequence ();
|
||||
}
|
||||
|
||||
/* If this was optimized so that there is no exception region for the
|
||||
cleanup, then mark the TREE_LIST node, so that we can later tell
|
||||
if we need to call expand_eh_region_end. */
|
||||
if (! using_eh_for_cleanups_p
|
||||
|| expand_eh_region_start_tree (decl, cleanup))
|
||||
if (! using_eh_for_cleanups_p)
|
||||
TREE_ADDRESSABLE (t) = 1;
|
||||
else
|
||||
expand_eh_region_start ();
|
||||
|
||||
/* If that started a new EH region, we're in a new block. */
|
||||
thisblock = block_stack;
|
||||
|
||||
@ -4106,82 +4105,6 @@ expand_decl_cleanup (decl, cleanup)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Arrange for the top element of the dynamic cleanup chain to be
|
||||
popped if we exit the current binding contour. DECL is the
|
||||
associated declaration, if any, otherwise NULL_TREE. If the
|
||||
current contour is left via an exception, then __sjthrow will pop
|
||||
the top element off the dynamic cleanup chain. The code that
|
||||
avoids doing the action we push into the cleanup chain in the
|
||||
exceptional case is contained in expand_cleanups.
|
||||
|
||||
This routine is only used by expand_eh_region_start, and that is
|
||||
the only way in which an exception region should be started. This
|
||||
routine is only used when using the setjmp/longjmp codegen method
|
||||
for exception handling. */
|
||||
|
||||
int
|
||||
expand_dcc_cleanup (decl)
|
||||
tree decl;
|
||||
{
|
||||
struct nesting *thisblock;
|
||||
tree cleanup;
|
||||
|
||||
/* Error if we are not in any block. */
|
||||
if (cfun == 0 || block_stack == 0)
|
||||
return 0;
|
||||
thisblock = block_stack;
|
||||
|
||||
/* Record the cleanup for the dynamic handler chain. */
|
||||
|
||||
cleanup = make_node (POPDCC_EXPR);
|
||||
|
||||
/* Add the cleanup in a manner similar to expand_decl_cleanup. */
|
||||
thisblock->data.block.cleanups
|
||||
= tree_cons (decl, cleanup, thisblock->data.block.cleanups);
|
||||
|
||||
/* If this block has a cleanup, it belongs in stack_block_stack. */
|
||||
stack_block_stack = thisblock;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Arrange for the top element of the dynamic handler chain to be
|
||||
popped if we exit the current binding contour. DECL is the
|
||||
associated declaration, if any, otherwise NULL_TREE. If the current
|
||||
contour is left via an exception, then __sjthrow will pop the top
|
||||
element off the dynamic handler chain. The code that avoids doing
|
||||
the action we push into the handler chain in the exceptional case
|
||||
is contained in expand_cleanups.
|
||||
|
||||
This routine is only used by expand_eh_region_start, and that is
|
||||
the only way in which an exception region should be started. This
|
||||
routine is only used when using the setjmp/longjmp codegen method
|
||||
for exception handling. */
|
||||
|
||||
int
|
||||
expand_dhc_cleanup (decl)
|
||||
tree decl;
|
||||
{
|
||||
struct nesting *thisblock;
|
||||
tree cleanup;
|
||||
|
||||
/* Error if we are not in any block. */
|
||||
if (cfun == 0 || block_stack == 0)
|
||||
return 0;
|
||||
thisblock = block_stack;
|
||||
|
||||
/* Record the cleanup for the dynamic handler chain. */
|
||||
|
||||
cleanup = make_node (POPDHC_EXPR);
|
||||
|
||||
/* Add the cleanup in a manner similar to expand_decl_cleanup. */
|
||||
thisblock->data.block.cleanups
|
||||
= tree_cons (decl, cleanup, thisblock->data.block.cleanups);
|
||||
|
||||
/* If this block has a cleanup, it belongs in stack_block_stack. */
|
||||
stack_block_stack = thisblock;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* DECL is an anonymous union. CLEANUP is a cleanup for DECL.
|
||||
DECL_ELTS is the list of elements that belong to DECL's type.
|
||||
@ -4286,20 +4209,8 @@ expand_cleanups (list, dont_do, in_fixup, reachable)
|
||||
expand_cleanups (TREE_VALUE (tail), dont_do, in_fixup, reachable);
|
||||
else
|
||||
{
|
||||
if (! in_fixup)
|
||||
{
|
||||
tree cleanup = TREE_VALUE (tail);
|
||||
|
||||
/* See expand_d{h,c}c_cleanup for why we avoid this. */
|
||||
if (TREE_CODE (cleanup) != POPDHC_EXPR
|
||||
&& TREE_CODE (cleanup) != POPDCC_EXPR
|
||||
/* See expand_eh_region_start_tree for this case. */
|
||||
&& ! TREE_ADDRESSABLE (tail))
|
||||
{
|
||||
cleanup = protect_with_terminate (cleanup);
|
||||
expand_eh_region_end (cleanup);
|
||||
}
|
||||
}
|
||||
if (! in_fixup && using_eh_for_cleanups_p)
|
||||
expand_eh_region_end_cleanup (TREE_VALUE (tail));
|
||||
|
||||
if (reachable)
|
||||
{
|
||||
@ -4312,19 +4223,18 @@ expand_cleanups (list, dont_do, in_fixup, reachable)
|
||||
times, the control paths are non-overlapping so the
|
||||
cleanups will not be executed twice. */
|
||||
|
||||
/* We may need to protect fixups with rethrow regions. */
|
||||
int protect = (in_fixup && ! TREE_ADDRESSABLE (tail));
|
||||
/* We may need to protect from outer cleanups. */
|
||||
if (in_fixup && using_eh_for_cleanups_p)
|
||||
{
|
||||
expand_eh_region_start ();
|
||||
|
||||
if (protect)
|
||||
expand_fixup_region_start ();
|
||||
expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
|
||||
|
||||
expand_eh_region_end_fixup (TREE_VALUE (tail));
|
||||
}
|
||||
else
|
||||
expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
|
||||
|
||||
/* The cleanup might contain try-blocks, so we have to
|
||||
preserve our current queue. */
|
||||
push_ehqueue ();
|
||||
expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
|
||||
pop_ehqueue ();
|
||||
if (protect)
|
||||
expand_fixup_region_end (TREE_VALUE (tail));
|
||||
free_temp_slots ();
|
||||
}
|
||||
}
|
||||
|
48
gcc/tm.texi
48
gcc/tm.texi
@ -2505,6 +2505,54 @@ You only need to define this macro if the default is incorrect, and you
|
||||
want to support call frame debugging information like that provided by
|
||||
DWARF 2.
|
||||
|
||||
@findex EH_RETURN_DATA_REGNO
|
||||
@item EH_RETURN_DATA_REGNO (@var{N})
|
||||
A C expression whose value is the @var{N}th register number used for
|
||||
data by exception handlers, or @code{INVALID_REGNUM} if fewer than
|
||||
@var{N} registers are usable.
|
||||
|
||||
The exception handling library routines communicate with the exception
|
||||
handlers via a set of agreed upon registers. Ideally these registers
|
||||
should be call-clobbered; it is possible to use call-saved registers,
|
||||
but may negatively impact code size. The target must support at least
|
||||
2 data registers, but should define 4 if there are enough free registers.
|
||||
|
||||
You must define this macro if you want to support call frame exception
|
||||
handling like that provided by DWARF 2.
|
||||
|
||||
@findex EH_RETURN_STACKADJ_RTX
|
||||
@item EH_RETURN_STACKADJ_RTX
|
||||
A C expression whose value is RTL representing a location in which
|
||||
to store a stack adjustment to be applied before function return.
|
||||
This is used to unwind the stack to an exception handler's call frame.
|
||||
It will be assigned zero on code paths that return normally.
|
||||
|
||||
Typically this is a call-clobbered hard register that is otherwise
|
||||
untouched by the epilogue, but could also be a stack slot.
|
||||
|
||||
You must define this macro if you want to support call frame exception
|
||||
handling like that provided by DWARF 2.
|
||||
|
||||
@findex EH_RETURN_HANDLER_RTX
|
||||
@item EH_RETURN_HANDLER_RTX
|
||||
A C expression whose value is RTL representing a location in which
|
||||
to store the address of an exception handler to which we should
|
||||
return. It will not be assigned on code paths that return normally.
|
||||
|
||||
Typically this is the location in the call frame at which the normal
|
||||
return address is stored. For targets that return by popping an
|
||||
address off the stack, this might be a memory address just below
|
||||
the @emph{target} call frame rather than inside the current call
|
||||
frame. @code{EH_RETURN_STACKADJ_RTX} will have already been assigned,
|
||||
so it may be used to calculate the location of the target call frame.
|
||||
|
||||
Some targets have more complex requirements than storing to an
|
||||
address calculable during initial code generation. In that case
|
||||
the @code{eh_return} instruction pattern should be used instead.
|
||||
|
||||
If you want to support call frame exception handling, you must
|
||||
define either this macro or the @code{eh_return} instruction pattern.
|
||||
|
||||
@findex SMALL_STACK
|
||||
@item SMALL_STACK
|
||||
Define this macro if the stack size for the target is very small. This
|
||||
|
49
gcc/toplev.c
49
gcc/toplev.c
@ -252,6 +252,7 @@ enum dump_file_index
|
||||
{
|
||||
DFI_rtl,
|
||||
DFI_sibling,
|
||||
DFI_eh,
|
||||
DFI_jump,
|
||||
DFI_cse,
|
||||
DFI_addressof,
|
||||
@ -289,7 +290,7 @@ enum dump_file_index
|
||||
|
||||
Remaining -d letters:
|
||||
|
||||
" h o q u "
|
||||
" o q u "
|
||||
" H K OPQ TUVW YZ"
|
||||
*/
|
||||
|
||||
@ -297,6 +298,7 @@ struct dump_file_info dump_file[DFI_MAX] =
|
||||
{
|
||||
{ "rtl", 'r', 0, 0, 0 },
|
||||
{ "sibling", 'i', 0, 0, 0 },
|
||||
{ "eh", 'h', 0, 0, 0 },
|
||||
{ "jump", 'j', 0, 0, 0 },
|
||||
{ "cse", 's', 0, 0, 0 },
|
||||
{ "addressof", 'F', 0, 0, 0 },
|
||||
@ -2162,9 +2164,9 @@ compile_file (name)
|
||||
init_regs ();
|
||||
init_alias_once ();
|
||||
init_decl_processing ();
|
||||
init_eh ();
|
||||
init_optabs ();
|
||||
init_stmt ();
|
||||
init_eh ();
|
||||
init_loop ();
|
||||
init_reload ();
|
||||
init_function_once ();
|
||||
@ -2402,14 +2404,6 @@ compile_file (name)
|
||||
loop above. */
|
||||
output_func_start_profiler ();
|
||||
|
||||
/* Now that all possible functions have been output, we can dump
|
||||
the exception table. */
|
||||
|
||||
#ifndef IA64_UNWIND_INFO
|
||||
output_exception_table ();
|
||||
#endif
|
||||
free_exception_table ();
|
||||
|
||||
check_global_declarations (vec, len);
|
||||
|
||||
/* Clean up. */
|
||||
@ -2805,6 +2799,11 @@ rest_of_compilation (decl)
|
||||
close_dump_file (DFI_rtl, print_rtl, insns);
|
||||
}
|
||||
|
||||
/* Convert from NOTE_INSN_EH_REGION style notes, and do other
|
||||
sorts of eh initialization. Delay this until after the
|
||||
initial rtl dump so that we can see the original nesting. */
|
||||
convert_from_eh_region_ranges ();
|
||||
|
||||
/* If function is inline, and we don't yet know whether to
|
||||
compile it by itself, defer decision till end of compilation.
|
||||
finish_compilation will call rest_of_compilation again
|
||||
@ -2884,9 +2883,6 @@ rest_of_compilation (decl)
|
||||
if ((rtl_dump_and_exit || flag_syntax_only) && !warn_return_type)
|
||||
goto exit_rest_of_compilation;
|
||||
|
||||
/* Emit code to get eh context, if needed. */
|
||||
emit_eh_context ();
|
||||
|
||||
/* We may have potential sibling or tail recursion sites. Select one
|
||||
(of possibly multiple) methods of performing the call. */
|
||||
if (flag_optimize_sibling_calls)
|
||||
@ -2900,6 +2896,19 @@ rest_of_compilation (decl)
|
||||
timevar_pop (TV_JUMP);
|
||||
}
|
||||
|
||||
/* Complete generation of exception handling code. */
|
||||
find_exception_handler_labels ();
|
||||
if (doing_eh (0))
|
||||
{
|
||||
timevar_push (TV_JUMP);
|
||||
open_dump_file (DFI_eh, decl);
|
||||
|
||||
finish_eh_generation ();
|
||||
|
||||
close_dump_file (DFI_eh, print_rtl, get_insns ());
|
||||
timevar_pop (TV_JUMP);
|
||||
}
|
||||
|
||||
#ifdef FINALIZE_PIC
|
||||
/* If we are doing position-independent code generation, now
|
||||
is the time to output special prologues and epilogues.
|
||||
@ -2923,9 +2932,6 @@ rest_of_compilation (decl)
|
||||
/* Instantiate all virtual registers. */
|
||||
instantiate_virtual_regs (current_function_decl, insns);
|
||||
|
||||
/* Find all the EH handlers. */
|
||||
find_exception_handler_labels ();
|
||||
|
||||
open_dump_file (DFI_jump, decl);
|
||||
|
||||
/* Always do one jump optimization pass to ensure that JUMP_LABEL fields
|
||||
@ -3679,6 +3685,12 @@ rest_of_compilation (decl)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef STACK_REGS
|
||||
/* ??? Do this before shorten branches so that we aren't creating
|
||||
insns too late and fail sanity checks in final. */
|
||||
convert_to_eh_region_ranges ();
|
||||
#endif
|
||||
|
||||
/* Shorten branches.
|
||||
|
||||
Note this must run before reg-stack because of death note (ab)use
|
||||
@ -3697,6 +3709,8 @@ rest_of_compilation (decl)
|
||||
timevar_pop (TV_REG_STACK);
|
||||
|
||||
ggc_collect ();
|
||||
|
||||
convert_to_eh_region_ranges ();
|
||||
#endif
|
||||
|
||||
current_function_nothrow = nothrow_function_p ();
|
||||
@ -3728,6 +3742,9 @@ rest_of_compilation (decl)
|
||||
final (insns, asm_out_file, optimize, 0);
|
||||
final_end_function (insns, asm_out_file, optimize);
|
||||
assemble_end_function (decl, fnname);
|
||||
|
||||
output_function_exception_table ();
|
||||
|
||||
if (! quiet_flag)
|
||||
fflush (asm_out_file);
|
||||
|
||||
|
15
gcc/tree.def
15
gcc/tree.def
@ -770,17 +770,6 @@ DEFTREECODE (TRY_FINALLY_EXPR, "try_finally", 'e', 2)
|
||||
Operand 1 is the rtx for a variable in which to store the address
|
||||
of where the subroutine should return to. */
|
||||
DEFTREECODE (GOTO_SUBROUTINE_EXPR, "goto_subroutine", 'e', 2)
|
||||
|
||||
/* Pop the top element off the dynamic handler chain. Used in
|
||||
conjunction with setjmp/longjmp based exception handling, see
|
||||
except.c for more details. This is meant to be used only by the
|
||||
exception handling backend, expand_dhc_cleanup specifically. */
|
||||
DEFTREECODE (POPDHC_EXPR, "popdhc_expr", 's', 0)
|
||||
|
||||
/* Pop the top element off the dynamic cleanup chain. Used in
|
||||
conjunction with the exception handling. This is meant to be used
|
||||
only by the exception handling backend. */
|
||||
DEFTREECODE (POPDCC_EXPR, "popdcc_expr", 's', 0)
|
||||
|
||||
/* These types of expressions have no useful value,
|
||||
and always have side effects. */
|
||||
@ -834,6 +823,10 @@ DEFTREECODE (EXPR_WITH_FILE_LOCATION, "expr_with_file_location", 'e', 3)
|
||||
Operand 1 contains the case values. The way they're organized is
|
||||
front-end implementation defined. */
|
||||
DEFTREECODE (SWITCH_EXPR, "switch_expr", 'e', 2)
|
||||
|
||||
/* The exception object from the runtime. */
|
||||
DEFTREECODE (EXC_PTR_EXPR, "exc_ptr_expr", 'e', 0)
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
mode:c
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* Subroutines needed for unwinding stack frames for exception handling. */
|
||||
/* Compile this one with gcc. */
|
||||
/* Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
Contributed by Jason Merrill <jason@cygnus.com>.
|
||||
|
||||
This file is part of GNU CC.
|
||||
@ -29,6 +28,129 @@ 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 "tconfig.h"
|
||||
#include "tsystem.h"
|
||||
#include "unwind-dw2-fde.h"
|
||||
#include "gthr.h"
|
||||
|
||||
static struct object *objects;
|
||||
|
||||
#ifdef __GTHREAD_MUTEX_INIT
|
||||
static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
|
||||
#else
|
||||
static __gthread_mutex_t object_mutex;
|
||||
#endif
|
||||
|
||||
#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
|
||||
static void
|
||||
init_object_mutex (void)
|
||||
{
|
||||
__GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
init_object_mutex_once (void)
|
||||
{
|
||||
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
|
||||
__gthread_once (&once, init_object_mutex);
|
||||
}
|
||||
#else
|
||||
#define init_object_mutex_once()
|
||||
#endif
|
||||
|
||||
/* Called from crtbegin.o to register the unwind info for an object. */
|
||||
|
||||
void
|
||||
__register_frame_info (void *begin, struct object *ob)
|
||||
{
|
||||
ob->pc_begin = ob->pc_end = 0;
|
||||
ob->fde_begin = begin;
|
||||
ob->fde_array = 0;
|
||||
ob->count = 0;
|
||||
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
|
||||
ob->next = objects;
|
||||
objects = ob;
|
||||
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
__register_frame (void *begin)
|
||||
{
|
||||
struct object *ob = (struct object *) malloc (sizeof (struct object));
|
||||
__register_frame_info (begin, ob);
|
||||
}
|
||||
|
||||
/* Similar, but BEGIN is actually a pointer to a table of unwind entries
|
||||
for different translation units. Called from the file generated by
|
||||
collect2. */
|
||||
|
||||
void
|
||||
__register_frame_info_table (void *begin, struct object *ob)
|
||||
{
|
||||
ob->pc_begin = ob->pc_end = 0;
|
||||
ob->fde_begin = begin;
|
||||
ob->fde_array = begin;
|
||||
ob->count = 0;
|
||||
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
|
||||
ob->next = objects;
|
||||
objects = ob;
|
||||
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
__register_frame_table (void *begin)
|
||||
{
|
||||
struct object *ob = (struct object *) malloc (sizeof (struct object));
|
||||
__register_frame_info_table (begin, ob);
|
||||
}
|
||||
|
||||
/* Called from crtbegin.o to deregister the unwind info for an object. */
|
||||
|
||||
void *
|
||||
__deregister_frame_info (void *begin)
|
||||
{
|
||||
struct object **p;
|
||||
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
|
||||
p = &objects;
|
||||
while (*p)
|
||||
{
|
||||
if ((*p)->fde_begin == begin)
|
||||
{
|
||||
struct object *ob = *p;
|
||||
*p = (*p)->next;
|
||||
|
||||
/* If we've run init_frame for this object, free the FDE array. */
|
||||
if (ob->fde_array && ob->fde_array != begin)
|
||||
free (ob->fde_array);
|
||||
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
return (void *) ob;
|
||||
}
|
||||
p = &((*p)->next);
|
||||
}
|
||||
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
__deregister_frame (void *begin)
|
||||
{
|
||||
free (__deregister_frame_info (begin));
|
||||
}
|
||||
|
||||
|
||||
/* Sorting an array of FDEs by address.
|
||||
(Ideally we would have the linker sort the FDEs so we don't have to do
|
||||
it at run time. But the linkers are not yet prepared for this.) */
|
||||
@ -56,6 +178,12 @@ typedef struct fde_accumulator
|
||||
fde_vector erratic;
|
||||
} fde_accumulator;
|
||||
|
||||
static inline saddr
|
||||
fde_compare (fde *x, fde *y)
|
||||
{
|
||||
return (saddr)x->pc_begin - (saddr)y->pc_begin;
|
||||
}
|
||||
|
||||
static inline int
|
||||
start_fde_sort (fde_accumulator *accu, size_t count)
|
||||
{
|
||||
@ -241,97 +369,174 @@ end_fde_sort (fde_accumulator *accu, size_t count)
|
||||
return accu->linear.array;
|
||||
}
|
||||
|
||||
/* Called from crtbegin.o to register the unwind info for an object. */
|
||||
|
||||
void
|
||||
__register_frame_info (void *begin, struct object *ob)
|
||||
|
||||
static size_t
|
||||
count_fdes (fde *this_fde)
|
||||
{
|
||||
ob->fde_begin = begin;
|
||||
size_t count;
|
||||
|
||||
ob->pc_begin = ob->pc_end = 0;
|
||||
ob->fde_array = 0;
|
||||
ob->count = 0;
|
||||
for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
/* Skip CIEs and omitted link-once FDE entries. */
|
||||
if (this_fde->CIE_delta != 0 && this_fde->pc_begin != 0)
|
||||
++count;
|
||||
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
|
||||
ob->next = objects;
|
||||
objects = ob;
|
||||
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
return count;
|
||||
}
|
||||
|
||||
void
|
||||
__register_frame (void *begin)
|
||||
static void
|
||||
add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr)
|
||||
{
|
||||
struct object *ob = (struct object *) malloc (sizeof (struct object));
|
||||
__register_frame_info (begin, ob);
|
||||
}
|
||||
void *pc_begin = *beg_ptr;
|
||||
void *pc_end = *end_ptr;
|
||||
|
||||
/* Similar, but BEGIN is actually a pointer to a table of unwind entries
|
||||
for different translation units. Called from the file generated by
|
||||
collect2. */
|
||||
|
||||
void
|
||||
__register_frame_info_table (void *begin, struct object *ob)
|
||||
{
|
||||
ob->fde_begin = begin;
|
||||
ob->fde_array = begin;
|
||||
|
||||
ob->pc_begin = ob->pc_end = 0;
|
||||
ob->count = 0;
|
||||
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
|
||||
ob->next = objects;
|
||||
objects = ob;
|
||||
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
__register_frame_table (void *begin)
|
||||
{
|
||||
struct object *ob = (struct object *) malloc (sizeof (struct object));
|
||||
__register_frame_info_table (begin, ob);
|
||||
}
|
||||
|
||||
/* Called from crtbegin.o to deregister the unwind info for an object. */
|
||||
|
||||
void *
|
||||
__deregister_frame_info (void *begin)
|
||||
{
|
||||
struct object **p;
|
||||
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
|
||||
p = &objects;
|
||||
while (*p)
|
||||
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
if ((*p)->fde_begin == begin)
|
||||
{
|
||||
struct object *ob = *p;
|
||||
*p = (*p)->next;
|
||||
/* Skip CIEs and linked once FDE entries. */
|
||||
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
|
||||
continue;
|
||||
|
||||
/* If we've run init_frame for this object, free the FDE array. */
|
||||
if (ob->fde_array && ob->fde_array != begin)
|
||||
free (ob->fde_array);
|
||||
fde_insert (accu, this_fde);
|
||||
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
return (void *) ob;
|
||||
}
|
||||
p = &((*p)->next);
|
||||
if (this_fde->pc_begin < pc_begin)
|
||||
pc_begin = this_fde->pc_begin;
|
||||
if (this_fde->pc_begin + this_fde->pc_range > pc_end)
|
||||
pc_end = this_fde->pc_begin + this_fde->pc_range;
|
||||
}
|
||||
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
abort ();
|
||||
*beg_ptr = pc_begin;
|
||||
*end_ptr = pc_end;
|
||||
}
|
||||
|
||||
void
|
||||
__deregister_frame (void *begin)
|
||||
static fde *
|
||||
search_fdes (fde *this_fde, void *pc)
|
||||
{
|
||||
free (__deregister_frame_info (begin));
|
||||
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs and linked once FDE entries. */
|
||||
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
|
||||
continue;
|
||||
|
||||
if ((uaddr)((char *)pc - (char *)this_fde->pc_begin) < this_fde->pc_range)
|
||||
return this_fde;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set up a sorted array of pointers to FDEs for a loaded object. We
|
||||
count up the entries before allocating the array because it's likely to
|
||||
be faster. We can be called multiple times, should we have failed to
|
||||
allocate a sorted fde array on a previous occasion. */
|
||||
|
||||
static void
|
||||
frame_init (struct object* ob)
|
||||
{
|
||||
size_t count;
|
||||
fde_accumulator accu;
|
||||
void *pc_begin, *pc_end;
|
||||
fde **array;
|
||||
|
||||
if (ob->pc_begin)
|
||||
count = ob->count;
|
||||
else if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
for (count = 0; *p; ++p)
|
||||
count += count_fdes (*p);
|
||||
}
|
||||
else
|
||||
count = count_fdes (ob->fde_begin);
|
||||
ob->count = count;
|
||||
|
||||
if (!start_fde_sort (&accu, count) && ob->pc_begin)
|
||||
return;
|
||||
|
||||
pc_begin = (void*)(uaddr)-1;
|
||||
pc_end = 0;
|
||||
|
||||
if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
for (; *p; ++p)
|
||||
add_fdes (*p, &accu, &pc_begin, &pc_end);
|
||||
}
|
||||
else
|
||||
add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end);
|
||||
array = end_fde_sort (&accu, count);
|
||||
if (array)
|
||||
ob->fde_array = array;
|
||||
ob->pc_begin = pc_begin;
|
||||
ob->pc_end = pc_end;
|
||||
}
|
||||
|
||||
fde *
|
||||
_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
{
|
||||
struct object *ob;
|
||||
size_t lo, hi;
|
||||
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
|
||||
/* Linear search through the objects, to find the one containing the pc. */
|
||||
for (ob = objects; ob; ob = ob->next)
|
||||
{
|
||||
if (ob->pc_begin == 0)
|
||||
frame_init (ob);
|
||||
if (pc >= ob->pc_begin && pc < ob->pc_end)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ob == 0)
|
||||
{
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ob->fde_array || (void *)ob->fde_array == (void *)ob->fde_begin)
|
||||
frame_init (ob);
|
||||
|
||||
if (ob->fde_array && (void *)ob->fde_array != (void *)ob->fde_begin)
|
||||
{
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
|
||||
/* Standard binary search algorithm. */
|
||||
for (lo = 0, hi = ob->count; lo < hi; )
|
||||
{
|
||||
size_t i = (lo + hi) / 2;
|
||||
fde *f = ob->fde_array[i];
|
||||
|
||||
if (pc < f->pc_begin)
|
||||
hi = i;
|
||||
else if (pc >= f->pc_begin + f->pc_range)
|
||||
lo = i + 1;
|
||||
else
|
||||
return f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Long slow labourious linear search, cos we've no memory. */
|
||||
fde *f;
|
||||
|
||||
if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
|
||||
do
|
||||
{
|
||||
f = search_fdes (*p, pc);
|
||||
if (f)
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
while (*p);
|
||||
}
|
||||
else
|
||||
f = search_fdes (ob->fde_begin, pc);
|
||||
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
return f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
120
gcc/unwind-dw2-fde.h
Normal file
120
gcc/unwind-dw2-fde.h
Normal file
@ -0,0 +1,120 @@
|
||||
/* Subroutines needed for unwinding stack frames for exception handling. */
|
||||
/* Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
Contributed by Jason Merrill <jason@cygnus.com>.
|
||||
|
||||
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.
|
||||
|
||||
In addition to the permissions in the GNU General Public License, the
|
||||
Free Software Foundation gives you unlimited permission to link the
|
||||
compiled version of this file into combinations with other programs,
|
||||
and to distribute those combinations without any restriction coming
|
||||
from the use of this file. (The General Public License restrictions
|
||||
do apply in other respects; for example, they cover modification of
|
||||
the file, and distribution when not linked into a combine
|
||||
executable.)
|
||||
|
||||
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. */
|
||||
|
||||
|
||||
/* Describes data used to hold onto one shared object or object file. */
|
||||
struct object
|
||||
{
|
||||
void *pc_begin;
|
||||
void *pc_end;
|
||||
struct dwarf_fde *fde_begin;
|
||||
struct dwarf_fde **fde_array;
|
||||
size_t count;
|
||||
struct object *next;
|
||||
};
|
||||
|
||||
struct dwarf_eh_bases
|
||||
{
|
||||
void *tbase;
|
||||
void *dbase;
|
||||
void *func;
|
||||
};
|
||||
|
||||
|
||||
extern void __register_frame_info (void *, struct object *);
|
||||
extern void __register_frame (void *);
|
||||
extern void __register_frame_info_table (void *, struct object *);
|
||||
extern void __register_frame_table (void *);
|
||||
extern void *__deregister_frame_info (void *);
|
||||
extern void __deregister_frame (void *);
|
||||
|
||||
|
||||
typedef int sword __attribute__ ((mode (SI)));
|
||||
typedef unsigned int uword __attribute__ ((mode (SI)));
|
||||
typedef unsigned int uaddr __attribute__ ((mode (pointer)));
|
||||
typedef int saddr __attribute__ ((mode (pointer)));
|
||||
typedef unsigned char ubyte;
|
||||
|
||||
/* Terminology:
|
||||
CIE - Common Information Element
|
||||
FDE - Frame Descriptor Element
|
||||
|
||||
There is one per function, and it describes where the function code
|
||||
is located, and what the register lifetimes and stack layout are
|
||||
within the function.
|
||||
|
||||
The data structures are defined in the DWARF specfication, although
|
||||
not in a very readable way (see LITERATURE).
|
||||
|
||||
Every time an exception is thrown, the code needs to locate the FDE
|
||||
for the current function, and starts to look for exception regions
|
||||
from that FDE. This works in a two-level search:
|
||||
a) in a linear search, find the shared image (i.e. DLL) containing
|
||||
the PC
|
||||
b) using the FDE table for that shared object, locate the FDE using
|
||||
binary search (which requires the sorting). */
|
||||
|
||||
/* The first few fields of a CIE. The CIE_id field is 0 for a CIE,
|
||||
to distinguish it from a valid FDE. FDEs are aligned to an addressing
|
||||
unit boundary, but the fields within are unaligned. */
|
||||
struct dwarf_cie
|
||||
{
|
||||
uword length;
|
||||
sword CIE_id;
|
||||
ubyte version;
|
||||
unsigned char augmentation[];
|
||||
} __attribute__ ((packed, aligned (__alignof__ (void *))));
|
||||
|
||||
/* The first few fields of an FDE. */
|
||||
struct dwarf_fde
|
||||
{
|
||||
uword length;
|
||||
sword CIE_delta;
|
||||
void * pc_begin;
|
||||
uaddr pc_range;
|
||||
} __attribute__ ((packed, aligned (__alignof__ (void *))));
|
||||
|
||||
typedef struct dwarf_fde fde;
|
||||
|
||||
/* Locate the CIE for a given FDE. */
|
||||
|
||||
static inline struct dwarf_cie *
|
||||
get_cie (struct dwarf_fde *f)
|
||||
{
|
||||
return (void *)&f->CIE_delta - f->CIE_delta;
|
||||
}
|
||||
|
||||
static inline fde *
|
||||
next_fde (fde *f)
|
||||
{
|
||||
return (fde *)((char *)f + f->length + sizeof (f->length));
|
||||
}
|
||||
|
||||
extern fde * _Unwind_Find_FDE (void *, struct dwarf_eh_bases *);
|
1217
gcc/unwind-dw2.c
Normal file
1217
gcc/unwind-dw2.c
Normal file
File diff suppressed because it is too large
Load Diff
259
gcc/unwind-sjlj.c
Normal file
259
gcc/unwind-sjlj.c
Normal file
@ -0,0 +1,259 @@
|
||||
/* DWARF2 exception handling and frame unwind runtime interface routines.
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
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 "tconfig.h"
|
||||
#include "tsystem.h"
|
||||
#include "unwind.h"
|
||||
#include "gthr.h"
|
||||
|
||||
#if USING_SJLJ_EXCEPTIONS
|
||||
|
||||
#ifdef DONT_USE_BUILTIN_SETJMP
|
||||
#include <setjmp.h>
|
||||
#else
|
||||
#define setjmp __builtin_setjmp
|
||||
#define longjmp __builtin_longjmp
|
||||
#endif
|
||||
|
||||
/* This structure is allocated on the stack of the target function.
|
||||
This must match the definition created in except.c:init_eh. */
|
||||
struct SjLj_Function_Context
|
||||
{
|
||||
/* This is the chain through all registered contexts. It is
|
||||
filled in by _Unwind_SjLj_Register. */
|
||||
struct SjLj_Function_Context *prev;
|
||||
|
||||
/* This is assigned in by the target function before every call
|
||||
to the index of the call site in the lsda. It is assigned by
|
||||
the personality routine to the landing pad index. */
|
||||
int call_site;
|
||||
|
||||
/* This is how data is returned from the personality routine to
|
||||
the target function's handler. */
|
||||
_Unwind_Word data[4];
|
||||
|
||||
/* These are filled in once by the target function before any
|
||||
exceptions are expected to be handled. */
|
||||
_Unwind_Personality_Fn personality;
|
||||
void *lsda;
|
||||
|
||||
#ifdef DONT_USE_BUILTIN_SETJMP
|
||||
/* We don't know what sort of alignment requirements the system
|
||||
jmp_buf has. We over estimated in except.c, and now we have
|
||||
to match that here just in case the system *didn't* have more
|
||||
restrictive requirements. */
|
||||
jmp_buf jbuf __attribute__((aligned));
|
||||
#else
|
||||
void *jbuf[];
|
||||
#endif
|
||||
};
|
||||
|
||||
struct _Unwind_Context
|
||||
{
|
||||
struct SjLj_Function_Context *fc;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
_Unwind_Personality_Fn personality;
|
||||
} _Unwind_FrameState;
|
||||
|
||||
|
||||
/* Manage the chain of registered function contexts. */
|
||||
|
||||
/* Single threaded fallback chain. */
|
||||
static struct SjLj_Function_Context *fc_static;
|
||||
|
||||
#if __GTHREADS
|
||||
static __gthread_key_t fc_key;
|
||||
static int use_fc_key = -1;
|
||||
|
||||
static void
|
||||
fc_key_dtor (void *ptr)
|
||||
{
|
||||
__gthread_key_dtor (fc_key, ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
fc_key_init (void)
|
||||
{
|
||||
use_fc_key = __gthread_key_create (&fc_key, fc_key_dtor) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
fc_key_init_once (void)
|
||||
{
|
||||
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
|
||||
if (__gthread_once (&once, fc_key_init) != 0 || use_fc_key < 0)
|
||||
use_fc_key = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
_Unwind_SjLj_Register (struct SjLj_Function_Context *fc)
|
||||
{
|
||||
#if __GTHREADS
|
||||
if (use_fc_key < 0)
|
||||
fc_key_init_once ();
|
||||
|
||||
if (use_fc_key)
|
||||
{
|
||||
fc->prev = __gthread_getspecific (fc_key);
|
||||
__gthread_setspecific (fc_key, fc);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fc->prev = fc_static;
|
||||
fc_static = fc;
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct SjLj_Function_Context *
|
||||
_Unwind_SjLj_GetContext (void)
|
||||
{
|
||||
#if __GTHREADS
|
||||
if (use_fc_key < 0)
|
||||
fc_key_init_once ();
|
||||
|
||||
if (use_fc_key)
|
||||
return __gthread_getspecific (fc_key);
|
||||
#endif
|
||||
return fc_static;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_Unwind_SjLj_SetContext (struct SjLj_Function_Context *fc)
|
||||
{
|
||||
#if __GTHREADS
|
||||
if (use_fc_key < 0)
|
||||
fc_key_init_once ();
|
||||
|
||||
if (use_fc_key)
|
||||
__gthread_setspecific (fc_key, fc);
|
||||
else
|
||||
#endif
|
||||
fc_static = fc;
|
||||
}
|
||||
|
||||
void
|
||||
_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc)
|
||||
{
|
||||
_Unwind_SjLj_SetContext (fc->prev);
|
||||
}
|
||||
|
||||
|
||||
/* Get/set the return data value at INDEX in CONTEXT. */
|
||||
|
||||
_Unwind_Word
|
||||
_Unwind_GetGR (struct _Unwind_Context *context, int index)
|
||||
{
|
||||
return context->fc->data[index];
|
||||
}
|
||||
|
||||
void
|
||||
_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
|
||||
{
|
||||
context->fc->data[index] = val;
|
||||
}
|
||||
|
||||
/* Get the call-site index as saved in CONTEXT. */
|
||||
|
||||
_Unwind_Ptr
|
||||
_Unwind_GetIP (struct _Unwind_Context *context)
|
||||
{
|
||||
return context->fc->call_site + 1;
|
||||
}
|
||||
|
||||
/* Set the return landing pad index in CONTEXT. */
|
||||
|
||||
void
|
||||
_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
|
||||
{
|
||||
context->fc->call_site = val - 1;
|
||||
}
|
||||
|
||||
void *
|
||||
_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
|
||||
{
|
||||
return context->fc->lsda;
|
||||
}
|
||||
|
||||
_Unwind_Ptr
|
||||
_Unwind_GetRegionStart (struct _Unwind_Context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline _Unwind_Reason_Code
|
||||
uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
|
||||
{
|
||||
if (context->fc == NULL)
|
||||
{
|
||||
fs->personality = NULL;
|
||||
return _URC_END_OF_STACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
fs->personality = context->fc->personality;
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
uw_update_context (struct _Unwind_Context *context,
|
||||
_Unwind_FrameState *fs __attribute__((unused)) )
|
||||
{
|
||||
context->fc = context->fc->prev;
|
||||
}
|
||||
|
||||
static inline void
|
||||
uw_init_context (struct _Unwind_Context *context)
|
||||
{
|
||||
context->fc = _Unwind_SjLj_GetContext ();
|
||||
}
|
||||
|
||||
/* ??? There appear to be bugs in integrate.c wrt __builtin_longjmp and
|
||||
virtual-stack-vars. An inline version of this segfaults on Sparc. */
|
||||
#define uw_install_context(CURRENT, TARGET) \
|
||||
do { \
|
||||
_Unwind_SjLj_SetContext ((TARGET)->fc); \
|
||||
longjmp ((TARGET)->fc->jbuf, 1); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static inline _Unwind_Ptr
|
||||
uw_identify_context (struct _Unwind_Context *context)
|
||||
{
|
||||
return (_Unwind_Ptr) context->fc;
|
||||
}
|
||||
|
||||
|
||||
/* Play games with unwind symbols so that we can have call frame
|
||||
and sjlj symbols in the same shared library. Not that you can
|
||||
use them simultaneously... */
|
||||
#define _Unwind_RaiseException _Unwind_SjLj_RaiseException
|
||||
#define _Unwind_ForcedUnwind _Unwind_SjLj_ForcedUnwind
|
||||
#define _Unwind_Resume _Unwind_SjLj_Resume
|
||||
|
||||
#include "unwind.inc"
|
||||
|
||||
#endif /* USING_SJLJ_EXCEPTIONS */
|
166
gcc/unwind.h
Normal file
166
gcc/unwind.h
Normal file
@ -0,0 +1,166 @@
|
||||
/* Exception handling and frame unwind runtime interface routines.
|
||||
Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
|
||||
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. */
|
||||
|
||||
/* This is derived from the C++ ABI for IA-64. Where we diverge
|
||||
for cross-architecture compatibility are noted with "@@@". */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Level 1: Base ABI */
|
||||
|
||||
/* @@@ The IA-64 ABI uses uint64 throughout. Most places this is
|
||||
inefficient for 32-bit and smaller machines. */
|
||||
typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
|
||||
typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
|
||||
typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
|
||||
|
||||
/* @@@ The IA-64 ABI uses a 64-bit word to identify the producer and
|
||||
consumer of an exception. We'll go along with this for now even on
|
||||
32-bit machines. We'll need to provide some other option for
|
||||
16-bit machines and for machines with > 8 bits per byte. */
|
||||
typedef unsigned _Unwind_Exception_Class __attribute__((__mode__(__DI__)));
|
||||
|
||||
/* The unwind interface uses reason codes in several contexts to
|
||||
identify the reasons for failures or other actions. */
|
||||
typedef enum
|
||||
{
|
||||
_URC_NO_REASON = 0,
|
||||
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||
_URC_FATAL_PHASE2_ERROR = 2,
|
||||
_URC_FATAL_PHASE1_ERROR = 3,
|
||||
_URC_NORMAL_STOP = 4,
|
||||
_URC_END_OF_STACK = 5,
|
||||
_URC_HANDLER_FOUND = 6,
|
||||
_URC_INSTALL_CONTEXT = 7,
|
||||
_URC_CONTINUE_UNWIND = 8
|
||||
} _Unwind_Reason_Code;
|
||||
|
||||
|
||||
/* The unwind interface uses a pointer to an exception header object
|
||||
as its representation of an exception being thrown. In general, the
|
||||
full representation of an exception object is language- and
|
||||
implementation-specific, but it will be prefixed by a header
|
||||
understood by the unwind interface. */
|
||||
|
||||
struct _Unwind_Exception;
|
||||
|
||||
typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code,
|
||||
struct _Unwind_Exception *);
|
||||
|
||||
struct _Unwind_Exception
|
||||
{
|
||||
_Unwind_Exception_Class exception_class;
|
||||
_Unwind_Exception_Cleanup_Fn exception_cleanup;
|
||||
_Unwind_Word private_1;
|
||||
_Unwind_Word private_2;
|
||||
|
||||
/* @@@ The IA-64 ABI says that this structure must be double-word aligned.
|
||||
Taking that literally does not make much sense generically. Instead we
|
||||
provide the maximum alignment required by any type for the machine. */
|
||||
} __attribute__((__aligned__));
|
||||
|
||||
|
||||
/* The ACTIONS argument to the personality routine is a bitwise OR of one
|
||||
or more of the following constants. */
|
||||
typedef int _Unwind_Action;
|
||||
|
||||
#define _UA_SEARCH_PHASE 1
|
||||
#define _UA_CLEANUP_PHASE 2
|
||||
#define _UA_HANDLER_FRAME 4
|
||||
#define _UA_FORCE_UNWIND 8
|
||||
|
||||
/* This is an opaque type used to refer to a system-specific data
|
||||
structure used by the system unwinder. This context is created and
|
||||
destroyed by the system, and passed to the personality routine
|
||||
during unwinding. */
|
||||
struct _Unwind_Context;
|
||||
|
||||
/* Raise an exception, passing along the given exception object. */
|
||||
extern _Unwind_Reason_Code _Unwind_RaiseException (struct _Unwind_Exception *);
|
||||
|
||||
/* Raise an exception for forced unwinding. */
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
|
||||
(int, _Unwind_Action, _Unwind_Exception_Class,
|
||||
struct _Unwind_Exception *, struct _Unwind_Context *, void *);
|
||||
|
||||
extern _Unwind_Reason_Code _Unwind_ForcedUnwind (struct _Unwind_Exception *,
|
||||
_Unwind_Stop_Fn,
|
||||
void *);
|
||||
|
||||
/* Helper to invoke the exception_cleanup routine. */
|
||||
extern void _Unwind_DeleteException (struct _Unwind_Exception *);
|
||||
|
||||
/* Resume propagation of an existing exception. This is used after
|
||||
e.g. executing cleanup code, and not to implement rethrowing. */
|
||||
extern void _Unwind_Resume (struct _Unwind_Exception *);
|
||||
|
||||
/* These functions are used for communicating information about the unwind
|
||||
context (i.e. the unwind descriptors and the user register state) between
|
||||
the unwind library and the personality routine and landing pad. Only
|
||||
selected registers maybe manipulated. */
|
||||
|
||||
extern _Unwind_Word _Unwind_GetGR (struct _Unwind_Context *, int);
|
||||
extern void _Unwind_SetGR (struct _Unwind_Context *, int, _Unwind_Word);
|
||||
|
||||
extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
|
||||
extern void _Unwind_SetIP (struct _Unwind_Context *, _Unwind_Ptr);
|
||||
|
||||
extern void *_Unwind_GetLanguageSpecificData (struct _Unwind_Context *);
|
||||
|
||||
extern _Unwind_Ptr _Unwind_GetRegionStart (struct _Unwind_Context *);
|
||||
|
||||
|
||||
/* The personality routine is the function in the C++ (or other language)
|
||||
runtime library which serves as an interface between the system unwind
|
||||
library and language-specific exception handling semantics. It is
|
||||
specific to the code fragment described by an unwind info block, and
|
||||
it is always referenced via the pointer in the unwind info block, and
|
||||
hence it has no ABI-specified name.
|
||||
|
||||
Note that this implies that two different C++ implementations can
|
||||
use different names, and have different contents in the language
|
||||
specific data area. Moreover, that the language specific data
|
||||
area contains no version info because name of the function invoked
|
||||
provides more effective versioning by detecting at link time the
|
||||
lack of code to handle the different data format. */
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)
|
||||
(int, _Unwind_Action, _Unwind_Exception_Class,
|
||||
struct _Unwind_Exception *, struct _Unwind_Context *);
|
||||
|
||||
/* @@@ The following alternate entry points are for setjmp/longjmp
|
||||
based unwinding. */
|
||||
|
||||
struct SjLj_Function_Context;
|
||||
extern void _Unwind_SjLj_Register (struct SjLj_Function_Context *);
|
||||
extern void _Unwind_SjLj_Unregister (struct SjLj_Function_Context *);
|
||||
|
||||
extern _Unwind_Reason_Code _Unwind_SjLj_RaiseException
|
||||
(struct _Unwind_Exception *);
|
||||
extern _Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind
|
||||
(struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
|
||||
extern void _Unwind_SjLj_Resume (struct _Unwind_Exception *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
232
gcc/unwind.inc
Normal file
232
gcc/unwind.inc
Normal file
@ -0,0 +1,232 @@
|
||||
/* Exception handling and frame unwind runtime interface routines.
|
||||
Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
|
||||
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. */
|
||||
|
||||
/* This is derived from the C++ ABI for IA-64. Where we diverge
|
||||
for cross-architecture compatibility are noted with "@@@".
|
||||
This file is included from unwind-dw2.c or unwind-ia64.c. */
|
||||
|
||||
/* Subroutine of _Unwind_RaiseException also invoked from _Unwind_Resume.
|
||||
|
||||
Unwind the stack calling the personality routine to find both the
|
||||
exception handler and intermediary cleanup code. We'll only locate
|
||||
the first such frame here. Cleanup code will call back into
|
||||
_Unwind_Resume and we'll continue Phase 2 there. */
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
_Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc,
|
||||
struct _Unwind_Context *context)
|
||||
{
|
||||
_Unwind_Reason_Code code;
|
||||
|
||||
while (1)
|
||||
{
|
||||
_Unwind_FrameState fs;
|
||||
int match_handler;
|
||||
|
||||
code = uw_frame_state_for (context, &fs);
|
||||
|
||||
/* Identify when we've reached the designated handler context. */
|
||||
match_handler = (uw_identify_context (context) == exc->private_2
|
||||
? _UA_HANDLER_FRAME : 0);
|
||||
|
||||
if (code != _URC_NO_REASON)
|
||||
/* Some error encountered. Ususally the unwinder doesn't
|
||||
diagnose these and merely crashes. */
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
|
||||
/* Unwind successful. Run the personality routine, if any. */
|
||||
if (fs.personality)
|
||||
{
|
||||
code = (*fs.personality) (1, _UA_CLEANUP_PHASE | match_handler,
|
||||
exc->exception_class, exc, context);
|
||||
if (code == _URC_INSTALL_CONTEXT)
|
||||
break;
|
||||
if (code != _URC_CONTINUE_UNWIND)
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
/* Don't let us unwind past the handler context. */
|
||||
if (match_handler)
|
||||
abort ();
|
||||
|
||||
uw_update_context (context, &fs);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
/* Raise an exception, passing along the given exception object. */
|
||||
|
||||
_Unwind_Reason_Code
|
||||
_Unwind_RaiseException(struct _Unwind_Exception *exc)
|
||||
{
|
||||
struct _Unwind_Context this_context, cur_context;
|
||||
_Unwind_Reason_Code code;
|
||||
|
||||
uw_init_context (&this_context);
|
||||
cur_context = this_context;
|
||||
|
||||
/* Phase 1: Search. Unwind the stack, calling the personality routine
|
||||
with the _UA_SEARCH_PHASE flag set. Do not modify the stack yet. */
|
||||
while (1)
|
||||
{
|
||||
_Unwind_FrameState fs;
|
||||
|
||||
code = uw_frame_state_for (&cur_context, &fs);
|
||||
|
||||
if (code == _URC_END_OF_STACK)
|
||||
/* Hit end of stack with no handler found. */
|
||||
return _URC_END_OF_STACK;
|
||||
|
||||
if (code != _URC_NO_REASON)
|
||||
/* Some error encountered. Ususally the unwinder doesn't
|
||||
diagnose these and merely crashes. */
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
|
||||
/* Unwind successful. Run the personality routine, if any. */
|
||||
if (fs.personality)
|
||||
{
|
||||
code = (*fs.personality) (1, _UA_SEARCH_PHASE, exc->exception_class,
|
||||
exc, &cur_context);
|
||||
if (code == _URC_HANDLER_FOUND)
|
||||
break;
|
||||
else if (code != _URC_CONTINUE_UNWIND)
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
|
||||
uw_update_context (&cur_context, &fs);
|
||||
}
|
||||
|
||||
/* Indicate to _Unwind_Resume and associated subroutines that this
|
||||
is not a forced unwind. Further, note where we found a handler. */
|
||||
exc->private_1 = 0;
|
||||
exc->private_2 = uw_identify_context (&cur_context);
|
||||
|
||||
cur_context = this_context;
|
||||
code = _Unwind_RaiseException_Phase2 (exc, &cur_context);
|
||||
if (code != _URC_INSTALL_CONTEXT)
|
||||
return code;
|
||||
|
||||
uw_install_context (&this_context, &cur_context);
|
||||
}
|
||||
|
||||
|
||||
/* Subroutine of _Unwind_ForcedUnwind also invoked from _Unwind_Resume. */
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
_Unwind_ForcedUnwind_Phase2(struct _Unwind_Exception *exc,
|
||||
struct _Unwind_Context *context)
|
||||
{
|
||||
_Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) exc->private_1;
|
||||
void *stop_argument = (void *) exc->private_2;
|
||||
_Unwind_Reason_Code code, stop_code;
|
||||
|
||||
while (1)
|
||||
{
|
||||
_Unwind_FrameState fs;
|
||||
|
||||
code = uw_frame_state_for (context, &fs);
|
||||
if (code != _URC_NO_REASON && code != _URC_END_OF_STACK)
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
|
||||
/* Unwind successful. */
|
||||
stop_code = (*stop) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE,
|
||||
exc->exception_class, exc, context, stop_argument);
|
||||
if (stop_code != _URC_NO_REASON)
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
|
||||
/* Stop didn't want to do anything. Invoke the personality
|
||||
handler, if applicable, to run cleanups. */
|
||||
if (code == _URC_END_OF_STACK)
|
||||
break;
|
||||
|
||||
if (fs.personality)
|
||||
{
|
||||
code = (*fs.personality) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE,
|
||||
exc->exception_class, exc, context);
|
||||
if (code == _URC_INSTALL_CONTEXT)
|
||||
break;
|
||||
if (code != _URC_CONTINUE_UNWIND)
|
||||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
uw_update_context (context, &fs);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
/* Raise an exception for forced unwinding. */
|
||||
|
||||
_Unwind_Reason_Code
|
||||
_Unwind_ForcedUnwind (struct _Unwind_Exception *exc,
|
||||
_Unwind_Stop_Fn stop, void * stop_argument)
|
||||
{
|
||||
struct _Unwind_Context this_context, cur_context;
|
||||
_Unwind_Reason_Code code;
|
||||
|
||||
uw_init_context (&this_context);
|
||||
cur_context = this_context;
|
||||
|
||||
exc->private_1 = (_Unwind_Ptr) stop;
|
||||
exc->private_2 = (_Unwind_Ptr) stop_argument;
|
||||
|
||||
code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context);
|
||||
if (code != _URC_INSTALL_CONTEXT)
|
||||
return code;
|
||||
|
||||
uw_install_context (&this_context, &cur_context);
|
||||
}
|
||||
|
||||
|
||||
/* Resume propagation of an existing exception. This is used after
|
||||
e.g. executing cleanup code, and not to implement rethrowing. */
|
||||
|
||||
void
|
||||
_Unwind_Resume (struct _Unwind_Exception *exc)
|
||||
{
|
||||
struct _Unwind_Context this_context, cur_context;
|
||||
_Unwind_Reason_Code code;
|
||||
|
||||
uw_init_context (&this_context);
|
||||
cur_context = this_context;
|
||||
|
||||
/* Choose between continuing to process _Unwind_RaiseException
|
||||
or _Unwind_ForcedUnwind. */
|
||||
if (exc->private_1 == 0)
|
||||
code = _Unwind_RaiseException_Phase2 (exc, &cur_context);
|
||||
else
|
||||
code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context);
|
||||
|
||||
if (code != _URC_INSTALL_CONTEXT)
|
||||
abort ();
|
||||
|
||||
uw_install_context (&this_context, &cur_context);
|
||||
}
|
||||
|
||||
/* A convenience function that calls the exception_cleanup field. */
|
||||
|
||||
void
|
||||
_Unwind_DeleteException (struct _Unwind_Exception *exc)
|
||||
{
|
||||
(*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
|
||||
}
|
@ -1,3 +1,29 @@
|
||||
2001-03-28 Richard Henderson <rth@redhat.com>
|
||||
|
||||
IA-64 ABI Exception Handling:
|
||||
* Makefile.am (GCC_UNWIND_INCLUDE): Rename from EH_COMMON_INCLUDE.
|
||||
(AM_CXXFLAGS): -fnon-call-exceptions not -fasynchronous-exceptions.
|
||||
Remove EXCEPTIONSPEC.
|
||||
* configure.host (libgcj_sjlj): Remove.
|
||||
* configure.in (EXCEPTIONSPEC): Remove.
|
||||
(enable-sjlj-exceptions): Detect if not specified.
|
||||
(GCC_UNWIND_INCLUDE): Rename from EH_COMMON_INCLUDE; change
|
||||
what header we're looking for.
|
||||
* libgcj.spec.in (jc1): Remove EXCEPTIONSPEC.
|
||||
* Makefile.in, configure: Regenerate.
|
||||
* exception.cc: Don't declare libgcc2 stuff.
|
||||
(java_eh_info, _Jv_type_matcher, _Jv_exception_info): Remove.
|
||||
(_Jv_eh_alloc, _Jv_eh_free, _Jv_setup_eh_info): Remove.
|
||||
(win32_get_restart_frame): Remove.
|
||||
(struct java_exception_header): New.
|
||||
(__gcj_exception_class): New.
|
||||
(get_exception_header_from_ue): New.
|
||||
(_Jv_Throw): Rewrite for IA-64 ABI unwind routines.
|
||||
(size_of_encoded_value, read_encoded_value): New.
|
||||
(read_uleb128, read_sleb128, parse_lsda_header): New.
|
||||
(get_ttype_entry, __gcj_personality_sj0): New.
|
||||
* gcj/javaprims.h (_Jv_Sjlj_Throw): Remove.
|
||||
|
||||
2001-03-27 Joerg Brunsmann <joerg_brunsmann@yahoo.de>
|
||||
|
||||
* javax/naming/InitialContext.java (init): Fix typo.
|
||||
|
@ -87,18 +87,15 @@ LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(
|
||||
|
||||
JAVAC = $(GCJ_WITH_FLAGS) -C
|
||||
|
||||
EH_COMMON_INCLUDE = @EH_COMMON_INCLUDE@
|
||||
GCC_UNWIND_INCLUDE = @GCC_UNWIND_INCLUDE@
|
||||
|
||||
WARNINGS = -W -Wall
|
||||
## We need _GNU_SOURCE defined for some Linux builds. It doesn't hurt
|
||||
## to always define it.
|
||||
## Note that we need -fasynchronous-exceptions because gcc is
|
||||
## currently broken with respect to exception handling in leaf
|
||||
## functions.
|
||||
AM_CXXFLAGS = -fno-rtti -fvtable-thunks -fasynchronous-exceptions \
|
||||
AM_CXXFLAGS = -fno-rtti -fvtable-thunks -fnon-call-exceptions \
|
||||
## Some systems don't allow `$' in identifiers by default, so we force it.
|
||||
-fdollars-in-identifiers \
|
||||
@LIBGCJ_CXXFLAGS@ @EXCEPTIONSPEC@ @X_CFLAGS@ $(WARNINGS) -D_GNU_SOURCE
|
||||
@LIBGCJ_CXXFLAGS@ @X_CFLAGS@ $(WARNINGS) -D_GNU_SOURCE
|
||||
if USING_GCC
|
||||
AM_CFLAGS = @LIBGCJ_CFLAGS@ $(WARNINGS)
|
||||
else
|
||||
@ -112,7 +109,7 @@ LIBFFIINCS = -I$(top_srcdir)/../libffi/include -I$(MULTIBUILDTOP)../libffi/inclu
|
||||
|
||||
INCLUDES = -I$(top_srcdir) -Iinclude -I$(top_srcdir)/include \
|
||||
$(GCINCS) $(THREADINCS) $(INCLTDL) \
|
||||
$(EH_COMMON_INCLUDE) $(ZINCS) $(LIBFFIINCS)
|
||||
$(GCC_UNWIND_INCLUDE) $(ZINCS) $(LIBFFIINCS)
|
||||
|
||||
|
||||
## ################################################################
|
||||
|
@ -153,12 +153,12 @@ LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(
|
||||
|
||||
JAVAC = $(GCJ_WITH_FLAGS) -C
|
||||
|
||||
EH_COMMON_INCLUDE = @EH_COMMON_INCLUDE@
|
||||
GCC_UNWIND_INCLUDE = @GCC_UNWIND_INCLUDE@
|
||||
|
||||
WARNINGS = -W -Wall
|
||||
AM_CXXFLAGS = -fno-rtti -fvtable-thunks -fasynchronous-exceptions \
|
||||
AM_CXXFLAGS = -fno-rtti -fvtable-thunks -fnon-call-exceptions \
|
||||
-fdollars-in-identifiers \
|
||||
@LIBGCJ_CXXFLAGS@ @EXCEPTIONSPEC@ @X_CFLAGS@ $(WARNINGS) -D_GNU_SOURCE
|
||||
@LIBGCJ_CXXFLAGS@ @X_CFLAGS@ $(WARNINGS) -D_GNU_SOURCE
|
||||
|
||||
@USING_GCC_TRUE@AM_CFLAGS = @USING_GCC_TRUE@@LIBGCJ_CFLAGS@ $(WARNINGS)
|
||||
@USING_GCC_FALSE@AM_CFLAGS = @USING_GCC_FALSE@@LIBGCJ_CFLAGS@
|
||||
@ -170,7 +170,7 @@ LIBFFIINCS = -I$(top_srcdir)/../libffi/include -I$(MULTIBUILDTOP)../libffi/inclu
|
||||
|
||||
INCLUDES = -I$(top_srcdir) -Iinclude -I$(top_srcdir)/include \
|
||||
$(GCINCS) $(THREADINCS) $(INCLTDL) \
|
||||
$(EH_COMMON_INCLUDE) $(ZINCS) $(LIBFFIINCS)
|
||||
$(GCC_UNWIND_INCLUDE) $(ZINCS) $(LIBFFIINCS)
|
||||
|
||||
|
||||
nat_files = $(nat_source_files:.cc=.lo)
|
||||
|
776
libjava/configure
vendored
776
libjava/configure
vendored
File diff suppressed because it is too large
Load Diff
@ -23,7 +23,6 @@ libgcj_flags=
|
||||
libgcj_cflags=
|
||||
libgcj_cxxflags=
|
||||
libgcj_javaflags=
|
||||
libgcj_sjlj=
|
||||
libgcj_interpreter=
|
||||
|
||||
case "${target_optspace}:${host}" in
|
||||
@ -67,18 +66,13 @@ case "${host}" in
|
||||
alpha*-*)
|
||||
libgcj_flags="${libgcj_flags} -mieee"
|
||||
libgcj_interpreter=yes
|
||||
libgcj_sjlj=yes
|
||||
;;
|
||||
sparc-*)
|
||||
;;
|
||||
ia64-*)
|
||||
libgcj_flags="${libgcj_flags} -funwind-tables"
|
||||
libgcj_sjlj=yes
|
||||
libgcj_interpreter=yes
|
||||
;;
|
||||
*)
|
||||
libgcj_sjlj=yes
|
||||
;;
|
||||
esac
|
||||
|
||||
libgcj_cflags="${libgcj_cflags} ${libgcj_flags}"
|
||||
|
@ -88,19 +88,51 @@ if test "$libgcj_interpreter" = yes; then
|
||||
AC_DEFINE(INTERPRETER)
|
||||
fi
|
||||
|
||||
EXCEPTIONSPEC=
|
||||
dnl See if we should use setjmp/longjmp exceptions
|
||||
AC_MSG_CHECKING([for exception model to use])
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_ARG_ENABLE(sjlj-exceptions,
|
||||
[ --enable-sjlj-exceptions use setjmp/longjmp exceptions],
|
||||
if test "$enable_sjlj_exceptions" = yes; then
|
||||
# This can be set in configure.host.
|
||||
libgcj_sjlj=yes
|
||||
fi)
|
||||
|
||||
if test "$libgcj_sjlj" = yes; then
|
||||
EXCEPTIONSPEC="-fsjlj-exceptions"
|
||||
AC_DEFINE(SJLJ_EXCEPTIONS)
|
||||
[ --enable-sjlj-exceptions force use of builtin_setjmp for exceptions],
|
||||
[:],
|
||||
[dnl Botheration. Now we've got to detect the exception model.
|
||||
dnl Link tests against libgcc.a are problematic since -- at least
|
||||
dnl as of this writing -- we've not been given proper -L bits for
|
||||
dnl single-tree newlib and libgloss.
|
||||
dnl
|
||||
dnl This is what AC_TRY_COMPILE would do if it didn't delete the
|
||||
dnl conftest files before we got a change to grep them first.
|
||||
cat > conftest.$ac_ext << EOF
|
||||
[#]line __oline__ "configure"
|
||||
struct S { ~S(); };
|
||||
void bar();
|
||||
void foo()
|
||||
{
|
||||
S s;
|
||||
bar();
|
||||
}
|
||||
EOF
|
||||
old_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS=-S
|
||||
if AC_TRY_EVAL(ac_compile); then
|
||||
if grep _Unwind_SjLj_Resume conftest.s >/dev/null 2>&1 ; then
|
||||
enable_sjlj_exceptions=yes
|
||||
elif grep _Unwind_Resume conftest.s >/dev/null 2>&1 ; then
|
||||
enable_sjlj_exceptions=no
|
||||
fi
|
||||
fi
|
||||
CXXFLAGS="$old_CXXFLAGS"
|
||||
rm -f conftest*])
|
||||
if test x$enable_sjlj_exceptions = xyes; then
|
||||
AC_DEFINE(SJLJ_EXCEPTIONS, 1,
|
||||
[Define if the compiler is configured for setjmp/longjmp exceptions.])
|
||||
ac_exception_model_name=sjlj
|
||||
elif test x$enable_sjlj_exceptions = xno; then
|
||||
ac_exception_model_name="call frame"
|
||||
else
|
||||
AC_MSG_ERROR([unable to detect exception model])
|
||||
fi
|
||||
AC_LANG_RESTORE
|
||||
AC_MSG_RESULT($ac_exception_model_name)
|
||||
|
||||
AC_MSG_CHECKING([for data_start])
|
||||
LIBDATASTARTSPEC=
|
||||
@ -349,16 +381,17 @@ CANADIAN=no
|
||||
NULL_TARGET=no
|
||||
NATIVE=yes
|
||||
|
||||
# Find eh-common.h and support headers. If we're in the tree with
|
||||
# Find unwind.h and support headers. If we're in the tree with
|
||||
# gcc, then look there. Otherwise look in compat-include. If all else
|
||||
# fails, just hope the user has set things up somehow.
|
||||
if test -r $srcdir/../gcc/eh-common.h; then
|
||||
EH_COMMON_INCLUDE='-I$(top_srcdir)/../gcc -I$(top_srcdir)/../include'
|
||||
echo "probing $srcdir/../gcc/unwind.h"
|
||||
if test -r $srcdir/../gcc/unwind.h; then
|
||||
GCC_UNWIND_INCLUDE='-I$(top_srcdir)/../gcc'
|
||||
else
|
||||
if test -d $srcdir/../compat-include; then
|
||||
EH_COMMON_INCLUDE='-I$(top_srcdir)/../compat-include'
|
||||
GCC_UNWIND_INCLUDE='-I$(top_srcdir)/../compat-include'
|
||||
else
|
||||
EH_COMMON_INCLUDE=
|
||||
GCC_UNWIND_INCLUDE=
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -389,7 +422,7 @@ if test -n "${with_cross_host}"; then
|
||||
# directory.
|
||||
if test "$build" != "$with_cross_host"; then
|
||||
CANADIAN=yes
|
||||
EH_COMMON_INCLUDE=
|
||||
GCC_UNWIND_INCLUDE=
|
||||
GCJ="${target_alias}-gcj"
|
||||
else
|
||||
GCJ=
|
||||
@ -623,14 +656,13 @@ AC_SUBST(ZLIBS)
|
||||
AC_SUBST(ZDEPS)
|
||||
AC_SUBST(ZINCS)
|
||||
AC_SUBST(DIVIDESPEC)
|
||||
AC_SUBST(EXCEPTIONSPEC)
|
||||
|
||||
AM_CONDITIONAL(CANADIAN, test "$CANADIAN" = yes)
|
||||
AM_CONDITIONAL(NULL_TARGET, test "$NULL_TARGET" = yes)
|
||||
AM_CONDITIONAL(NATIVE, test "$NATIVE" = yes || test "$NULL_TARGET" = yes)
|
||||
AM_CONDITIONAL(USE_LIBDIR, test -z "$with_cross_host")
|
||||
AM_CONDITIONAL(NEEDS_DATA_START, test "$NEEDS_DATA_START" = yes && test "$NATIVE" = yes)
|
||||
AC_SUBST(EH_COMMON_INCLUDE)
|
||||
AC_SUBST(GCC_UNWIND_INCLUDE)
|
||||
|
||||
# Determine gcj version number.
|
||||
changequote(<<,>>)
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Functions for Exception Support for Java.
|
||||
|
||||
/* Copyright (C) 1998, 1999 Free Software Foundation
|
||||
/* Copyright (C) 1998, 1999, 2001 Free Software Foundation
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
@ -18,182 +18,546 @@ details. */
|
||||
#include <gcj/cni.h>
|
||||
#include <jvm.h>
|
||||
|
||||
// eh-common.h needs gansidecl.h.
|
||||
#include "gansidecl.h"
|
||||
#include "eh-common.h"
|
||||
#include "unwind.h"
|
||||
|
||||
|
||||
// More nastiness: the GC wants to define TRUE and FALSE. We don't
|
||||
// need the Java definitions (themselves a hack), so we undefine them.
|
||||
#undef TRUE
|
||||
#undef FALSE
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <gc_priv.h>
|
||||
#include <gc_mark.h>
|
||||
#include <include/gc_gcj.h>
|
||||
};
|
||||
|
||||
|
||||
struct alignment_test_struct
|
||||
{
|
||||
char space;
|
||||
char end[0] __attribute__((aligned));
|
||||
};
|
||||
|
||||
struct java_exception_header
|
||||
{
|
||||
/* Cache handler details between Phase 1 and Phase 2. */
|
||||
_Unwind_Ptr landingPad;
|
||||
int handlerSwitchValue;
|
||||
|
||||
/* The object being thrown. Compiled code expects this to be immediately
|
||||
before the generic exception header. Which is complicated by the fact
|
||||
that _Unwind_Exception is ((aligned)). */
|
||||
|
||||
char pad[sizeof(jthrowable) < sizeof(alignment_test_struct)
|
||||
? sizeof(alignment_test_struct) - sizeof(jthrowable) : 0]
|
||||
__attribute__((aligned));
|
||||
|
||||
typedef struct {
|
||||
__eh_info eh_info;
|
||||
jthrowable value;
|
||||
} java_eh_info;
|
||||
|
||||
/* The generic exception header. */
|
||||
_Unwind_Exception unwindHeader;
|
||||
};
|
||||
|
||||
// This is the exception class we report -- "GNUCJAVA".
|
||||
const _Unwind_Exception_Class __gcj_exception_class
|
||||
= ((((((((_Unwind_Exception_Class) 'G'
|
||||
<< 8 | (_Unwind_Exception_Class) 'N')
|
||||
<< 8 | (_Unwind_Exception_Class) 'U')
|
||||
<< 8 | (_Unwind_Exception_Class) 'C')
|
||||
<< 8 | (_Unwind_Exception_Class) 'J')
|
||||
<< 8 | (_Unwind_Exception_Class) 'A')
|
||||
<< 8 | (_Unwind_Exception_Class) 'V')
|
||||
<< 8 | (_Unwind_Exception_Class) 'A');
|
||||
|
||||
|
||||
/* Language-specific EH info pointer, throw routine, and language/version
|
||||
info routines. All defined in libgcc2. */
|
||||
|
||||
extern "C" java_eh_info **__get_eh_info ();
|
||||
extern "C" void __throw () __attribute__ ((__noreturn__));
|
||||
extern "C" void __sjthrow () __attribute__ ((__noreturn__));
|
||||
extern "C" short __get_eh_table_version (void *table);
|
||||
extern "C" short __get_eh_table_language (void *table);
|
||||
extern "C" void *__get_eh_context ();
|
||||
|
||||
extern "C" void *
|
||||
_Jv_type_matcher (java_eh_info *info, void* match_info,
|
||||
void *exception_table)
|
||||
{
|
||||
#ifndef SJLJ_EXCEPTIONS
|
||||
/* No exception table implies the old style mechanism, so don't check. */
|
||||
if (exception_table != NULL
|
||||
&& __get_eh_table_language (exception_table) != EH_LANG_Java)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
/* we don't worry about version info yet, there is only one version! */
|
||||
|
||||
if (match_info != NULL)
|
||||
{
|
||||
// The match_info is either a (java::lang::Class*) or
|
||||
// match_info is one more than a (Utf8Const*).
|
||||
if (sizeof(void*) != sizeof(size_t))
|
||||
abort();
|
||||
size_t mi = (size_t) match_info;
|
||||
if ((mi & 1) != 0)
|
||||
match_info = _Jv_FindClass ((Utf8Const*) (mi - 1), NULL);
|
||||
if (! _Jv_IsInstanceOf (info->value, (jclass) match_info))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return info->value;
|
||||
}
|
||||
|
||||
/* Compiler hook to return a pointer to java exception object. The value
|
||||
is cleared, so if the exception needs to be rethrown, it should be set
|
||||
again */
|
||||
|
||||
extern "C" void *
|
||||
_Jv_exception_info (void)
|
||||
{
|
||||
java_eh_info *info = *(__get_eh_info ());
|
||||
void *ptr;
|
||||
|
||||
if (info == NULL)
|
||||
abort ();
|
||||
|
||||
ptr = info->value;
|
||||
|
||||
/* clear the value so another throw is an error */
|
||||
info->value = NULL;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Allocate an exception info structure for java. Called the first time
|
||||
an exception is thrown. */
|
||||
|
||||
extern "C" void
|
||||
_Jv_eh_alloc ()
|
||||
{
|
||||
/* FIXME: we should use _Jv_AllocBytes here. However, libgcc2
|
||||
apparently can sometimes free() this value itself. */
|
||||
java_eh_info *p = (java_eh_info *) malloc (sizeof (java_eh_info));
|
||||
if (p == 0)
|
||||
abort ();
|
||||
|
||||
p->value = 0;
|
||||
java_eh_info ** info_ptr = __get_eh_info ();
|
||||
|
||||
/* There should NOT be an exception info pointer already. */
|
||||
if (*info_ptr != NULL)
|
||||
abort ();
|
||||
|
||||
*info_ptr = p;
|
||||
}
|
||||
|
||||
/* Deallocate the current exception info structure. Called at shutdown time. */
|
||||
|
||||
extern "C" void
|
||||
_Jv_eh_free ()
|
||||
{
|
||||
java_eh_info ** info_ptr = __get_eh_info ();
|
||||
if (*info_ptr == NULL)
|
||||
abort ();
|
||||
|
||||
/* FIXME: ideally we should just let the GC handle this. */
|
||||
free (*info_ptr);
|
||||
*info_ptr = NULL;
|
||||
}
|
||||
|
||||
/* Initialize an __eh_info structure with this libraries matching info. */
|
||||
|
||||
extern "C" void
|
||||
_Jv_setup_eh_info (__eh_info *)
|
||||
static inline java_exception_header *
|
||||
get_exception_header_from_ue (_Unwind_Exception *exc)
|
||||
{
|
||||
return reinterpret_cast<java_exception_header *>(exc + 1) - 1;
|
||||
}
|
||||
|
||||
/* Perform a throw, Java style. Throw will unwind through this call,
|
||||
so there better not be any handlers or exception thrown here. */
|
||||
|
||||
#ifdef SJLJ_EXCEPTIONS
|
||||
#define _Jv_Throw _Jv_Sjlj_Throw
|
||||
#endif
|
||||
|
||||
extern "C" void
|
||||
_Jv_Throw (jthrowable value)
|
||||
{
|
||||
/* FIXME: Use the proper API to the collector. */
|
||||
java_exception_header *xh
|
||||
= static_cast<java_exception_header *>(GC_malloc (sizeof (*xh)));
|
||||
|
||||
if (value == NULL)
|
||||
value = new java::lang::NullPointerException;
|
||||
java_eh_info *ehinfo = *(__get_eh_info ());
|
||||
if (ehinfo == NULL)
|
||||
{
|
||||
_Jv_eh_alloc ();
|
||||
ehinfo = *(__get_eh_info ());
|
||||
}
|
||||
ehinfo->eh_info.match_function = (__eh_matcher) _Jv_type_matcher;
|
||||
ehinfo->eh_info.language = EH_LANG_Java;
|
||||
ehinfo->eh_info.version = 1;
|
||||
ehinfo->value = value;
|
||||
value = new java::lang::NullPointerException ();
|
||||
xh->value = value;
|
||||
|
||||
/* We're happy with setjmp/longjmp exceptions or region-based
|
||||
exception handlers: entry points are provided here for both. */
|
||||
xh->unwindHeader.exception_class = __gcj_exception_class;
|
||||
xh->unwindHeader.exception_cleanup = NULL;
|
||||
|
||||
/* We're happy with setjmp/longjmp exceptions or region-based
|
||||
exception handlers: entry points are provided here for both. */
|
||||
_Unwind_Reason_Code code;
|
||||
#ifdef SJLJ_EXCEPTIONS
|
||||
__sjthrow ();
|
||||
code = _Unwind_SjLj_RaiseException (&xh->unwindHeader);
|
||||
#else
|
||||
__throw ();
|
||||
code = _Unwind_RaiseException (&xh->unwindHeader);
|
||||
#endif
|
||||
|
||||
/* FIXME: If code == _URC_END_OF_STACK, then we reached top of
|
||||
stack without finding a handler for the exception. I seem to
|
||||
recall that Java has specific rules to handle this.
|
||||
|
||||
If code is something else, we encountered some sort of heinous
|
||||
lossage, from which we could not recover. As is the way of such
|
||||
things we'll almost certainly have crashed before now, rather
|
||||
than actually being able to diagnose the problem. */
|
||||
abort ();
|
||||
}
|
||||
|
||||
#ifdef USE_WIN32_SIGNALLING
|
||||
|
||||
// ??? These ought to go somewhere else dwarf2 or dwarf2eh related.
|
||||
|
||||
// This is a mangled version of _Jv_Throw and __sjthrow except
|
||||
// rather than calling longjmp, it returns a pointer to the jmp buffer
|
||||
// Pointer encodings.
|
||||
#define DW_EH_PE_absptr 0x00
|
||||
#define DW_EH_PE_omit 0xff
|
||||
|
||||
extern "C" int *
|
||||
win32_get_restart_frame (void *value)
|
||||
#define DW_EH_PE_uleb128 0x01
|
||||
#define DW_EH_PE_udata2 0x02
|
||||
#define DW_EH_PE_udata4 0x03
|
||||
#define DW_EH_PE_udata8 0x04
|
||||
#define DW_EH_PE_sleb128 0x09
|
||||
#define DW_EH_PE_sdata2 0x0A
|
||||
#define DW_EH_PE_sdata4 0x0B
|
||||
#define DW_EH_PE_sdata8 0x0C
|
||||
#define DW_EH_PE_signed 0x08
|
||||
|
||||
#define DW_EH_PE_pcrel 0x10
|
||||
#define DW_EH_PE_textrel 0x20
|
||||
#define DW_EH_PE_datarel 0x30
|
||||
#define DW_EH_PE_funcrel 0x40
|
||||
|
||||
static unsigned int
|
||||
size_of_encoded_value (unsigned char encoding)
|
||||
{
|
||||
struct eh_context *eh = (struct eh_context *)__get_eh_context ();
|
||||
void ***dhc = &eh->dynamic_handler_chain;
|
||||
|
||||
java_eh_info *ehinfo = *(__get_eh_info ());
|
||||
if (ehinfo == NULL)
|
||||
switch (encoding & 0x07)
|
||||
{
|
||||
_Jv_eh_alloc ();
|
||||
ehinfo = *(__get_eh_info ());
|
||||
case DW_EH_PE_absptr:
|
||||
return sizeof (void *);
|
||||
case DW_EH_PE_udata2:
|
||||
return 2;
|
||||
case DW_EH_PE_udata4:
|
||||
return 4;
|
||||
case DW_EH_PE_udata8:
|
||||
return 8;
|
||||
}
|
||||
ehinfo->eh_info.match_function = (__eh_matcher) _Jv_type_matcher;
|
||||
ehinfo->eh_info.language = EH_LANG_Java;
|
||||
ehinfo->eh_info.version = 1;
|
||||
ehinfo->value = value;
|
||||
|
||||
// FIXME: Run clean ups?
|
||||
|
||||
int *jmpbuf = (int*)&(*dhc)[2];
|
||||
|
||||
*dhc = (void**)(*dhc)[0];
|
||||
|
||||
return jmpbuf;
|
||||
abort ();
|
||||
}
|
||||
|
||||
#endif /* USE_WIN32_SIGNALLING */
|
||||
static const unsigned char *
|
||||
read_encoded_value (_Unwind_Context *context, unsigned char encoding,
|
||||
const unsigned char *p, _Unwind_Ptr *val)
|
||||
{
|
||||
union unaligned
|
||||
{
|
||||
void *ptr;
|
||||
unsigned u2 __attribute__ ((mode (HI)));
|
||||
unsigned u4 __attribute__ ((mode (SI)));
|
||||
unsigned u8 __attribute__ ((mode (DI)));
|
||||
signed s2 __attribute__ ((mode (HI)));
|
||||
signed s4 __attribute__ ((mode (SI)));
|
||||
signed s8 __attribute__ ((mode (DI)));
|
||||
} __attribute__((__packed__));
|
||||
|
||||
union unaligned *u = (union unaligned *) p;
|
||||
_Unwind_Ptr result;
|
||||
|
||||
switch (encoding & 0x0f)
|
||||
{
|
||||
case DW_EH_PE_absptr:
|
||||
result = (_Unwind_Ptr) u->ptr;
|
||||
p += sizeof (void *);
|
||||
break;
|
||||
|
||||
case DW_EH_PE_uleb128:
|
||||
{
|
||||
unsigned int shift = 0;
|
||||
unsigned char byte;
|
||||
|
||||
result = 0;
|
||||
do
|
||||
{
|
||||
byte = *p++;
|
||||
result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
while (byte & 0x80);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_EH_PE_sleb128:
|
||||
{
|
||||
unsigned int shift = 0;
|
||||
unsigned char byte;
|
||||
|
||||
result = 0;
|
||||
do
|
||||
{
|
||||
byte = *p++;
|
||||
result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
while (byte & 0x80);
|
||||
|
||||
if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
|
||||
result |= -(1L << shift);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_EH_PE_udata2:
|
||||
result = u->u2;
|
||||
p += 2;
|
||||
break;
|
||||
case DW_EH_PE_udata4:
|
||||
result = u->u4;
|
||||
p += 4;
|
||||
break;
|
||||
case DW_EH_PE_udata8:
|
||||
result = u->u8;
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_sdata2:
|
||||
result = u->s2;
|
||||
p += 2;
|
||||
break;
|
||||
case DW_EH_PE_sdata4:
|
||||
result = u->s4;
|
||||
p += 4;
|
||||
break;
|
||||
case DW_EH_PE_sdata8:
|
||||
result = u->s8;
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (result != 0)
|
||||
switch (encoding & 0xf0)
|
||||
{
|
||||
case DW_EH_PE_absptr:
|
||||
break;
|
||||
|
||||
case DW_EH_PE_pcrel:
|
||||
// Define as relative to the beginning of the pointer.
|
||||
result += (_Unwind_Ptr) u;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_textrel:
|
||||
case DW_EH_PE_datarel:
|
||||
// FIXME.
|
||||
abort ();
|
||||
|
||||
case DW_EH_PE_funcrel:
|
||||
result += _Unwind_GetRegionStart (context);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
*val = result;
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline const unsigned char *
|
||||
read_uleb128 (const unsigned char *p, _Unwind_Ptr *val)
|
||||
{
|
||||
return read_encoded_value (0, DW_EH_PE_uleb128, p, val);
|
||||
}
|
||||
|
||||
static inline const unsigned char *
|
||||
read_sleb128 (const unsigned char *p, _Unwind_Ptr *val)
|
||||
{
|
||||
return read_encoded_value (0, DW_EH_PE_sleb128, p, val);
|
||||
}
|
||||
|
||||
|
||||
struct lsda_header_info
|
||||
{
|
||||
_Unwind_Ptr Start;
|
||||
_Unwind_Ptr LPStart;
|
||||
const unsigned char *TType;
|
||||
const unsigned char *action_table;
|
||||
unsigned char ttype_encoding;
|
||||
unsigned char call_site_encoding;
|
||||
};
|
||||
|
||||
static const unsigned char *
|
||||
parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
|
||||
lsda_header_info *info)
|
||||
{
|
||||
_Unwind_Ptr tmp;
|
||||
unsigned char lpstart_encoding;
|
||||
|
||||
info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
|
||||
|
||||
// Find @LPStart, the base to which landing pad offsets are relative.
|
||||
lpstart_encoding = *p++;
|
||||
if (lpstart_encoding != DW_EH_PE_omit)
|
||||
p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
|
||||
else
|
||||
info->LPStart = info->Start;
|
||||
|
||||
// Find @TType, the base of the handler and exception spec type data.
|
||||
info->ttype_encoding = *p++;
|
||||
if (info->ttype_encoding != DW_EH_PE_omit)
|
||||
{
|
||||
p = read_uleb128 (p, &tmp);
|
||||
info->TType = p + tmp;
|
||||
}
|
||||
else
|
||||
info->TType = 0;
|
||||
|
||||
// The encoding and length of the call-site table; the action table
|
||||
// immediately follows.
|
||||
info->call_site_encoding = *p++;
|
||||
p = read_uleb128 (p, &tmp);
|
||||
info->action_table = p + tmp;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static jclass
|
||||
get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
|
||||
{
|
||||
_Unwind_Ptr ptr;
|
||||
|
||||
i *= size_of_encoded_value (info->ttype_encoding);
|
||||
read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
|
||||
|
||||
return reinterpret_cast<jclass>(ptr);
|
||||
}
|
||||
|
||||
|
||||
// Using a different personality function name causes link failures
|
||||
// when trying to mix code using different exception handling models.
|
||||
#ifdef SJLJ_EXCEPTIONS
|
||||
#define PERSONALITY_FUNCTION __gcj_personality_sj0
|
||||
#define __builtin_eh_return_data_regno(x) x
|
||||
#else
|
||||
#define PERSONALITY_FUNCTION __gcj_personality_v0
|
||||
#endif
|
||||
|
||||
extern "C" _Unwind_Reason_Code
|
||||
PERSONALITY_FUNCTION (int version,
|
||||
_Unwind_Action actions,
|
||||
_Unwind_Exception_Class exception_class,
|
||||
struct _Unwind_Exception *ue_header,
|
||||
struct _Unwind_Context *context)
|
||||
{
|
||||
java_exception_header *xh = get_exception_header_from_ue (ue_header);
|
||||
|
||||
lsda_header_info info;
|
||||
const unsigned char *language_specific_data;
|
||||
const unsigned char *action_record;
|
||||
const unsigned char *p;
|
||||
_Unwind_Ptr landing_pad, ip;
|
||||
int handler_switch_value;
|
||||
bool saw_cleanup;
|
||||
bool saw_handler;
|
||||
|
||||
|
||||
// Interface version check.
|
||||
if (version != 1)
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
|
||||
// Shortcut for phase 2 found handler for domestic exception.
|
||||
if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
|
||||
&& exception_class == __gcj_exception_class)
|
||||
{
|
||||
handler_switch_value = xh->handlerSwitchValue;
|
||||
landing_pad = xh->landingPad;
|
||||
goto install_context;
|
||||
}
|
||||
|
||||
// FIXME: In Phase 1, record _Unwind_GetIP in xh->obj as a part of
|
||||
// the stack trace for this exception. This will only collect Java
|
||||
// frames, but perhaps that is acceptable.
|
||||
// FIXME2: _Unwind_GetIP is nonsensical for SJLJ, being a call-site
|
||||
// index instead of a PC value. We could perhaps arrange for
|
||||
// _Unwind_GetRegionStart to return context->fc->jbuf[1], which
|
||||
// is the address of the handler label for __builtin_longjmp, but
|
||||
// there is no solution for DONT_USE_BUILTIN_SETJMP.
|
||||
|
||||
language_specific_data = (const unsigned char *)
|
||||
_Unwind_GetLanguageSpecificData (context);
|
||||
|
||||
// If no LSDA, then there are no handlers or cleanups.
|
||||
if (! language_specific_data)
|
||||
return _URC_CONTINUE_UNWIND;
|
||||
|
||||
// Parse the LSDA header.
|
||||
p = parse_lsda_header (context, language_specific_data, &info);
|
||||
ip = _Unwind_GetIP (context) - 1;
|
||||
landing_pad = 0;
|
||||
action_record = 0;
|
||||
handler_switch_value = 0;
|
||||
|
||||
#ifdef SJLJ_EXCEPTIONS
|
||||
// The given "IP" is an index into the call-site table, with two
|
||||
// exceptions -- -1 means no-action, and 0 means terminate. But
|
||||
// since we're using uleb128 values, we've not got random access
|
||||
// to the array.
|
||||
if ((int) ip <= 0)
|
||||
return _URC_CONTINUE_UNWIND;
|
||||
else
|
||||
{
|
||||
_Unwind_Ptr cs_lp, cs_action;
|
||||
do
|
||||
{
|
||||
p = read_uleb128 (p, &cs_lp);
|
||||
p = read_uleb128 (p, &cs_action);
|
||||
}
|
||||
while (--ip);
|
||||
|
||||
// Can never have null landing pad for sjlj -- that would have
|
||||
// been indicated by a -1 call site index.
|
||||
landing_pad = cs_lp + 1;
|
||||
if (cs_action)
|
||||
action_record = info.action_table + cs_action - 1;
|
||||
goto found_something;
|
||||
}
|
||||
#else
|
||||
// Search the call-site table for the action associated with this IP.
|
||||
while (p < info.action_table)
|
||||
{
|
||||
_Unwind_Ptr cs_start, cs_len, cs_lp, cs_action;
|
||||
|
||||
// Note that all call-site encodings are "absolute" displacements.
|
||||
p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
|
||||
p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
|
||||
p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
|
||||
p = read_uleb128 (p, &cs_action);
|
||||
|
||||
// The table is sorted, so if we've passed the ip, stop.
|
||||
if (ip < info.Start + cs_start)
|
||||
p = info.action_table;
|
||||
else if (ip < info.Start + cs_start + cs_len)
|
||||
{
|
||||
if (cs_lp)
|
||||
landing_pad = info.LPStart + cs_lp;
|
||||
if (cs_action)
|
||||
action_record = info.action_table + cs_action - 1;
|
||||
goto found_something;
|
||||
}
|
||||
}
|
||||
#endif // SJLJ_EXCEPTIONS
|
||||
|
||||
// If ip is not present in the table, C++ would call terminate.
|
||||
// ??? It is perhaps better to tweek the LSDA so that no-action
|
||||
// is mapped to no-entry for Java.
|
||||
return _URC_CONTINUE_UNWIND;
|
||||
|
||||
found_something:
|
||||
saw_cleanup = false;
|
||||
saw_handler = false;
|
||||
|
||||
if (landing_pad == 0)
|
||||
{
|
||||
// If ip is present, and has a null landing pad, there are
|
||||
// no cleanups or handlers to be run.
|
||||
}
|
||||
else if (action_record == 0)
|
||||
{
|
||||
// If ip is present, has a non-null landing pad, and a null
|
||||
// action table offset, then there are only cleanups present.
|
||||
// Cleanups use a zero switch value, as set above.
|
||||
saw_cleanup = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise we have a catch handler.
|
||||
signed long ar_filter, ar_disp;
|
||||
|
||||
while (1)
|
||||
{
|
||||
_Unwind_Ptr tmp;
|
||||
|
||||
p = action_record;
|
||||
p = read_sleb128 (p, &tmp); ar_filter = tmp;
|
||||
read_sleb128 (p, &tmp); ar_disp = tmp;
|
||||
|
||||
if (ar_filter == 0)
|
||||
{
|
||||
// Zero filter values are cleanups.
|
||||
saw_cleanup = true;
|
||||
}
|
||||
|
||||
// During forced unwinding, we only run cleanups. With a
|
||||
// foreign exception class, we have no class info to match.
|
||||
else if ((actions & _UA_FORCE_UNWIND)
|
||||
|| exception_class != __gcj_exception_class)
|
||||
;
|
||||
|
||||
else if (ar_filter > 0)
|
||||
{
|
||||
// Positive filter values are handlers.
|
||||
|
||||
jclass catch_type = get_ttype_entry (context, &info, ar_filter);
|
||||
|
||||
// The catch_type is either a (java::lang::Class*) or
|
||||
// is one more than a (Utf8Const*).
|
||||
if ((size_t)catch_type & 1)
|
||||
catch_type = _Jv_FindClass ((Utf8Const*)catch_type - 1, NULL);
|
||||
|
||||
if (_Jv_IsInstanceOf (xh->value, catch_type))
|
||||
{
|
||||
handler_switch_value = ar_filter;
|
||||
saw_handler = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Negative filter values are exception specifications,
|
||||
// which Java does not use.
|
||||
// ??? Perhaps better to make them an index into a table
|
||||
// of null-terminated strings instead of playing games
|
||||
// with Utf8Const+1 as above.
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (ar_disp == 0)
|
||||
break;
|
||||
action_record = p + ar_disp;
|
||||
}
|
||||
}
|
||||
|
||||
if (! saw_handler && ! saw_cleanup)
|
||||
return _URC_CONTINUE_UNWIND;
|
||||
|
||||
if (actions & _UA_SEARCH_PHASE)
|
||||
{
|
||||
if (! saw_handler)
|
||||
return _URC_CONTINUE_UNWIND;
|
||||
|
||||
// For domestic exceptions, we cache data from phase 1 for phase 2.
|
||||
if (exception_class == __gcj_exception_class)
|
||||
{
|
||||
xh->handlerSwitchValue = handler_switch_value;
|
||||
xh->landingPad = landing_pad;
|
||||
}
|
||||
return _URC_HANDLER_FOUND;
|
||||
}
|
||||
|
||||
install_context:
|
||||
_Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
|
||||
(_Unwind_Ptr) &xh->unwindHeader);
|
||||
_Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
|
||||
handler_switch_value);
|
||||
_Unwind_SetIP (context, landing_pad);
|
||||
return _URC_INSTALL_CONTEXT;
|
||||
}
|
||||
|
@ -369,7 +369,6 @@ extern "C" jsize _Jv_GetStringUTFLength (jstring);
|
||||
extern "C" jsize _Jv_GetStringUTFRegion (jstring, jsize, jsize, char *);
|
||||
|
||||
extern "C" void _Jv_Throw (jthrowable) __attribute__ ((__noreturn__));
|
||||
extern "C" void _Jv_Sjlj_Throw (jthrowable) __attribute__ ((__noreturn__));
|
||||
extern "C" void* _Jv_Malloc (jsize) __attribute__((__malloc__));
|
||||
extern "C" void* _Jv_Realloc (void *, jsize);
|
||||
extern "C" void _Jv_Free (void*);
|
||||
|
@ -6,7 +6,7 @@
|
||||
%rename lib liborig
|
||||
*lib: -lgcj -lm @GCSPEC@ @THREADSPEC@ @ZLIBSPEC@ @SYSTEMSPEC@ %(libgcc) %(liborig)
|
||||
|
||||
*jc1: @DIVIDESPEC@ @EXCEPTIONSPEC@ @JC1GCSPEC@ -fasynchronous-exceptions
|
||||
*jc1: @DIVIDESPEC@ @JC1GCSPEC@
|
||||
|
||||
#
|
||||
# On some systems we force in a data_start symbol so that the GC will work
|
||||
|
@ -1,3 +1,23 @@
|
||||
2001-03-28 Richard Henderson <rth@redhat.com>
|
||||
|
||||
IA-64 ABI Exception Handling:
|
||||
* acinclude.m4 (GLIBCPP_ENABLE_SJLJ_EXCEPTIONS): New.
|
||||
* configure.in: Use it.
|
||||
* Makefile.in, aclocal.m4, config.h.in, configure: Regenerate.
|
||||
* libsupc++/Makefile.am (sources): Update files list.
|
||||
* libsupc++/Makefile.in: Regenerate.
|
||||
* libsupc++/eh_alloc.cc, libsupc++/eh_aux_runtime.cc: New files.
|
||||
* libsupc++/eh_catch.cc, libsupc++/eh_exception.cc: New files.
|
||||
* libsupc++/eh_globals.cc, libsupc++/eh_personality.cc: New files.
|
||||
* libsupc++/eh_terminate.cc, libsupc++/eh_throw.cc: New files.
|
||||
* libsupc++/exception_support.cc: Remove.
|
||||
* libsupc++/exception_support.h: Remove.
|
||||
* libsupc++/pure.cc: Use std::terminate.
|
||||
* libsupc++/tinfo2.cc (__throw_type_match_rtti_2): Remove.
|
||||
(__is_pointer): Remove.
|
||||
* libsupc++/unwind-cxx.h: New file.
|
||||
* libsupc++/vec.cc (uncatch_exception): Update for new abi.
|
||||
|
||||
2001-03-27 Alexandre Oliva <aoliva@redhat.com>
|
||||
|
||||
* libsupc++/Makefile.am (CXXLINK): Use CXX again, and choose
|
||||
|
@ -134,48 +134,7 @@ MULTICLEAN = true
|
||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||
# values defined in terms of make variables, as is the case for CC and
|
||||
# friends when we are called from the top level Makefile.
|
||||
AM_MAKEFLAGS = \
|
||||
"AR_FLAGS=$(AR_FLAGS)" \
|
||||
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||
"CC_FOR_TARGET=$(CC_FOR_TARGET)" \
|
||||
"CFLAGS=$(CFLAGS)" \
|
||||
"CXXFLAGS=$(CXXFLAGS)" \
|
||||
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||
"INSTALL=$(INSTALL)" \
|
||||
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||
"LDFLAGS=$(LDFLAGS)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||
"MAKE=$(MAKE)" \
|
||||
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||
"SHELL=$(SHELL)" \
|
||||
"EXPECT=$(EXPECT)" \
|
||||
"RUNTEST=$(RUNTEST)" \
|
||||
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||
"exec_prefix=$(exec_prefix)" \
|
||||
"infodir=$(infodir)" \
|
||||
"libdir=$(libdir)" \
|
||||
"includedir=$(includedir)" \
|
||||
"prefix=$(prefix)" \
|
||||
"tooldir=$(tooldir)" \
|
||||
"AR=$(AR)" \
|
||||
"AS=$(AS)" \
|
||||
"CC=$(CC)" \
|
||||
"CXX=$(CXX)" \
|
||||
"LD=$(LD)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"RANLIB=$(RANLIB)" \
|
||||
"NM=$(NM)" \
|
||||
"NM_FOR_BUILD=$(NM_FOR_BUILD)" \
|
||||
"NM_FOR_TARGET=$(NM_FOR_TARGET)" \
|
||||
"DESTDIR=$(DESTDIR)" \
|
||||
"WERROR=$(WERROR)"
|
||||
AM_MAKEFLAGS = "AR_FLAGS=$(AR_FLAGS)" "CC_FOR_BUILD=$(CC_FOR_BUILD)" "CC_FOR_TARGET=$(CC_FOR_TARGET)" "CFLAGS=$(CFLAGS)" "CXXFLAGS=$(CXXFLAGS)" "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" "INSTALL=$(INSTALL)" "INSTALL_DATA=$(INSTALL_DATA)" "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" "LDFLAGS=$(LDFLAGS)" "LIBCFLAGS=$(LIBCFLAGS)" "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" "MAKE=$(MAKE)" "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" "PICFLAG=$(PICFLAG)" "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" "SHELL=$(SHELL)" "EXPECT=$(EXPECT)" "RUNTEST=$(RUNTEST)" "RUNTESTFLAGS=$(RUNTESTFLAGS)" "exec_prefix=$(exec_prefix)" "infodir=$(infodir)" "libdir=$(libdir)" "includedir=$(includedir)" "prefix=$(prefix)" "tooldir=$(tooldir)" "AR=$(AR)" "AS=$(AS)" "CC=$(CC)" "CXX=$(CXX)" "LD=$(LD)" "LIBCFLAGS=$(LIBCFLAGS)" "PICFLAG=$(PICFLAG)" "RANLIB=$(RANLIB)" "NM=$(NM)" "NM_FOR_BUILD=$(NM_FOR_BUILD)" "NM_FOR_TARGET=$(NM_FOR_TARGET)" "DESTDIR=$(DESTDIR)" "WERROR=$(WERROR)"
|
||||
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
CONFIG_HEADER = config.h
|
||||
@ -353,7 +312,7 @@ distdir: $(DISTFILES)
|
||||
@for file in $(DISTFILES); do \
|
||||
if test -f $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
cp -pr $$d/$$file $(distdir)/$$file; \
|
||||
cp -pr $$/$$file $(distdir)/$$file; \
|
||||
else \
|
||||
test -f $(distdir)/$$file \
|
||||
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|
||||
|
@ -1257,6 +1257,66 @@ AC_DEFUN(GLIBCPP_ENABLE_THREADS, [
|
||||
])
|
||||
|
||||
|
||||
dnl
|
||||
dnl Check for exception handling support. If an explicit enable/disable
|
||||
dnl sjlj exceptions is given, we don't have to detect. Otherwise the
|
||||
dnl target may or may not support call frame exceptions.
|
||||
dnl
|
||||
dnl GLIBCPP_ENABLE_SJLJ_EXCEPTIONS
|
||||
dnl --enable-sjlj-exceptions forces the use of builtin setjmp.
|
||||
dnl --disable-sjlj-exceptions forces the use of call frame unwinding.
|
||||
dnl
|
||||
dnl Define _GLIBCPP_SJLJ_EXCEPTIONS if the compiler is configured for it.
|
||||
dnl
|
||||
AC_DEFUN(GLIBCPP_ENABLE_SJLJ_EXCEPTIONS, [
|
||||
AC_MSG_CHECKING([for exception model to use])
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_ARG_ENABLE(sjlj-exceptions,
|
||||
[ --enable-sjlj-exceptions force use of builtin_setjmp for exceptions],
|
||||
[:],
|
||||
[dnl Botheration. Now we've got to detect the exception model.
|
||||
dnl Link tests against libgcc.a are problematic since -- at least
|
||||
dnl as of this writing -- we've not been given proper -L bits for
|
||||
dnl single-tree newlib and libgloss.
|
||||
dnl
|
||||
dnl This is what AC_TRY_COMPILE would do if it didn't delete the
|
||||
dnl conftest files before we got a change to grep them first.
|
||||
cat > conftest.$ac_ext << EOF
|
||||
[#]line __oline__ "configure"
|
||||
struct S { ~S(); };
|
||||
void bar();
|
||||
void foo()
|
||||
{
|
||||
S s;
|
||||
bar();
|
||||
}
|
||||
EOF
|
||||
old_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS=-S
|
||||
if AC_TRY_EVAL(ac_compile); then
|
||||
if grep _Unwind_SjLj_Resume conftest.s >/dev/null 2>&1 ; then
|
||||
enable_sjlj_exceptions=yes
|
||||
elif grep _Unwind_Resume conftest.s >/dev/null 2>&1 ; then
|
||||
enable_sjlj_exceptions=no
|
||||
fi
|
||||
fi
|
||||
CXXFLAGS="$old_CXXFLAGS"
|
||||
rm -f conftest*])
|
||||
if test x$enable_sjlj_exceptions = xyes; then
|
||||
AC_DEFINE(_GLIBCPP_SJLJ_EXCEPTIONS, 1,
|
||||
[Define if the compiler is configured for setjmp/longjmp exceptions.])
|
||||
ac_exception_model_name=sjlj
|
||||
elif test x$enable_sjlj_exceptions = xno; then
|
||||
ac_exception_model_name="call frame"
|
||||
else
|
||||
AC_MSG_ERROR([unable to detect exception model])
|
||||
fi
|
||||
AC_LANG_RESTORE
|
||||
AC_MSG_RESULT($ac_exception_model_name)
|
||||
])
|
||||
|
||||
|
||||
dnl
|
||||
dnl Check for template specializations for the 'long long' type extension.
|
||||
dnl
|
||||
|
60
libstdc++-v3/aclocal.m4
vendored
60
libstdc++-v3/aclocal.m4
vendored
@ -1269,6 +1269,66 @@ AC_DEFUN(GLIBCPP_ENABLE_THREADS, [
|
||||
])
|
||||
|
||||
|
||||
dnl
|
||||
dnl Check for exception handling support. If an explicit enable/disable
|
||||
dnl sjlj exceptions is given, we don't have to detect. Otherwise the
|
||||
dnl target may or may not support call frame exceptions.
|
||||
dnl
|
||||
dnl GLIBCPP_ENABLE_SJLJ_EXCEPTIONS
|
||||
dnl --enable-sjlj-exceptions forces the use of builtin setjmp.
|
||||
dnl --disable-sjlj-exceptions forces the use of call frame unwinding.
|
||||
dnl
|
||||
dnl Define _GLIBCPP_SJLJ_EXCEPTIONS if the compiler is configured for it.
|
||||
dnl
|
||||
AC_DEFUN(GLIBCPP_ENABLE_SJLJ_EXCEPTIONS, [
|
||||
AC_MSG_CHECKING([for exception model to use])
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_ARG_ENABLE(sjlj-exceptions,
|
||||
[ --enable-sjlj-exceptions force use of builtin_setjmp for exceptions],
|
||||
[:],
|
||||
[dnl Botheration. Now we've got to detect the exception model.
|
||||
dnl Link tests against libgcc.a are problematic since -- at least
|
||||
dnl as of this writing -- we've not been given proper -L bits for
|
||||
dnl single-tree newlib and libgloss.
|
||||
dnl
|
||||
dnl This is what AC_TRY_COMPILE would do if it didn't delete the
|
||||
dnl conftest files before we got a change to grep them first.
|
||||
cat > conftest.$ac_ext << EOF
|
||||
[#]line __oline__ "configure"
|
||||
struct S { ~S(); };
|
||||
void bar();
|
||||
void foo()
|
||||
{
|
||||
S s;
|
||||
bar();
|
||||
}
|
||||
EOF
|
||||
old_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS=-S
|
||||
if AC_TRY_EVAL(ac_compile); then
|
||||
if grep _Unwind_SjLj_Resume conftest.s >/dev/null 2>&1 ; then
|
||||
enable_sjlj_exceptions=yes
|
||||
elif grep _Unwind_Resume conftest.s >/dev/null 2>&1 ; then
|
||||
enable_sjlj_exceptions=no
|
||||
fi
|
||||
fi
|
||||
CXXFLAGS="$old_CXXFLAGS"
|
||||
rm -f conftest*])
|
||||
if test x$enable_sjlj_exceptions = xyes; then
|
||||
AC_DEFINE(_GLIBCPP_SJLJ_EXCEPTIONS, 1,
|
||||
[Define if the compiler is configured for setjmp/longjmp exceptions.])
|
||||
ac_exception_model_name=sjlj
|
||||
elif test x$enable_sjlj_exceptions = xno; then
|
||||
ac_exception_model_name="call frame"
|
||||
else
|
||||
AC_MSG_ERROR([unable to detect exception model])
|
||||
fi
|
||||
AC_LANG_RESTORE
|
||||
AC_MSG_RESULT($ac_exception_model_name)
|
||||
])
|
||||
|
||||
|
||||
dnl
|
||||
dnl Check for template specializations for the 'long long' type extension.
|
||||
dnl
|
||||
|
@ -546,6 +546,9 @@
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define if the compiler is configured for setjmp/longjmp exceptions. */
|
||||
#undef _GLIBCPP_SJLJ_EXCEPTIONS
|
||||
|
||||
/* Define if sigsetjmp is available. */
|
||||
#undef HAVE_SIGSETJMP
|
||||
|
||||
|
1674
libstdc++-v3/configure
vendored
1674
libstdc++-v3/configure
vendored
File diff suppressed because it is too large
Load Diff
@ -68,6 +68,7 @@ GLIBCPP_ENABLE_LONG_LONG([no])
|
||||
GLIBCPP_ENABLE_CHEADERS([c_std])
|
||||
GLIBCPP_ENABLE_THREADS
|
||||
GLIBCPP_ENABLE_CXX_FLAGS([none])
|
||||
GLIBCPP_ENABLE_SJLJ_EXCEPTIONS
|
||||
|
||||
if test -n "$with_cross_host"; then
|
||||
|
||||
|
@ -110,7 +110,7 @@ toplevel_srcdir = @toplevel_srcdir@
|
||||
AUTOMAKE_OPTIONS = 1.3 cygnus
|
||||
|
||||
mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
|
||||
@GLIBCPP_BUILD_LIBIO_TRUE@noinst_LTLIBRARIES = @GLIBCPP_BUILD_LIBIO_TRUE@libio.la
|
||||
@GLIBCPP_BUILD_LIBIO_TRUE@noinst_LTLIBRARIES = libio.la
|
||||
@GLIBCPP_BUILD_LIBIO_FALSE@noinst_LTLIBRARIES =
|
||||
|
||||
# Use common includes from acinclude.m4/GLIBCPP_EXPORT_INCLUDES
|
||||
@ -122,21 +122,14 @@ LIBSUPCXX_INCLUDES = @LIBSUPCXX_INCLUDES@
|
||||
LIBIO_INCLUDES = @LIBIO_INCLUDES@
|
||||
CSHADOW_INCLUDES = @CSHADOW_INCLUDES@
|
||||
|
||||
INCLUDES = \
|
||||
-nostdinc++ \
|
||||
-I$(top_builddir)/include -I$(GLIBCPP_INCLUDE_DIR) \
|
||||
$(LIBIO_INCLUDES) $(TOPLEVEL_INCLUDES)
|
||||
INCLUDES = -nostdinc++ -I$(top_builddir)/include -I$(GLIBCPP_INCLUDE_DIR) $(LIBIO_INCLUDES) $(TOPLEVEL_INCLUDES)
|
||||
|
||||
|
||||
libio_headers = \
|
||||
libio.h libioP.h iolibio.h
|
||||
libio_headers = libio.h libioP.h iolibio.h
|
||||
|
||||
@GLIBCPP_NEED_LIBIO_TRUE@LIBIO_SRCS = @GLIBCPP_NEED_LIBIO_TRUE@\
|
||||
@GLIBCPP_NEED_LIBIO_TRUE@ filedoalloc.c genops.c fileops.c stdfiles.c c_codecvt.c \
|
||||
@GLIBCPP_NEED_LIBIO_TRUE@ iofclose.c iofopen.c
|
||||
@GLIBCPP_NEED_LIBIO_TRUE@LIBIO_SRCS = filedoalloc.c genops.c fileops.c stdfiles.c c_codecvt.c iofclose.c iofopen.c
|
||||
@GLIBCPP_NEED_LIBIO_FALSE@LIBIO_SRCS =
|
||||
@GLIBCPP_NEED_WLIBIO_TRUE@LIBIO_WSRCS = @GLIBCPP_NEED_WLIBIO_TRUE@\
|
||||
@GLIBCPP_NEED_WLIBIO_TRUE@ wfiledoalloc.c wfileops.c wgenops.c iofwide.c
|
||||
@GLIBCPP_NEED_WLIBIO_TRUE@LIBIO_WSRCS = wfiledoalloc.c wfileops.c wgenops.c iofwide.c
|
||||
@GLIBCPP_NEED_WLIBIO_FALSE@LIBIO_WSRCS =
|
||||
|
||||
EXTRA_DIST = iostreamP.h
|
||||
@ -299,7 +292,7 @@ distdir: $(DISTFILES)
|
||||
@for file in $(DISTFILES); do \
|
||||
if test -f $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
cp -pr $$d/$$file $(distdir)/$$file; \
|
||||
cp -pr $$/$$file $(distdir)/$$file; \
|
||||
else \
|
||||
test -f $(distdir)/$$file \
|
||||
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|
||||
|
@ -113,24 +113,18 @@ mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
|
||||
|
||||
noinst_LTLIBRARIES = libmath.la
|
||||
|
||||
EXTRA_LONG_DOUBLE_yes = \
|
||||
hypotl.c signbitl.c
|
||||
EXTRA_LONG_DOUBLE_yes = hypotl.c signbitl.c
|
||||
|
||||
|
||||
EXTRA_DIST = \
|
||||
hypot.c hypotf.c atan2f.c expf.c \
|
||||
$(EXTRA_LONG_DOUBLE_yes)
|
||||
EXTRA_DIST = hypot.c hypotf.c atan2f.c expf.c $(EXTRA_LONG_DOUBLE_yes)
|
||||
|
||||
|
||||
libmath_la_LIBADD = \
|
||||
@LIBMATHOBJS@ \
|
||||
$(EXTRA_LONG_DOUBLE_$(USE_COMPLEX_LONG_DOUBLE))
|
||||
libmath_la_LIBADD = @LIBMATHOBJS@ $(EXTRA_LONG_DOUBLE_$(USE_COMPLEX_LONG_DOUBLE))
|
||||
|
||||
|
||||
libmath_la_DEPENDENCIES = $(libmath_la_LIBADD)
|
||||
|
||||
libmath_la_SOURCES = \
|
||||
signbit.c signbitf.c
|
||||
libmath_la_SOURCES = signbit.c signbitf.c
|
||||
|
||||
|
||||
LINK = $(LIBTOOL) --mode=link "$(CCLD)" $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
|
||||
@ -144,9 +138,7 @@ LIBSUPCXX_INCLUDES = @LIBSUPCXX_INCLUDES@
|
||||
LIBIO_INCLUDES = @LIBIO_INCLUDES@
|
||||
CSHADOW_INCLUDES = @CSHADOW_INCLUDES@
|
||||
|
||||
INCLUDES = \
|
||||
-I$(GLIBCPP_INCLUDE_DIR) -I$(top_builddir)/include \
|
||||
$(TOPLEVEL_INCLUDES)
|
||||
INCLUDES = -I$(GLIBCPP_INCLUDE_DIR) -I$(top_builddir)/include $(TOPLEVEL_INCLUDES)
|
||||
|
||||
CONFIG_HEADER = ../config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
@ -277,7 +269,7 @@ distdir: $(DISTFILES)
|
||||
@for file in $(DISTFILES); do \
|
||||
if test -f $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
cp -pr $$d/$$file $(distdir)/$$file; \
|
||||
cp -pr $$/$$file $(distdir)/$$file; \
|
||||
else \
|
||||
test -f $(distdir)/$$file \
|
||||
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|
||||
|
@ -75,7 +75,14 @@ sources = \
|
||||
del_opnt.cc \
|
||||
del_opv.cc \
|
||||
del_opvnt.cc \
|
||||
exception_support.cc \
|
||||
eh_alloc.cc \
|
||||
eh_aux_runtime.cc \
|
||||
eh_catch.cc \
|
||||
eh_exception.cc \
|
||||
eh_globals.cc \
|
||||
eh_personality.cc \
|
||||
eh_terminate.cc \
|
||||
eh_throw.cc \
|
||||
new_handler.cc \
|
||||
new_op.cc \
|
||||
new_opnt.cc \
|
||||
|
@ -127,13 +127,11 @@ OPTIMIZE_CXXFLAGS = @OPTIMIZE_CXXFLAGS@
|
||||
# These bits are all figured out from configure. Look in acinclude.m4
|
||||
# or configure.in to see how they are set. See GLIBCPP_EXPORT_FLAGS
|
||||
# NB: DEBUGFLAGS have to be at the end so that -O2 can be overridden.
|
||||
CONFIG_CXXFLAGS = \
|
||||
@EXTRA_CXX_FLAGS@ @SECTION_FLAGS@ @CSHADOW_FLAGS@ @DEBUG_FLAGS@
|
||||
CONFIG_CXXFLAGS = @EXTRA_CXX_FLAGS@ @SECTION_FLAGS@ @CSHADOW_FLAGS@ @DEBUG_FLAGS@
|
||||
|
||||
|
||||
# Warning flags to use.
|
||||
WARN_CXXFLAGS = \
|
||||
@WARN_FLAGS@ $(WERROR) -fdiagnostics-show-location=once
|
||||
WARN_CXXFLAGS = @WARN_FLAGS@ $(WERROR) -fdiagnostics-show-location=once
|
||||
|
||||
|
||||
# Use common includes from acinclude.m4/GLIBCPP_EXPORT_INCLUDES
|
||||
@ -145,31 +143,13 @@ LIBSUPCXX_INCLUDES = @LIBSUPCXX_INCLUDES@
|
||||
LIBIO_INCLUDES = @LIBIO_INCLUDES@
|
||||
TOPLEVEL_INCLUDES = @TOPLEVEL_INCLUDES@
|
||||
|
||||
INCLUDES = \
|
||||
-I$(toplevel_srcdir)/gcc -I$(toplevel_srcdir)/include \
|
||||
-I$(GLIBCPP_INCLUDE_DIR) $(CSTD_INCLUDES) -I$(top_builddir)/include \
|
||||
$(LIBSUPCXX_INCLUDES)
|
||||
INCLUDES = -I$(toplevel_srcdir)/gcc -I$(toplevel_srcdir)/include -I$(GLIBCPP_INCLUDE_DIR) $(CSTD_INCLUDES) -I$(top_builddir)/include $(LIBSUPCXX_INCLUDES)
|
||||
|
||||
|
||||
headers = \
|
||||
exception new typeinfo cxxabi.h exception_defines.h
|
||||
headers = exception new typeinfo cxxabi.h exception_defines.h
|
||||
|
||||
|
||||
sources = \
|
||||
del_op.cc \
|
||||
del_opnt.cc \
|
||||
del_opv.cc \
|
||||
del_opvnt.cc \
|
||||
exception_support.cc \
|
||||
new_handler.cc \
|
||||
new_op.cc \
|
||||
new_opnt.cc \
|
||||
new_opv.cc \
|
||||
new_opvnt.cc \
|
||||
pure.cc \
|
||||
tinfo.cc \
|
||||
tinfo2.cc \
|
||||
vec.cc
|
||||
sources = del_op.cc del_opnt.cc del_opv.cc del_opvnt.cc eh_alloc.cc eh_aux_runtime.cc eh_catch.cc eh_exception.cc eh_globals.cc eh_personality.cc eh_terminate.cc eh_throw.cc new_handler.cc new_op.cc new_opnt.cc new_opv.cc new_opvnt.cc pure.cc tinfo.cc tinfo2.cc vec.cc
|
||||
|
||||
|
||||
libsupc___la_SOURCES = $(sources)
|
||||
@ -187,12 +167,7 @@ LIBSUPCXX_CXXFLAGS = -prefer-pic
|
||||
# set this option because CONFIG_CXXFLAGS has to be after
|
||||
# OPTIMIZE_CXXFLAGS on the compile line so that -O2 can be overridden
|
||||
# as the occasion call for it. (ie, --enable-debug)
|
||||
AM_CXXFLAGS = \
|
||||
-fno-implicit-templates \
|
||||
$(LIBSUPCXX_CXXFLAGS) \
|
||||
$(WARN_CXXFLAGS) \
|
||||
$(OPTIMIZE_CXXFLAGS) \
|
||||
$(CONFIG_CXXFLAGS)
|
||||
AM_CXXFLAGS = -fno-implicit-templates $(LIBSUPCXX_CXXFLAGS) $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS)
|
||||
|
||||
|
||||
# libstdc++ libtool notes
|
||||
@ -216,9 +191,7 @@ AM_CXXFLAGS = \
|
||||
#
|
||||
# We have to put --tag disable-shared after --tag CXX lest things
|
||||
# CXX undo the affect of disable-shared.
|
||||
LTCXXCOMPILE = $(LIBTOOL) --tag CXX --tag disable-shared \
|
||||
--mode=compile $(CXX) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(AM_CXXFLAGS)
|
||||
LTCXXCOMPILE = $(LIBTOOL) --tag CXX --tag disable-shared --mode=compile $(CXX) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(AM_CXXFLAGS)
|
||||
|
||||
|
||||
# 3) We'd have a problem when building the shared libstdc++ object if
|
||||
@ -227,8 +200,7 @@ LTCXXCOMPILE = $(LIBTOOL) --tag CXX --tag disable-shared \
|
||||
# course is problematic at this point. So, we get the top-level
|
||||
# directory to configure libstdc++-v3 to use gcc as the C++
|
||||
# compilation driver.
|
||||
CXXLINK = $(LIBTOOL) --tag CXX --mode=link $(CXX) \
|
||||
@OPT_LDFLAGS@ @SECTION_LDFLAGS@ $(AM_CXXFLAGS) $(LDFLAGS) -o $@
|
||||
CXXLINK = $(LIBTOOL) --tag CXX --mode=link $(CXX) @OPT_LDFLAGS@ @SECTION_LDFLAGS@ $(AM_CXXFLAGS) $(LDFLAGS) -o $@
|
||||
|
||||
CONFIG_HEADER = ../config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
@ -242,13 +214,16 @@ LIBS = @LIBS@
|
||||
libsupc__convenience_la_LDFLAGS =
|
||||
libsupc__convenience_la_LIBADD =
|
||||
libsupc__convenience_la_OBJECTS = del_op.lo del_opnt.lo del_opv.lo \
|
||||
del_opvnt.lo exception_support.lo new_handler.lo new_op.lo new_opnt.lo \
|
||||
new_opv.lo new_opvnt.lo pure.lo tinfo.lo tinfo2.lo vec.lo
|
||||
del_opvnt.lo eh_alloc.lo eh_aux_runtime.lo eh_catch.lo eh_exception.lo \
|
||||
eh_globals.lo eh_personality.lo eh_terminate.lo eh_throw.lo \
|
||||
new_handler.lo new_op.lo new_opnt.lo new_opv.lo new_opvnt.lo pure.lo \
|
||||
tinfo.lo tinfo2.lo vec.lo
|
||||
libsupc___la_LDFLAGS =
|
||||
libsupc___la_LIBADD =
|
||||
libsupc___la_OBJECTS = del_op.lo del_opnt.lo del_opv.lo del_opvnt.lo \
|
||||
exception_support.lo new_handler.lo new_op.lo new_opnt.lo new_opv.lo \
|
||||
new_opvnt.lo pure.lo tinfo.lo tinfo2.lo vec.lo
|
||||
eh_alloc.lo eh_aux_runtime.lo eh_catch.lo eh_exception.lo eh_globals.lo \
|
||||
eh_personality.lo eh_terminate.lo eh_throw.lo new_handler.lo new_op.lo \
|
||||
new_opnt.lo new_opv.lo new_opvnt.lo pure.lo tinfo.lo tinfo2.lo vec.lo
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||
CXXLD = $(CXX)
|
||||
@ -417,7 +392,7 @@ distdir: $(DISTFILES)
|
||||
@for file in $(DISTFILES); do \
|
||||
if test -f $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
cp -pr $$d/$$file $(distdir)/$$file; \
|
||||
cp -pr $$/$$file $(distdir)/$$file; \
|
||||
else \
|
||||
test -f $(distdir)/$$file \
|
||||
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|
||||
|
157
libstdc++-v3/libsupc++/eh_alloc.cc
Normal file
157
libstdc++-v3/libsupc++/eh_alloc.cc
Normal file
@ -0,0 +1,157 @@
|
||||
// -*- C++ -*- Allocate exception objects.
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
// This is derived from the C++ ABI for IA-64. Where we diverge
|
||||
// for cross-architecture compatibility are noted with "@@@".
|
||||
|
||||
#include <exception>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <limits.h>
|
||||
#include "unwind-cxx.h"
|
||||
#include "gthr.h"
|
||||
|
||||
using namespace __cxxabiv1;
|
||||
|
||||
|
||||
// ??? How to control these parameters.
|
||||
|
||||
// Guess from the size of basic types how large a buffer is reasonable.
|
||||
// Note that the basic c++ exception header has 13 pointers and 2 ints,
|
||||
// so on a system with PSImode pointers we're talking about 56 bytes
|
||||
// just for overhead.
|
||||
|
||||
#if INT_MAX == 32767
|
||||
# define EMERGENCY_OBJ_SIZE 128
|
||||
# define EMERGENCY_OBJ_COUNT 16
|
||||
#elif LONG_MAX == 2147483647
|
||||
# define EMERGENCY_OBJ_SIZE 512
|
||||
# define EMERGENCY_OBJ_COUNT 32
|
||||
#else
|
||||
# define EMERGENCY_OBJ_SIZE 1024
|
||||
# define EMERGENCY_OBJ_COUNT 64
|
||||
#endif
|
||||
|
||||
#ifndef __GTHREADS
|
||||
# undef EMERGENCY_OBJ_COUNT
|
||||
# define EMERGENCY_OBJ_COUNT 4
|
||||
#endif
|
||||
|
||||
#if INT_MAX == 32767 || EMERGENCY_OBJ_COUNT <= 32
|
||||
typedef unsigned int bitmask_type;
|
||||
#else
|
||||
typedef unsigned long bitmask_type;
|
||||
#endif
|
||||
|
||||
|
||||
typedef char one_buffer[EMERGENCY_OBJ_SIZE] __attribute__((aligned));
|
||||
static one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT];
|
||||
static bitmask_type emergency_used;
|
||||
|
||||
|
||||
#ifdef __GTHREADS
|
||||
#ifdef __GTHREAD_MUTEX_INIT
|
||||
static __gthread_mutex_t emergency_mutex =__GTHREAD_MUTEX_INIT;
|
||||
#else
|
||||
static __gthread_mutex_t emergency_mutex;
|
||||
#endif
|
||||
|
||||
#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
|
||||
static void
|
||||
emergency_mutex_init ()
|
||||
{
|
||||
__GTHREAD_MUTEX_INIT_FUNCTION (&emergency_mutex);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
extern "C" void *
|
||||
__cxa_allocate_exception(std::size_t thrown_size)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
thrown_size += sizeof (__cxa_exception);
|
||||
ret = malloc (thrown_size);
|
||||
|
||||
if (! ret)
|
||||
{
|
||||
#ifdef __GTHREADS
|
||||
#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
|
||||
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
|
||||
__gthread_once (&once, emergency_mutex_init);
|
||||
#endif
|
||||
__gthread_mutex_lock (&emergency_mutex);
|
||||
#endif
|
||||
|
||||
bitmask_type used = emergency_used;
|
||||
unsigned int which = 0;
|
||||
|
||||
while (used & 1)
|
||||
{
|
||||
used >>= 1;
|
||||
if (++which >= EMERGENCY_OBJ_COUNT)
|
||||
std::terminate ();
|
||||
}
|
||||
|
||||
emergency_used |= (bitmask_type)1 << which;
|
||||
ret = &emergency_buffer[which][0];
|
||||
|
||||
#ifdef __GTHREADS
|
||||
__gthread_mutex_unlock (&emergency_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
memset (ret, 0, sizeof (__cxa_exception));
|
||||
|
||||
return (void *)((char *)ret + sizeof (__cxa_exception));
|
||||
}
|
||||
|
||||
|
||||
extern "C" void
|
||||
__cxa_free_exception(void *vptr)
|
||||
{
|
||||
char *ptr = (char *) vptr;
|
||||
if (ptr >= &emergency_buffer[0][0]
|
||||
&& ptr < &emergency_buffer[0][0] + sizeof (emergency_buffer))
|
||||
{
|
||||
unsigned int which
|
||||
= (unsigned)(ptr - &emergency_buffer[0][0]) / EMERGENCY_OBJ_SIZE;
|
||||
|
||||
#ifdef __GTHREADS
|
||||
__gthread_mutex_lock (&emergency_mutex);
|
||||
emergency_used &= ~((bitmask_type)1 << which);
|
||||
__gthread_mutex_unlock (&emergency_mutex);
|
||||
#else
|
||||
emergency_used &= ~((bitmask_type)1 << which);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
free (ptr - sizeof (__cxa_exception));
|
||||
}
|
56
libstdc++-v3/libsupc++/eh_aux_runtime.cc
Normal file
56
libstdc++-v3/libsupc++/eh_aux_runtime.cc
Normal file
@ -0,0 +1,56 @@
|
||||
// -*- C++ -*- Common throw conditions.
|
||||
// Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
|
||||
// Free Software Foundation
|
||||
//
|
||||
// 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.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
#include "typeinfo"
|
||||
#include "exception"
|
||||
#include <cstddef>
|
||||
#include "unwind-cxx.h"
|
||||
#include "exception_defines.h"
|
||||
|
||||
|
||||
extern "C" void
|
||||
__cxa_bad_cast ()
|
||||
{
|
||||
#ifdef __EXCEPTIONS
|
||||
throw std::bad_cast();
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
__cxa_bad_typeid ()
|
||||
{
|
||||
#ifdef __EXCEPTIONS
|
||||
throw std::bad_typeid();
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
103
libstdc++-v3/libsupc++/eh_catch.cc
Normal file
103
libstdc++-v3/libsupc++/eh_catch.cc
Normal file
@ -0,0 +1,103 @@
|
||||
// -*- C++ -*- Exception handling routines for catching.
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
|
||||
#include <cstdlib>
|
||||
#include "unwind-cxx.h"
|
||||
|
||||
using namespace __cxxabiv1;
|
||||
|
||||
|
||||
extern "C" void *
|
||||
__cxa_begin_catch (_Unwind_Exception *exceptionObject)
|
||||
{
|
||||
// ??? Foreign exceptions can't be stacked here, and there doesn't
|
||||
// appear to be any place to store for __cxa_end_catch to destroy.
|
||||
|
||||
__cxa_exception *header = __get_exception_header_from_ue (exceptionObject);
|
||||
__cxa_eh_globals *globals = __cxa_get_globals ();
|
||||
__cxa_exception *prev = globals->caughtExceptions;
|
||||
int count = header->handlerCount;
|
||||
|
||||
if (count < 0)
|
||||
// This exception was rethrown from an immediately enclosing region.
|
||||
count = -count + 1;
|
||||
else
|
||||
count += 1;
|
||||
header->handlerCount = count;
|
||||
|
||||
globals->uncaughtExceptions -= 1;
|
||||
if (header != prev)
|
||||
{
|
||||
header->nextException = prev;
|
||||
globals->caughtExceptions = header;
|
||||
}
|
||||
|
||||
return header->adjustedPtr;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void
|
||||
__cxa_end_catch ()
|
||||
{
|
||||
__cxa_eh_globals *globals = __cxa_get_globals_fast ();
|
||||
__cxa_exception *header = globals->caughtExceptions;
|
||||
int count = header->handlerCount;
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
// This exception was rethrown. Decrement the (inverted) catch
|
||||
// count and remove it from the chain when it reaches zero.
|
||||
if (++count == 0)
|
||||
{
|
||||
globals->uncaughtExceptions += 1;
|
||||
globals->caughtExceptions = header->nextException;
|
||||
}
|
||||
}
|
||||
else if (--count == 0)
|
||||
{
|
||||
// Handling for this exception is complete. Destroy the object.
|
||||
globals->caughtExceptions = header->nextException;
|
||||
_Unwind_DeleteException (&header->unwindHeader);
|
||||
return;
|
||||
}
|
||||
else if (count < 0)
|
||||
// A bug in the exception handling library or compiler.
|
||||
abort ();
|
||||
|
||||
header->handlerCount = count;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
std::uncaught_exception() throw()
|
||||
{
|
||||
__cxa_eh_globals *globals = __cxa_get_globals ();
|
||||
return globals->uncaughtExceptions != 0;
|
||||
}
|
44
libstdc++-v3/libsupc++/eh_exception.cc
Normal file
44
libstdc++-v3/libsupc++/eh_exception.cc
Normal file
@ -0,0 +1,44 @@
|
||||
// -*- C++ -*- std::exception implementation.
|
||||
// Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
|
||||
// Free Software Foundation
|
||||
//
|
||||
// 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.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
|
||||
#include "typeinfo"
|
||||
#include "exception"
|
||||
#include "unwind-cxx.h"
|
||||
|
||||
std::exception::~exception() throw() { }
|
||||
|
||||
std::bad_exception::~bad_exception() throw() { }
|
||||
|
||||
const char*
|
||||
std::exception::what() const throw()
|
||||
{
|
||||
return typeid (*this).name ();
|
||||
}
|
120
libstdc++-v3/libsupc++/eh_globals.cc
Normal file
120
libstdc++-v3/libsupc++/eh_globals.cc
Normal file
@ -0,0 +1,120 @@
|
||||
// -*- C++ -*- Manage the thread-local exception globals.
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
|
||||
#include <exception>
|
||||
#include "unwind-cxx.h"
|
||||
#include "gthr.h"
|
||||
|
||||
using namespace __cxxabiv1;
|
||||
|
||||
|
||||
// Single-threaded fallback buffer.
|
||||
static __cxa_eh_globals globals_static;
|
||||
|
||||
#if __GTHREADS
|
||||
static __gthread_key_t globals_key;
|
||||
static int use_thread_key = -1;
|
||||
|
||||
static void
|
||||
get_globals_dtor (void *ptr)
|
||||
{
|
||||
__gthread_key_dtor (globals_key, ptr);
|
||||
if (ptr)
|
||||
free (ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
get_globals_init ()
|
||||
{
|
||||
use_thread_key =
|
||||
(__gthread_key_create (&globals_key, get_globals_dtor) == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
get_globals_init_once ()
|
||||
{
|
||||
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
|
||||
if (__gthread_once (&once, get_globals_init) != 0
|
||||
|| use_thread_key < 0)
|
||||
use_thread_key = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" __cxa_eh_globals *
|
||||
__cxa_get_globals_fast ()
|
||||
{
|
||||
#if __GTHREADS
|
||||
if (use_thread_key)
|
||||
return (__cxa_eh_globals *) __gthread_getspecific (globals_key);
|
||||
else
|
||||
return &globals_static;
|
||||
#else
|
||||
return &globals_static;
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" __cxa_eh_globals *
|
||||
__cxa_get_globals ()
|
||||
{
|
||||
#if __GTHREADS
|
||||
__cxa_eh_globals *g;
|
||||
|
||||
if (use_thread_key == 0)
|
||||
return &globals_static;
|
||||
|
||||
if (use_thread_key < 0)
|
||||
get_globals_init_once ();
|
||||
|
||||
g = (__cxa_eh_globals *) __gthread_getspecific (globals_key);
|
||||
if (! g)
|
||||
{
|
||||
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
|
||||
|
||||
// Make sure use_thread_key got initialized. Some systems have
|
||||
// dummy thread routines in their libc that return a success.
|
||||
if (__gthread_once (&once, eh_threads_initialize) != 0
|
||||
|| use_thread_key < 0)
|
||||
{
|
||||
use_thread_key = 0;
|
||||
return &globals_static;
|
||||
}
|
||||
|
||||
if ((g = malloc (sizeof (__cxa_eh_globals))) == 0
|
||||
|| __gthread_setspecific (eh_context_key, (void *) g) != 0)
|
||||
std::terminate ();
|
||||
g->caughtExceptions = 0;
|
||||
g->uncaughtExceptions = 0;
|
||||
}
|
||||
|
||||
return g;
|
||||
#else
|
||||
return &globals_static;
|
||||
#endif
|
||||
}
|
599
libstdc++-v3/libsupc++/eh_personality.cc
Normal file
599
libstdc++-v3/libsupc++/eh_personality.cc
Normal file
@ -0,0 +1,599 @@
|
||||
// -*- C++ -*- The GNU C++ exception personality routine.
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
|
||||
#include <bits/c++config.h>
|
||||
#include <cstdlib>
|
||||
#include "unwind-cxx.h"
|
||||
|
||||
using namespace __cxxabiv1;
|
||||
|
||||
|
||||
|
||||
// ??? These ought to go somewhere else dwarf2 or dwarf2eh related.
|
||||
|
||||
// Pointer encodings.
|
||||
#define DW_EH_PE_absptr 0x00
|
||||
#define DW_EH_PE_omit 0xff
|
||||
|
||||
#define DW_EH_PE_uleb128 0x01
|
||||
#define DW_EH_PE_udata2 0x02
|
||||
#define DW_EH_PE_udata4 0x03
|
||||
#define DW_EH_PE_udata8 0x04
|
||||
#define DW_EH_PE_sleb128 0x09
|
||||
#define DW_EH_PE_sdata2 0x0A
|
||||
#define DW_EH_PE_sdata4 0x0B
|
||||
#define DW_EH_PE_sdata8 0x0C
|
||||
#define DW_EH_PE_signed 0x08
|
||||
|
||||
#define DW_EH_PE_pcrel 0x10
|
||||
#define DW_EH_PE_textrel 0x20
|
||||
#define DW_EH_PE_datarel 0x30
|
||||
#define DW_EH_PE_funcrel 0x40
|
||||
|
||||
static unsigned int
|
||||
size_of_encoded_value (unsigned char encoding)
|
||||
{
|
||||
switch (encoding & 0x07)
|
||||
{
|
||||
case DW_EH_PE_absptr:
|
||||
return sizeof (void *);
|
||||
case DW_EH_PE_udata2:
|
||||
return 2;
|
||||
case DW_EH_PE_udata4:
|
||||
return 4;
|
||||
case DW_EH_PE_udata8:
|
||||
return 8;
|
||||
}
|
||||
abort ();
|
||||
}
|
||||
|
||||
static const unsigned char *
|
||||
read_encoded_value (_Unwind_Context *context, unsigned char encoding,
|
||||
const unsigned char *p, _Unwind_Ptr *val)
|
||||
{
|
||||
union unaligned
|
||||
{
|
||||
void *ptr;
|
||||
unsigned u2 __attribute__ ((mode (HI)));
|
||||
unsigned u4 __attribute__ ((mode (SI)));
|
||||
unsigned u8 __attribute__ ((mode (DI)));
|
||||
signed s2 __attribute__ ((mode (HI)));
|
||||
signed s4 __attribute__ ((mode (SI)));
|
||||
signed s8 __attribute__ ((mode (DI)));
|
||||
} __attribute__((__packed__));
|
||||
|
||||
union unaligned *u = (union unaligned *) p;
|
||||
_Unwind_Ptr result;
|
||||
|
||||
switch (encoding & 0x0f)
|
||||
{
|
||||
case DW_EH_PE_absptr:
|
||||
result = (_Unwind_Ptr) u->ptr;
|
||||
p += sizeof (void *);
|
||||
break;
|
||||
|
||||
case DW_EH_PE_uleb128:
|
||||
{
|
||||
unsigned int shift = 0;
|
||||
unsigned char byte;
|
||||
|
||||
result = 0;
|
||||
do
|
||||
{
|
||||
byte = *p++;
|
||||
result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
while (byte & 0x80);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_EH_PE_sleb128:
|
||||
{
|
||||
unsigned int shift = 0;
|
||||
unsigned char byte;
|
||||
|
||||
result = 0;
|
||||
do
|
||||
{
|
||||
byte = *p++;
|
||||
result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
while (byte & 0x80);
|
||||
|
||||
if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
|
||||
result |= -(1L << shift);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_EH_PE_udata2:
|
||||
result = u->u2;
|
||||
p += 2;
|
||||
break;
|
||||
case DW_EH_PE_udata4:
|
||||
result = u->u4;
|
||||
p += 4;
|
||||
break;
|
||||
case DW_EH_PE_udata8:
|
||||
result = u->u8;
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_sdata2:
|
||||
result = u->s2;
|
||||
p += 2;
|
||||
break;
|
||||
case DW_EH_PE_sdata4:
|
||||
result = u->s4;
|
||||
p += 4;
|
||||
break;
|
||||
case DW_EH_PE_sdata8:
|
||||
result = u->s8;
|
||||
p += 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (result != 0)
|
||||
switch (encoding & 0xf0)
|
||||
{
|
||||
case DW_EH_PE_absptr:
|
||||
break;
|
||||
|
||||
case DW_EH_PE_pcrel:
|
||||
// Define as relative to the beginning of the pointer.
|
||||
result += (_Unwind_Ptr) u;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_textrel:
|
||||
case DW_EH_PE_datarel:
|
||||
// FIXME.
|
||||
abort ();
|
||||
|
||||
case DW_EH_PE_funcrel:
|
||||
result += _Unwind_GetRegionStart (context);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
*val = result;
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline const unsigned char *
|
||||
read_uleb128 (const unsigned char *p, _Unwind_Ptr *val)
|
||||
{
|
||||
return read_encoded_value (0, DW_EH_PE_uleb128, p, val);
|
||||
}
|
||||
|
||||
static inline const unsigned char *
|
||||
read_sleb128 (const unsigned char *p, _Unwind_Ptr *val)
|
||||
{
|
||||
return read_encoded_value (0, DW_EH_PE_sleb128, p, val);
|
||||
}
|
||||
|
||||
|
||||
struct lsda_header_info
|
||||
{
|
||||
_Unwind_Ptr Start;
|
||||
_Unwind_Ptr LPStart;
|
||||
const unsigned char *TType;
|
||||
const unsigned char *action_table;
|
||||
unsigned char ttype_encoding;
|
||||
unsigned char call_site_encoding;
|
||||
};
|
||||
|
||||
static const unsigned char *
|
||||
parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
|
||||
lsda_header_info *info)
|
||||
{
|
||||
_Unwind_Ptr tmp;
|
||||
unsigned char lpstart_encoding;
|
||||
|
||||
info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
|
||||
|
||||
// Find @LPStart, the base to which landing pad offsets are relative.
|
||||
lpstart_encoding = *p++;
|
||||
if (lpstart_encoding != DW_EH_PE_omit)
|
||||
p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
|
||||
else
|
||||
info->LPStart = info->Start;
|
||||
|
||||
// Find @TType, the base of the handler and exception spec type data.
|
||||
info->ttype_encoding = *p++;
|
||||
if (info->ttype_encoding != DW_EH_PE_omit)
|
||||
{
|
||||
p = read_uleb128 (p, &tmp);
|
||||
info->TType = p + tmp;
|
||||
}
|
||||
else
|
||||
info->TType = 0;
|
||||
|
||||
// The encoding and length of the call-site table; the action table
|
||||
// immediately follows.
|
||||
info->call_site_encoding = *p++;
|
||||
p = read_uleb128 (p, &tmp);
|
||||
info->action_table = p + tmp;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static const std::type_info *
|
||||
get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
|
||||
{
|
||||
_Unwind_Ptr ptr;
|
||||
|
||||
i *= size_of_encoded_value (info->ttype_encoding);
|
||||
read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
|
||||
|
||||
return reinterpret_cast<const std::type_info *>(ptr);
|
||||
}
|
||||
|
||||
static bool
|
||||
check_exception_spec (_Unwind_Context *context, lsda_header_info *info,
|
||||
const std::type_info *throw_type, long filter_value)
|
||||
{
|
||||
const unsigned char *e = info->TType - filter_value - 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
const std::type_info *catch_type;
|
||||
_Unwind_Ptr tmp;
|
||||
void *dummy;
|
||||
|
||||
e = read_uleb128 (e, &tmp);
|
||||
|
||||
// Zero signals the end of the list. If we've not found
|
||||
// a match by now, then we've failed the specification.
|
||||
if (tmp == 0)
|
||||
return false;
|
||||
|
||||
// Match a ttype entry.
|
||||
catch_type = get_ttype_entry (context, info, tmp);
|
||||
if (catch_type->__do_catch (throw_type, &dummy, 1))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Using a different personality function name causes link failures
|
||||
// when trying to mix code using different exception handling models.
|
||||
#ifdef _GLIBCPP_SJLJ_EXCEPTIONS
|
||||
#define PERSONALITY_FUNCTION __gxx_personality_sj0
|
||||
#define __builtin_eh_return_data_regno(x) x
|
||||
#else
|
||||
#define PERSONALITY_FUNCTION __gxx_personality_v0
|
||||
#endif
|
||||
|
||||
extern "C" _Unwind_Reason_Code
|
||||
PERSONALITY_FUNCTION (int version,
|
||||
_Unwind_Action actions,
|
||||
_Unwind_Exception_Class exception_class,
|
||||
struct _Unwind_Exception *ue_header,
|
||||
struct _Unwind_Context *context)
|
||||
{
|
||||
__cxa_exception *xh = __get_exception_header_from_ue (ue_header);
|
||||
|
||||
enum found_handler_type
|
||||
{
|
||||
found_nothing,
|
||||
found_terminate,
|
||||
found_cleanup,
|
||||
found_handler
|
||||
} found_type;
|
||||
|
||||
lsda_header_info info;
|
||||
const unsigned char *language_specific_data;
|
||||
const unsigned char *action_record;
|
||||
const unsigned char *p;
|
||||
_Unwind_Ptr landing_pad, ip;
|
||||
int handler_switch_value;
|
||||
void *adjusted_ptr = xh + 1;
|
||||
|
||||
// Interface version check.
|
||||
if (version != 1)
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
|
||||
// Shortcut for phase 2 found handler for domestic exception.
|
||||
if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
|
||||
&& exception_class == __gxx_exception_class)
|
||||
{
|
||||
handler_switch_value = xh->handlerSwitchValue;
|
||||
landing_pad = (_Unwind_Ptr) xh->catchTemp;
|
||||
found_type = (landing_pad == 0 ? found_terminate : found_handler);
|
||||
goto install_context;
|
||||
}
|
||||
|
||||
language_specific_data = (const unsigned char *)
|
||||
_Unwind_GetLanguageSpecificData (context);
|
||||
|
||||
// If no LSDA, then there are no handlers or cleanups.
|
||||
if (! language_specific_data)
|
||||
return _URC_CONTINUE_UNWIND;
|
||||
|
||||
// Parse the LSDA header.
|
||||
p = parse_lsda_header (context, language_specific_data, &info);
|
||||
ip = _Unwind_GetIP (context) - 1;
|
||||
landing_pad = 0;
|
||||
action_record = 0;
|
||||
handler_switch_value = 0;
|
||||
|
||||
#ifdef _GLIBCPP_SJLJ_EXCEPTIONS
|
||||
// The given "IP" is an index into the call-site table, with two
|
||||
// exceptions -- -1 means no-action, and 0 means terminate. But
|
||||
// since we're using uleb128 values, we've not got random access
|
||||
// to the array.
|
||||
if ((int) ip < 0)
|
||||
return _URC_CONTINUE_UNWIND;
|
||||
else if (ip == 0)
|
||||
{
|
||||
// Fall through to set found_terminate.
|
||||
}
|
||||
else
|
||||
{
|
||||
_Unwind_Ptr cs_lp, cs_action;
|
||||
do
|
||||
{
|
||||
p = read_uleb128 (p, &cs_lp);
|
||||
p = read_uleb128 (p, &cs_action);
|
||||
}
|
||||
while (--ip);
|
||||
|
||||
// Can never have null landing pad for sjlj -- that would have
|
||||
// been indicated by a -1 call site index.
|
||||
landing_pad = cs_lp + 1;
|
||||
if (cs_action)
|
||||
action_record = info.action_table + cs_action - 1;
|
||||
goto found_something;
|
||||
}
|
||||
#else
|
||||
// Search the call-site table for the action associated with this IP.
|
||||
while (p < info.action_table)
|
||||
{
|
||||
_Unwind_Ptr cs_start, cs_len, cs_lp, cs_action;
|
||||
|
||||
// Note that all call-site encodings are "absolute" displacements.
|
||||
p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
|
||||
p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
|
||||
p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
|
||||
p = read_uleb128 (p, &cs_action);
|
||||
|
||||
// The table is sorted, so if we've passed the ip, stop.
|
||||
if (ip < info.Start + cs_start)
|
||||
p = info.action_table;
|
||||
else if (ip < info.Start + cs_start + cs_len)
|
||||
{
|
||||
if (cs_lp)
|
||||
landing_pad = info.LPStart + cs_lp;
|
||||
if (cs_action)
|
||||
action_record = info.action_table + cs_action - 1;
|
||||
goto found_something;
|
||||
}
|
||||
}
|
||||
#endif // _GLIBCPP_SJLJ_EXCEPTIONS
|
||||
|
||||
// If ip is not present in the table, call terminate. This is for
|
||||
// a destructor inside a cleanup, or a library routine the compiler
|
||||
// was not expecting to throw.
|
||||
found_type = (actions & _UA_FORCE_UNWIND ? found_nothing : found_terminate);
|
||||
goto do_something;
|
||||
|
||||
found_something:
|
||||
if (landing_pad == 0)
|
||||
{
|
||||
// If ip is present, and has a null landing pad, there are
|
||||
// no cleanups or handlers to be run.
|
||||
found_type = found_nothing;
|
||||
}
|
||||
else if (action_record == 0)
|
||||
{
|
||||
// If ip is present, has a non-null landing pad, and a null
|
||||
// action table offset, then there are only cleanups present.
|
||||
// Cleanups use a zero switch value, as set above.
|
||||
found_type = found_cleanup;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise we have a catch handler or exception specification.
|
||||
|
||||
signed long ar_filter, ar_disp;
|
||||
const std::type_info *throw_type, *catch_type;
|
||||
bool saw_cleanup = false;
|
||||
bool saw_handler = false;
|
||||
|
||||
// During forced unwinding, we only run cleanups. With a foreign
|
||||
// exception class, there's no exception type.
|
||||
// ??? What to do about GNU Java and GNU Ada exceptions.
|
||||
|
||||
if ((actions & _UA_FORCE_UNWIND)
|
||||
|| exception_class != __gxx_exception_class)
|
||||
throw_type = 0;
|
||||
else
|
||||
throw_type = xh->exceptionType;
|
||||
|
||||
while (1)
|
||||
{
|
||||
_Unwind_Ptr tmp;
|
||||
|
||||
p = action_record;
|
||||
p = read_sleb128 (p, &tmp); ar_filter = tmp;
|
||||
read_sleb128 (p, &tmp); ar_disp = tmp;
|
||||
|
||||
if (ar_filter == 0)
|
||||
{
|
||||
// Zero filter values are cleanups.
|
||||
saw_cleanup = true;
|
||||
}
|
||||
else if (ar_filter > 0)
|
||||
{
|
||||
// Positive filter values are handlers.
|
||||
catch_type = get_ttype_entry (context, &info, ar_filter);
|
||||
adjusted_ptr = xh + 1;
|
||||
|
||||
// Null catch type is a catch-all handler. We can catch
|
||||
// foreign exceptions with this.
|
||||
if (! catch_type)
|
||||
{
|
||||
if (!(actions & _UA_FORCE_UNWIND))
|
||||
{
|
||||
saw_handler = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (throw_type)
|
||||
{
|
||||
// Pointer types need to adjust the actual pointer, not
|
||||
// the pointer to pointer that is the exception object.
|
||||
// This also has the effect of passing pointer types
|
||||
// "by value" through the __cxa_begin_catch return value.
|
||||
if (throw_type->__is_pointer_p ())
|
||||
adjusted_ptr = *(void **) adjusted_ptr;
|
||||
|
||||
if (catch_type->__do_catch (throw_type, &adjusted_ptr, 1))
|
||||
{
|
||||
saw_handler = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Negative filter values are exception specifications.
|
||||
// ??? How do foreign exceptions fit in? As far as I can
|
||||
// see we can't match because there's no __cxa_exception
|
||||
// object to stuff bits in for __cxa_call_unexpected to use.
|
||||
if (throw_type
|
||||
&& ! check_exception_spec (context, &info, throw_type,
|
||||
ar_filter))
|
||||
{
|
||||
saw_handler = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ar_disp == 0)
|
||||
break;
|
||||
action_record = p + ar_disp;
|
||||
}
|
||||
|
||||
if (saw_handler)
|
||||
{
|
||||
handler_switch_value = ar_filter;
|
||||
found_type = found_handler;
|
||||
}
|
||||
else
|
||||
found_type = (saw_cleanup ? found_cleanup : found_nothing);
|
||||
}
|
||||
|
||||
do_something:
|
||||
if (found_type == found_nothing)
|
||||
return _URC_CONTINUE_UNWIND;
|
||||
|
||||
if (actions & _UA_SEARCH_PHASE)
|
||||
{
|
||||
if (found_type == found_cleanup)
|
||||
return _URC_CONTINUE_UNWIND;
|
||||
|
||||
// For domestic exceptions, we cache data from phase 1 for phase 2.
|
||||
if (exception_class == __gxx_exception_class)
|
||||
{
|
||||
xh->handlerSwitchValue = handler_switch_value;
|
||||
xh->actionRecord = action_record;
|
||||
xh->languageSpecificData = language_specific_data;
|
||||
xh->adjustedPtr = adjusted_ptr;
|
||||
|
||||
// ??? Completely unknown what this field is supposed to be for.
|
||||
// ??? Need to cache TType encoding base for call_unexpected.
|
||||
xh->catchTemp = (void *) (_Unwind_Ptr) landing_pad;
|
||||
}
|
||||
return _URC_HANDLER_FOUND;
|
||||
}
|
||||
|
||||
install_context:
|
||||
if (found_type == found_terminate)
|
||||
{
|
||||
__cxa_begin_catch (&xh->unwindHeader);
|
||||
__terminate (xh->terminateHandler);
|
||||
}
|
||||
|
||||
_Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
|
||||
(_Unwind_Ptr) &xh->unwindHeader);
|
||||
_Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
|
||||
handler_switch_value);
|
||||
_Unwind_SetIP (context, landing_pad);
|
||||
return _URC_INSTALL_CONTEXT;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
__cxa_call_unexpected (_Unwind_Exception *exc_obj)
|
||||
{
|
||||
__cxa_begin_catch (exc_obj);
|
||||
|
||||
// This function is a handler for our exception argument. If we exit
|
||||
// by throwing a different exception, we'll need the original cleaned up.
|
||||
struct end_catch_protect
|
||||
{
|
||||
end_catch_protect() { }
|
||||
~end_catch_protect() { __cxa_end_catch(); }
|
||||
} end_catch_protect_obj;
|
||||
|
||||
__cxa_exception *xh = __get_exception_header_from_ue (exc_obj);
|
||||
|
||||
try {
|
||||
__unexpected (xh->unexpectedHandler);
|
||||
} catch (...) {
|
||||
// Get the exception thrown from unexpected.
|
||||
// ??? Foreign exceptions can't be stacked this way.
|
||||
|
||||
__cxa_eh_globals *globals = __cxa_get_globals_fast ();
|
||||
__cxa_exception *new_xh = globals->caughtExceptions;
|
||||
|
||||
// We don't quite have enough stuff cached; re-parse the LSDA.
|
||||
lsda_header_info info;
|
||||
parse_lsda_header (0, xh->languageSpecificData, &info);
|
||||
|
||||
// If this new exception meets the exception spec, allow it.
|
||||
if (check_exception_spec (0, &info, new_xh->exceptionType,
|
||||
xh->handlerSwitchValue))
|
||||
throw;
|
||||
|
||||
// If the exception spec allows std::bad_exception, throw that.
|
||||
const std::type_info &bad_exc = typeid (std::bad_exception);
|
||||
if (check_exception_spec (0, &info, &bad_exc, xh->handlerSwitchValue))
|
||||
throw std::bad_exception ();
|
||||
|
||||
// Otherwise, die.
|
||||
__terminate(xh->terminateHandler);
|
||||
}
|
||||
}
|
87
libstdc++-v3/libsupc++/eh_terminate.cc
Normal file
87
libstdc++-v3/libsupc++/eh_terminate.cc
Normal file
@ -0,0 +1,87 @@
|
||||
// -*- C++ -*- std::terminate, std::unexpected and friends.
|
||||
// Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
|
||||
// Free Software Foundation
|
||||
//
|
||||
// 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.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
#include "typeinfo"
|
||||
#include "exception"
|
||||
#include <cstdlib>
|
||||
#include "unwind-cxx.h"
|
||||
#include "exception_defines.h"
|
||||
|
||||
using namespace __cxxabiv1;
|
||||
|
||||
/* The current installed user handlers. */
|
||||
std::terminate_handler __cxxabiv1::__terminate_handler = abort;
|
||||
std::unexpected_handler __cxxabiv1::__unexpected_handler = std::terminate;
|
||||
|
||||
void
|
||||
__cxxabiv1::__terminate (std::terminate_handler handler)
|
||||
{
|
||||
try {
|
||||
handler ();
|
||||
abort ();
|
||||
} catch (...) {
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
std::terminate ()
|
||||
{
|
||||
__terminate (__terminate_handler);
|
||||
}
|
||||
|
||||
void
|
||||
__cxxabiv1::__unexpected (std::unexpected_handler handler)
|
||||
{
|
||||
handler();
|
||||
std::terminate ();
|
||||
}
|
||||
|
||||
void
|
||||
std::unexpected ()
|
||||
{
|
||||
__unexpected (__unexpected_handler);
|
||||
}
|
||||
|
||||
std::terminate_handler
|
||||
std::set_terminate (std::terminate_handler func) throw()
|
||||
{
|
||||
std::terminate_handler old = __terminate_handler;
|
||||
__terminate_handler = func;
|
||||
return old;
|
||||
}
|
||||
|
||||
std::unexpected_handler
|
||||
std::set_unexpected (std::unexpected_handler func) throw()
|
||||
{
|
||||
std::unexpected_handler old = __unexpected_handler;
|
||||
__unexpected_handler = func;
|
||||
return old;
|
||||
}
|
102
libstdc++-v3/libsupc++/eh_throw.cc
Normal file
102
libstdc++-v3/libsupc++/eh_throw.cc
Normal file
@ -0,0 +1,102 @@
|
||||
// -*- C++ -*- Exception handling routines for throwing.
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
|
||||
#include <bits/c++config.h>
|
||||
#include "unwind-cxx.h"
|
||||
|
||||
|
||||
using namespace __cxxabiv1;
|
||||
|
||||
|
||||
static void
|
||||
__gxx_exception_cleanup (_Unwind_Reason_Code code, _Unwind_Exception *exc)
|
||||
{
|
||||
__cxa_exception *header = __get_exception_header_from_ue (exc);
|
||||
|
||||
// If we havn't been caught by a foreign handler, then this is
|
||||
// some sort of unwind error. In that case just die immediately.
|
||||
if (code != _URC_FOREIGN_EXCEPTION_CAUGHT)
|
||||
__terminate (header->terminateHandler);
|
||||
|
||||
if (header->exceptionDestructor)
|
||||
header->exceptionDestructor (header + 1);
|
||||
|
||||
__cxa_free_exception (header + 1);
|
||||
}
|
||||
|
||||
|
||||
extern "C" void
|
||||
__cxa_throw (void *obj, std::type_info *tinfo, void (*dest) (void *))
|
||||
{
|
||||
__cxa_exception *header = __get_exception_header_from_obj (obj);
|
||||
header->exceptionType = tinfo;
|
||||
header->exceptionDestructor = dest;
|
||||
header->unexpectedHandler = __unexpected_handler;
|
||||
header->terminateHandler = __terminate_handler;
|
||||
header->unwindHeader.exception_class = __gxx_exception_class;
|
||||
header->unwindHeader.exception_cleanup = __gxx_exception_cleanup;
|
||||
|
||||
__cxa_eh_globals *globals = __cxa_get_globals ();
|
||||
globals->uncaughtExceptions += 1;
|
||||
|
||||
#ifdef _GLIBCPP_SJLJ_EXCEPTIONS
|
||||
_Unwind_SjLj_RaiseException (&header->unwindHeader);
|
||||
#else
|
||||
_Unwind_RaiseException (&header->unwindHeader);
|
||||
#endif
|
||||
|
||||
// Some sort of unwinding error. Note that terminate is a handler.
|
||||
__cxa_begin_catch (&header->unwindHeader);
|
||||
std::terminate ();
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
__cxa_rethrow ()
|
||||
{
|
||||
__cxa_eh_globals *globals = __cxa_get_globals ();
|
||||
__cxa_exception *header = globals->caughtExceptions;
|
||||
|
||||
// Watch for luser rethrowing with no active exception.
|
||||
if (header)
|
||||
{
|
||||
// Tell __cxa_end_catch this is a rethrow.
|
||||
header->handlerCount = -header->handlerCount;
|
||||
|
||||
#ifdef _GLIBCPP_SJLJ_EXCEPTIONS
|
||||
_Unwind_SjLj_RaiseException (&header->unwindHeader);
|
||||
#else
|
||||
_Unwind_RaiseException (&header->unwindHeader);
|
||||
#endif
|
||||
|
||||
// Some sort of unwinding error. Note that terminate is a handler.
|
||||
__cxa_begin_catch (&header->unwindHeader);
|
||||
}
|
||||
std::terminate ();
|
||||
}
|
@ -1,388 +0,0 @@
|
||||
// Functions for Exception Support for -*- C++ -*-
|
||||
|
||||
// Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
|
||||
// Free Software Foundation
|
||||
//
|
||||
// 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.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
#include "typeinfo"
|
||||
#include "exception"
|
||||
#include <cstddef>
|
||||
#include "exception_support.h"
|
||||
#include "exception_defines.h"
|
||||
|
||||
/* Define terminate, unexpected, set_terminate, set_unexpected as
|
||||
well as the default terminate func and default unexpected func. */
|
||||
|
||||
/* __terminate and __terminate_set_func, defined in libgcc2. */
|
||||
typedef void (*__terminate_func_ptr)(void) __attribute__ ((__noreturn__));
|
||||
extern "C" void __terminate (void) __attribute__ ((__noreturn__));
|
||||
extern "C" __terminate_func_ptr __terminate_set_func (__terminate_func_ptr);
|
||||
|
||||
using std::terminate;
|
||||
|
||||
void
|
||||
std::terminate ()
|
||||
{
|
||||
__terminate ();
|
||||
}
|
||||
|
||||
void
|
||||
__default_unexpected ()
|
||||
{
|
||||
terminate ();
|
||||
}
|
||||
|
||||
static std::unexpected_handler __unexpected_func __attribute__((__noreturn__))
|
||||
= __default_unexpected;
|
||||
|
||||
std::terminate_handler
|
||||
std::set_terminate (std::terminate_handler func) throw()
|
||||
{
|
||||
return __terminate_set_func (func);
|
||||
}
|
||||
|
||||
std::unexpected_handler
|
||||
std::set_unexpected (std::unexpected_handler func) throw()
|
||||
{
|
||||
std::unexpected_handler old = __unexpected_func;
|
||||
|
||||
__unexpected_func = func;
|
||||
return old;
|
||||
}
|
||||
|
||||
void
|
||||
std::unexpected ()
|
||||
{
|
||||
__unexpected_func ();
|
||||
}
|
||||
|
||||
/* Language-specific EH info pointer, defined in libgcc2. */
|
||||
extern "C" cp_eh_info **__get_eh_info (); // actually void **
|
||||
#define CP_EH_INFO ((cp_eh_info *) *__get_eh_info ())
|
||||
|
||||
/* Exception allocate and free, defined in libgcc2. */
|
||||
extern "C" void *__eh_alloc(std::size_t);
|
||||
extern "C" void __eh_free(void *);
|
||||
|
||||
/* Is P the type_info node for a pointer of some kind? */
|
||||
extern bool __is_pointer (void *);
|
||||
|
||||
|
||||
#ifdef __EXCEPTIONS
|
||||
/* OLD Compiler hook to return a pointer to the info for the current exception.
|
||||
Used by get_eh_info (). This fudges the actualy returned value to
|
||||
point to the beginning of what USE to be the cp_eh_info structure.
|
||||
THis is so that old code that dereferences this pointer will find
|
||||
things where it expects it to be.*/
|
||||
extern "C" void *
|
||||
__cp_exception_info (void)
|
||||
{
|
||||
return &((*__get_eh_info ())->value);
|
||||
}
|
||||
|
||||
/* Old Compiler hook to return a pointer to the info for the current exception.
|
||||
Used by get_eh_info (). */
|
||||
|
||||
extern "C" cp_eh_info *
|
||||
__cp_eh_info (void)
|
||||
{
|
||||
cp_eh_info *p = CP_EH_INFO;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Compiler hook to return a pointer to the info for the current exception,
|
||||
Set the caught bit, and increment the number of handlers that are
|
||||
looking at this exception. This makes handlers smaller. */
|
||||
|
||||
extern "C" cp_eh_info *
|
||||
__start_cp_handler (void)
|
||||
{
|
||||
cp_eh_info *p = CP_EH_INFO;
|
||||
p->caught = 1;
|
||||
p->handlers++;
|
||||
return p;
|
||||
}
|
||||
|
||||
extern "C" int __throw_type_match_rtti_2 (const void *, const void *,
|
||||
void *, void **);
|
||||
|
||||
extern "C" void *
|
||||
__cplus_type_matcher (__eh_info *info_, void *match_info,
|
||||
exception_descriptor *exception_table)
|
||||
{
|
||||
cp_eh_info *info = (cp_eh_info *)info_;
|
||||
|
||||
/* No exception table implies the old style mechanism, so don't check. */
|
||||
if (exception_table != NULL
|
||||
&& exception_table->lang.language != EH_LANG_C_plus_plus)
|
||||
return NULL;
|
||||
|
||||
if (match_info == CATCH_ALL_TYPE)
|
||||
return (void *)1;
|
||||
|
||||
/* we don't worry about version info yet, there is only one version! */
|
||||
|
||||
void *match_type = match_info;
|
||||
|
||||
if (__throw_type_match_rtti_2 (match_type, info->type,
|
||||
info->original_value, &info->value))
|
||||
// Arbitrary non-null pointer.
|
||||
return (void *)1;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Compiler hook to push a new exception onto the stack.
|
||||
Used by expand_throw(). */
|
||||
|
||||
extern "C" void
|
||||
__cp_push_exception (void *value, void *type, cleanup_fn cleanup)
|
||||
{
|
||||
cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info));
|
||||
|
||||
p->value = value;
|
||||
p->type = type;
|
||||
p->cleanup = cleanup;
|
||||
p->handlers = 0;
|
||||
p->caught = false;
|
||||
p->original_value = value;
|
||||
|
||||
p->eh_info.match_function = __cplus_type_matcher;
|
||||
p->eh_info.language = EH_LANG_C_plus_plus;
|
||||
p->eh_info.version = 1;
|
||||
|
||||
cp_eh_info **q = __get_eh_info ();
|
||||
|
||||
p->next = *q;
|
||||
*q = p;
|
||||
}
|
||||
|
||||
/* Compiler hook to pop an exception that has been finalized. Used by
|
||||
push_eh_cleanup(). P is the info for the exception caught by the
|
||||
current catch block. */
|
||||
|
||||
extern "C" void
|
||||
__cp_pop_exception (void* p_)
|
||||
{
|
||||
cp_eh_info *p = static_cast <cp_eh_info *> (p_);
|
||||
cp_eh_info **stack = __get_eh_info ();
|
||||
cp_eh_info **q = stack;
|
||||
|
||||
--p->handlers;
|
||||
|
||||
/* Do nothing if our exception is being rethrown (i.e. if the active
|
||||
exception is our exception and it is uncaught). */
|
||||
if (p == *q && !p->caught)
|
||||
return;
|
||||
|
||||
/* Don't really pop if there are still active handlers for our exception;
|
||||
rather, push it down past any uncaught exceptions. */
|
||||
if (p->handlers != 0)
|
||||
{
|
||||
if (p == *q && p->next && !p->next->caught)
|
||||
{
|
||||
q = &(p->next);
|
||||
while (1)
|
||||
{
|
||||
if (*q == 0 || (*q)->caught)
|
||||
break;
|
||||
|
||||
q = &((*q)->next);
|
||||
}
|
||||
*stack = p->next;
|
||||
p->next = *q;
|
||||
*q = p;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (; *q; q = &((*q)->next))
|
||||
if (*q == p)
|
||||
break;
|
||||
|
||||
if (! *q)
|
||||
terminate ();
|
||||
|
||||
*q = p->next;
|
||||
|
||||
if (p->cleanup)
|
||||
// value may have been adjusted.
|
||||
CALL_CLEANUP (p->cleanup, p->original_value);
|
||||
|
||||
if (! __is_pointer (p->type))
|
||||
__eh_free (p->original_value); // value may have been adjusted.
|
||||
|
||||
__eh_free (p);
|
||||
}
|
||||
|
||||
/* We're doing a rethrow. Find the currently handled exception, mark it
|
||||
uncaught, and move it to the top of the EH stack. */
|
||||
|
||||
extern "C" cp_eh_info *
|
||||
__uncatch_exception (void)
|
||||
{
|
||||
cp_eh_info **stack = __get_eh_info ();
|
||||
cp_eh_info **q = stack;
|
||||
cp_eh_info *p;
|
||||
|
||||
while (1)
|
||||
{
|
||||
p = *q;
|
||||
|
||||
if (p == 0)
|
||||
terminate ();
|
||||
if (p->caught)
|
||||
break;
|
||||
|
||||
q = &(p->next);
|
||||
}
|
||||
|
||||
if (q != stack)
|
||||
{
|
||||
*q = p->next;
|
||||
p->next = *stack;
|
||||
*stack = p;
|
||||
}
|
||||
|
||||
p->caught = false;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Mark P as caught after we previously marked it as uncaught. */
|
||||
|
||||
extern "C" void
|
||||
__recatch_exception (cp_eh_info *p)
|
||||
{
|
||||
p->caught = true;
|
||||
}
|
||||
|
||||
/* As per [except.unexpected]:
|
||||
If an exception is thrown, we check it against the spec. If it doesn't
|
||||
match, we call unexpected (). If unexpected () throws, we check that
|
||||
exception against the spec. If it doesn't match, if the spec allows
|
||||
bad_exception we throw that; otherwise we call terminate ().
|
||||
|
||||
The compiler treats an exception spec as a try block with a generic
|
||||
handler that just calls this function with a list of the allowed
|
||||
exception types, so we have an active exception that can be rethrown.
|
||||
|
||||
This function does not return. */
|
||||
|
||||
extern "C" void
|
||||
__check_eh_spec (int n, const void **spec)
|
||||
{
|
||||
cp_eh_info *p = CP_EH_INFO;
|
||||
void *d;
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (__throw_type_match_rtti_2 (spec[i], p->type, p->value, &d))
|
||||
throw;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
std::unexpected ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// __exception_info is an artificial var pushed into each catch block.
|
||||
if (p != __exception_info)
|
||||
{
|
||||
p = __exception_info;
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (__throw_type_match_rtti_2 (spec[i], p->type, p->value, &d))
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
const std::type_info &bad_exc = typeid (std::bad_exception);
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (__throw_type_match_rtti_2 (spec[i], &bad_exc, p->value, &d))
|
||||
throw std::bad_exception ();
|
||||
}
|
||||
|
||||
terminate ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Special case of the above for throw() specs. */
|
||||
|
||||
extern "C" void
|
||||
__check_null_eh_spec (void)
|
||||
{
|
||||
__check_eh_spec (0, 0);
|
||||
}
|
||||
#endif //__EXCEPTIONS
|
||||
|
||||
// Helpers for rtti. Although these don't return, we give them return types so
|
||||
// that the type system is not broken.
|
||||
extern "C" void *
|
||||
__cxa_bad_cast ()
|
||||
{
|
||||
#ifdef __EXCEPTIONS
|
||||
throw std::bad_cast();
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" std::type_info const &
|
||||
__cxa_bad_typeid ()
|
||||
{
|
||||
#ifdef __EXCEPTIONS
|
||||
throw std::bad_typeid();
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
return typeid (void);
|
||||
}
|
||||
|
||||
/* Has the current exception been caught? */
|
||||
bool
|
||||
std::uncaught_exception() throw()
|
||||
{
|
||||
cp_eh_info *p = CP_EH_INFO;
|
||||
return p && ! p->caught;
|
||||
}
|
||||
|
||||
std::exception::~exception() throw() { }
|
||||
|
||||
std::bad_exception::~bad_exception() throw() { }
|
||||
|
||||
const char*
|
||||
std::exception::what() const throw()
|
||||
{ return typeid (*this).name (); }
|
||||
|
||||
|
||||
|
||||
|
@ -1,65 +0,0 @@
|
||||
// Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
#include "gansidecl.h" /* Needed to support macros used in eh-common.h. */
|
||||
#include "eh-common.h"
|
||||
|
||||
/* The type of a function called to clean up an exception object.
|
||||
(These will be destructors.) Under the old ABI, these take a
|
||||
second argument (the `in-charge' argument), that indicates whether
|
||||
or not do delete the object, and whether or not to destroy virtual
|
||||
bases. Under the new ABI, there is no second argument. */
|
||||
#if !defined (__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
|
||||
typedef void (*cleanup_fn)(void *, int);
|
||||
/* The `2' is the value for the in-charge parameter that indicates
|
||||
that virtual bases should be destroyed. */
|
||||
#define CALL_CLEANUP(FN, THIS) FN (THIS, 2)
|
||||
#else
|
||||
typedef void (*cleanup_fn)(void *);
|
||||
#define CALL_CLEANUP(FN, THIS) FN (THIS)
|
||||
#endif
|
||||
|
||||
/* C++-specific state about the current exception. This must match
|
||||
init_exception_processing().
|
||||
|
||||
Note that handlers and caught are not redundant; when rethrown, an
|
||||
exception can have multiple active handlers and still be considered
|
||||
uncaught. */
|
||||
|
||||
struct cp_eh_info
|
||||
{
|
||||
__eh_info eh_info;
|
||||
void *value;
|
||||
void *type;
|
||||
cleanup_fn cleanup;
|
||||
bool caught;
|
||||
cp_eh_info *next;
|
||||
long handlers;
|
||||
void *original_value;
|
||||
};
|
||||
|
||||
extern "C" cp_eh_info *__uncatch_exception (void);
|
||||
extern "C" void __recatch_exception (cp_eh_info *);
|
@ -28,6 +28,7 @@
|
||||
// the GNU General Public License.
|
||||
|
||||
#include <bits/c++config.h>
|
||||
#include "unwind-cxx.h"
|
||||
|
||||
#ifdef _GLIBCPP_HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
@ -42,15 +43,9 @@
|
||||
# define writestr(str) fputs(str, stderr)
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern void __terminate(void) __attribute__ ((__noreturn__));
|
||||
|
||||
void
|
||||
extern "C" void
|
||||
__cxa_pure_virtual (void)
|
||||
{
|
||||
writestr ("pure virtual method called\n");
|
||||
__terminate ();
|
||||
}
|
||||
|
||||
std::terminate ();
|
||||
}
|
||||
|
@ -165,31 +165,3 @@ __pointer_catch (const __pbase_type_info *thr_type,
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
// Entry points for the compiler.
|
||||
|
||||
/* Low level match routine used by compiler to match types of catch
|
||||
variables and thrown objects. */
|
||||
|
||||
extern "C" int
|
||||
__throw_type_match_rtti_2 (const void *catch_type_r, const void *throw_type_r,
|
||||
void *objptr, void **valp)
|
||||
{
|
||||
const type_info &catch_type = *(const type_info *)catch_type_r;
|
||||
const type_info &throw_type = *(const type_info *)throw_type_r;
|
||||
|
||||
*valp = objptr;
|
||||
|
||||
return catch_type.__do_catch (&throw_type, valp, 1);
|
||||
}
|
||||
|
||||
/* Called from __cp_pop_exception. Is P the type_info node for a pointer
|
||||
of some kind? */
|
||||
|
||||
bool
|
||||
__is_pointer (void *p)
|
||||
{
|
||||
const type_info *t = reinterpret_cast <const type_info *>(p);
|
||||
return t->__is_pointer_p ();
|
||||
}
|
||||
|
||||
|
163
libstdc++-v3/libsupc++/unwind-cxx.h
Normal file
163
libstdc++-v3/libsupc++/unwind-cxx.h
Normal file
@ -0,0 +1,163 @@
|
||||
// -*- C++ -*- Exception handling and frame unwind runtime interface routines.
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This is derived from the C++ ABI for IA-64. Where we diverge
|
||||
// for cross-architecture compatibility are noted with "@@@".
|
||||
|
||||
#ifndef __UNWIND_CXX_H
|
||||
#define __UNWIND_CXX_H 1
|
||||
|
||||
// Level 2: C++ ABI
|
||||
|
||||
#include <typeinfo>
|
||||
#include <exception>
|
||||
#include <cstddef>
|
||||
#include "unwind.h"
|
||||
|
||||
namespace __cxxabiv1
|
||||
{
|
||||
|
||||
// A C++ exception object consists of a header, which is a wrapper around
|
||||
// an unwind object header with additional C++ specific information,
|
||||
// followed by the exception object itself.
|
||||
|
||||
struct __cxa_exception
|
||||
{
|
||||
// Manage the exception object itself.
|
||||
std::type_info *exceptionType;
|
||||
void (*exceptionDestructor)(void *);
|
||||
|
||||
// The C++ standard has entertaining rules wrt calling set_terminate
|
||||
// and set_unexpected in the middle of the exception cleanup process.
|
||||
std::unexpected_handler unexpectedHandler;
|
||||
std::terminate_handler terminateHandler;
|
||||
|
||||
// The caught exception stack threads through here.
|
||||
__cxa_exception *nextException;
|
||||
|
||||
// How many nested handlers have caught this exception. A negated
|
||||
// value is a signal that this object has been rethrown.
|
||||
int handlerCount;
|
||||
|
||||
// Cache parsed handler data from the personality routine Phase 1
|
||||
// for Phase 2 and __cxa_call_unexpected.
|
||||
int handlerSwitchValue;
|
||||
const unsigned char *actionRecord;
|
||||
const unsigned char *languageSpecificData;
|
||||
void *catchTemp;
|
||||
void *adjustedPtr;
|
||||
|
||||
// The generic exception header. Must be last.
|
||||
_Unwind_Exception unwindHeader;
|
||||
};
|
||||
|
||||
// Each thread in a C++ program has access to a __cxa_eh_globals object.
|
||||
struct __cxa_eh_globals
|
||||
{
|
||||
__cxa_exception *caughtExceptions;
|
||||
unsigned int uncaughtExceptions;
|
||||
};
|
||||
|
||||
|
||||
// The __cxa_eh_globals for the current thread can be obtained by using
|
||||
// either of the following functions. The "fast" version assumes at least
|
||||
// one prior call of __cxa_get_globals has been made from the current
|
||||
// thread, so no initialization is necessary.
|
||||
extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
|
||||
extern "C" __cxa_eh_globals *__cxa_get_globals_fast () throw();
|
||||
|
||||
// Allocate memory for the exception plus the thown object.
|
||||
extern "C" void *__cxa_allocate_exception(std::size_t thrown_size) throw();
|
||||
|
||||
// Free the space allocated for the exception.
|
||||
extern "C" void __cxa_free_exception(void *thrown_exception) throw();
|
||||
|
||||
// Throw the exception.
|
||||
extern "C" void __cxa_throw (void *thrown_exception,
|
||||
std::type_info *tinfo,
|
||||
void (*dest) (void *))
|
||||
__attribute__((noreturn));
|
||||
|
||||
// Used to implement exception handlers.
|
||||
extern "C" void *__cxa_begin_catch (_Unwind_Exception *) throw();
|
||||
extern "C" void __cxa_end_catch ();
|
||||
extern "C" void __cxa_rethrow () __attribute__((noreturn));
|
||||
|
||||
// These facilitate code generation for recurring situations.
|
||||
extern "C" void __cxa_bad_cast ();
|
||||
extern "C" void __cxa_bad_typeid ();
|
||||
|
||||
// @@@ These are not directly specified by the IA-64 C++ ABI.
|
||||
|
||||
// Handles re-checking the exception specification if unexpectedHandler
|
||||
// throws, and if bad_exception needs to be thrown. Called from the
|
||||
// compiler.
|
||||
extern "C" void __cxa_call_unexpected (_Unwind_Exception *)
|
||||
__attribute__((noreturn));
|
||||
|
||||
// Invokes given handler, dying appropriately if the user handler was
|
||||
// so inconsiderate as to return.
|
||||
extern void __terminate(std::terminate_handler) __attribute__((noreturn));
|
||||
extern void __unexpected(std::unexpected_handler) __attribute__((noreturn));
|
||||
|
||||
// The current installed user handlers.
|
||||
extern std::terminate_handler __terminate_handler;
|
||||
extern std::unexpected_handler __unexpected_handler;
|
||||
|
||||
// These are explicitly GNU C++ specific.
|
||||
|
||||
// This is the exception class we report -- "GNUCC++\0".
|
||||
const _Unwind_Exception_Class __gxx_exception_class
|
||||
= ((((((((_Unwind_Exception_Class) 'G'
|
||||
<< 8 | (_Unwind_Exception_Class) 'N')
|
||||
<< 8 | (_Unwind_Exception_Class) 'U')
|
||||
<< 8 | (_Unwind_Exception_Class) 'C')
|
||||
<< 8 | (_Unwind_Exception_Class) 'C')
|
||||
<< 8 | (_Unwind_Exception_Class) '+')
|
||||
<< 8 | (_Unwind_Exception_Class) '+')
|
||||
<< 8 | (_Unwind_Exception_Class) '\0');
|
||||
|
||||
// GNU C++ personality routine, Version 0.
|
||||
extern "C" _Unwind_Reason_Code __gxx_personality_v0
|
||||
(int, _Unwind_Action, _Unwind_Exception_Class,
|
||||
struct _Unwind_Exception *, struct _Unwind_Context *);
|
||||
|
||||
// GNU C++ sjlj personality routine, Version 0.
|
||||
extern "C" _Unwind_Reason_Code __gxx_personality_sj0
|
||||
(int, _Unwind_Action, _Unwind_Exception_Class,
|
||||
struct _Unwind_Exception *, struct _Unwind_Context *);
|
||||
|
||||
// Acquire the C++ exception header from the C++ object.
|
||||
static inline __cxa_exception *
|
||||
__get_exception_header_from_obj (void *ptr)
|
||||
{
|
||||
return reinterpret_cast<__cxa_exception *>(ptr) - 1;
|
||||
}
|
||||
|
||||
// Acquire the C++ exception header from the generic exception header.
|
||||
static inline __cxa_exception *
|
||||
__get_exception_header_from_ue (_Unwind_Exception *exc)
|
||||
{
|
||||
return reinterpret_cast<__cxa_exception *>(exc + 1) - 1;
|
||||
}
|
||||
|
||||
} /* namespace __cxxabiv1 */
|
||||
|
||||
#endif // __UNWIND_CXX_H
|
@ -35,7 +35,7 @@
|
||||
#include <exception>
|
||||
#include <exception_defines.h>
|
||||
|
||||
#include "exception_support.h"
|
||||
#include "unwind-cxx.h"
|
||||
|
||||
namespace __cxxabiv1
|
||||
{
|
||||
@ -43,11 +43,21 @@ namespace __cxxabiv1
|
||||
{
|
||||
struct uncatch_exception
|
||||
{
|
||||
uncatch_exception () { p = __uncatch_exception (); }
|
||||
~uncatch_exception () { __recatch_exception (p); }
|
||||
uncatch_exception ();
|
||||
~uncatch_exception () { __cxa_begin_catch (&p->unwindHeader); }
|
||||
|
||||
cp_eh_info *p;
|
||||
__cxa_exception *p;
|
||||
};
|
||||
|
||||
uncatch_exception::uncatch_exception ()
|
||||
{
|
||||
__cxa_eh_globals *globals = __cxa_get_globals_fast ();
|
||||
|
||||
p = globals->caughtExceptions;
|
||||
p->handlerCount -= 1;
|
||||
globals->caughtExceptions = p->nextException;
|
||||
globals->uncaughtExceptions += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate and construct array.
|
||||
|
@ -120,13 +120,11 @@ OPTIMIZE_CXXFLAGS = @OPTIMIZE_CXXFLAGS@
|
||||
# These bits are all figured out from configure. Look in acinclude.m4
|
||||
# or configure.in to see how they are set. See GLIBCPP_EXPORT_FLAGS
|
||||
# NB: DEBUGFLAGS have to be at the end so that -O2 can be overridden.
|
||||
CONFIG_CXXFLAGS = \
|
||||
@EXTRA_CXX_FLAGS@ @SECTION_FLAGS@ @CSHADOW_FLAGS@ @DEBUG_FLAGS@
|
||||
CONFIG_CXXFLAGS = @EXTRA_CXX_FLAGS@ @SECTION_FLAGS@ @CSHADOW_FLAGS@ @DEBUG_FLAGS@
|
||||
|
||||
|
||||
# Warning flags to use.
|
||||
WARN_CXXFLAGS = \
|
||||
@WARN_FLAGS@ $(WERROR) -fdiagnostics-show-location=once
|
||||
WARN_CXXFLAGS = @WARN_FLAGS@ $(WERROR) -fdiagnostics-show-location=once
|
||||
|
||||
|
||||
# Use common includes from acinclude.m4/GLIBCPP_EXPORT_INCLUDES
|
||||
@ -138,133 +136,44 @@ LIBSUPCXX_INCLUDES = @LIBSUPCXX_INCLUDES@
|
||||
LIBIO_INCLUDES = @LIBIO_INCLUDES@
|
||||
TOPLEVEL_INCLUDES = @TOPLEVEL_INCLUDES@
|
||||
|
||||
INCLUDES = \
|
||||
-nostdinc++ \
|
||||
-I$(GLIBCPP_INCLUDE_DIR) $(CSTD_INCLUDES) -I$(top_builddir)/include \
|
||||
$(LIBSUPCXX_INCLUDES) $(LIBIO_INCLUDES) $(LIBMATH_INCLUDES) \
|
||||
$(TOPLEVEL_INCLUDES)
|
||||
INCLUDES = -nostdinc++ -I$(GLIBCPP_INCLUDE_DIR) $(CSTD_INCLUDES) -I$(top_builddir)/include $(LIBSUPCXX_INCLUDES) $(LIBIO_INCLUDES) $(LIBMATH_INCLUDES) $(TOPLEVEL_INCLUDES)
|
||||
|
||||
|
||||
base_headers = \
|
||||
bits/cpp_type_traits.h bits/char_traits.h bits/codecvt.h \
|
||||
bits/stringfwd.h bits/std_string.h bits/basic_string.h \
|
||||
bits/basic_string.tcc \
|
||||
bits/generic_shadow.h bits/std_utility.h \
|
||||
bits/std_complex.h \
|
||||
bits/valarray_array.h bits/valarray_array.tcc bits/valarray_meta.h \
|
||||
bits/std_valarray.h bits/mask_array.h bits/slice.h bits/slice_array.h \
|
||||
bits/gslice.h bits/gslice_array.h bits/indirect_array.h \
|
||||
bits/std_fstream.h bits/std_iomanip.h \
|
||||
bits/ios_base.h bits/fpos.h bits/basic_ios.h bits/basic_ios.tcc \
|
||||
bits/std_ios.h bits/std_iosfwd.h bits/std_iostream.h \
|
||||
bits/std_istream.h bits/istream.tcc bits/std_locale.h \
|
||||
bits/fstream.tcc bits/ostream.tcc bits/sbuf_iter.h bits/sstream.tcc \
|
||||
bits/std_ostream.h bits/std_sstream.h bits/std_streambuf.h \
|
||||
bits/streambuf.tcc bits/basic_file.h \
|
||||
bits/locale_facets.h bits/locale_facets.tcc bits/localefwd.h \
|
||||
bits/stl_pthread_alloc.h bits/pthread_allocimpl.h \
|
||||
bits/stl_threads.h bits/stl_iterator_base.h \
|
||||
bits/std_bitset.h bits/std_deque.h bits/std_functional.h \
|
||||
bits/std_iterator.h bits/std_list.h \
|
||||
bits/std_map.h bits/std_memory.h bits/std_numeric.h \
|
||||
bits/std_queue.h bits/std_set.h bits/std_stack.h \
|
||||
bits/std_stdexcept.h bits/functexcept.h bits/std_vector.h \
|
||||
bits/stl_algo.h bits/stl_algobase.h bits/stl_alloc.h \
|
||||
bits/stl_deque.h bits/stl_function.h \
|
||||
bits/stl_heap.h bits/stl_iterator.h bits/stl_list.h bits/stl_map.h \
|
||||
bits/stl_multimap.h bits/stl_multiset.h bits/stl_numeric.h \
|
||||
bits/stl_pair.h bits/stl_queue.h bits/stl_raw_storage_iter.h \
|
||||
bits/stl_relops.h bits/stl_set.h \
|
||||
bits/stl_stack.h bits/stl_tempbuf.h \
|
||||
bits/stl_tree.h bits/stl_uninitialized.h bits/stl_vector.h \
|
||||
bits/type_traits.h bits/std_algorithm.h \
|
||||
bits/concept_checks.h bits/container_concepts.h \
|
||||
bits/sequence_concepts.h bits/stl_construct.h
|
||||
base_headers = bits/cpp_type_traits.h bits/char_traits.h bits/codecvt.h bits/stringfwd.h bits/std_string.h bits/basic_string.h bits/basic_string.tcc bits/generic_shadow.h bits/std_utility.h bits/std_complex.h bits/valarray_array.h bits/valarray_array.tcc bits/valarray_meta.h bits/std_valarray.h bits/mask_array.h bits/slice.h bits/slice_array.h bits/gslice.h bits/gslice_array.h bits/indirect_array.h bits/std_fstream.h bits/std_iomanip.h bits/ios_base.h bits/fpos.h bits/basic_ios.h bits/basic_ios.tcc bits/std_ios.h bits/std_iosfwd.h bits/std_iostream.h bits/std_istream.h bits/istream.tcc bits/std_locale.h bits/fstream.tcc bits/ostream.tcc bits/sbuf_iter.h bits/sstream.tcc bits/std_ostream.h bits/std_sstream.h bits/std_streambuf.h bits/streambuf.tcc bits/basic_file.h bits/locale_facets.h bits/locale_facets.tcc bits/localefwd.h bits/stl_pthread_alloc.h bits/pthread_allocimpl.h bits/stl_threads.h bits/stl_iterator_base.h bits/std_bitset.h bits/std_deque.h bits/std_functional.h bits/std_iterator.h bits/std_list.h bits/std_map.h bits/std_memory.h bits/std_numeric.h bits/std_queue.h bits/std_set.h bits/std_stack.h bits/std_stdexcept.h bits/functexcept.h bits/std_vector.h bits/stl_algo.h bits/stl_algobase.h bits/stl_alloc.h bits/stl_deque.h bits/stl_function.h bits/stl_heap.h bits/stl_iterator.h bits/stl_list.h bits/stl_map.h bits/stl_multimap.h bits/stl_multiset.h bits/stl_numeric.h bits/stl_pair.h bits/stl_queue.h bits/stl_raw_storage_iter.h bits/stl_relops.h bits/stl_set.h bits/stl_stack.h bits/stl_tempbuf.h bits/stl_tree.h bits/stl_uninitialized.h bits/stl_vector.h bits/type_traits.h bits/std_algorithm.h bits/concept_checks.h bits/container_concepts.h bits/sequence_concepts.h bits/stl_construct.h
|
||||
|
||||
|
||||
backward_headers = \
|
||||
backward/complex.h backward/iomanip.h backward/istream.h \
|
||||
backward/ostream.h backward/stream.h backward/streambuf.h \
|
||||
backward/algo.h backward/algobase.h backward/alloc.h \
|
||||
backward/bvector.h backward/defalloc.h backward/deque.h \
|
||||
backward/function.h backward/hash_map.h backward/hash_set.h \
|
||||
backward/hashtable.h backward/heap.h backward/iterator.h \
|
||||
backward/list.h backward/map.h backward/multimap.h backward/new.h \
|
||||
backward/multiset.h backward/pair.h backward/iostream.h \
|
||||
backward/rope.h backward/set.h backward/slist.h backward/stack.h \
|
||||
backward/tempbuf.h backward/tree.h backward/vector.h \
|
||||
backward/fstream.h backward/strstream.h backward/strstream
|
||||
backward_headers = backward/complex.h backward/iomanip.h backward/istream.h backward/ostream.h backward/stream.h backward/streambuf.h backward/algo.h backward/algobase.h backward/alloc.h backward/bvector.h backward/defalloc.h backward/deque.h backward/function.h backward/hash_map.h backward/hash_set.h backward/hashtable.h backward/heap.h backward/iterator.h backward/list.h backward/map.h backward/multimap.h backward/new.h backward/multiset.h backward/pair.h backward/iostream.h backward/rope.h backward/set.h backward/slist.h backward/stack.h backward/tempbuf.h backward/tree.h backward/vector.h backward/fstream.h backward/strstream.h backward/strstream
|
||||
|
||||
|
||||
ext_headers = \
|
||||
ext/ropeimpl.h ext/stl_rope.h \
|
||||
ext/stl_bvector.h ext/stl_hashtable.h ext/stl_hash_fun.h \
|
||||
ext/hash_map ext/hash_set ext/rope ext/slist \
|
||||
ext/tree ext/bvector
|
||||
ext_headers = ext/ropeimpl.h ext/stl_rope.h ext/stl_bvector.h ext/stl_hashtable.h ext/stl_hash_fun.h ext/hash_map ext/hash_set ext/rope ext/slist ext/tree ext/bvector
|
||||
|
||||
|
||||
c_base_headers = \
|
||||
bits/std_cassert.h bits/std_cctype.h bits/std_cerrno.h \
|
||||
bits/std_cfloat.h bits/std_climits.h bits/std_clocale.h \
|
||||
bits/std_cmath.h bits/std_csetjmp.h bits/std_csignal.h \
|
||||
bits/std_cstdarg.h bits/std_cstddef.h bits/std_cstdio.h \
|
||||
bits/std_cstdlib.h bits/std_cstring.h bits/std_ctime.h \
|
||||
bits/std_cwchar.h bits/std_cwctype.h bits/cmath.tcc
|
||||
c_base_headers = bits/std_cassert.h bits/std_cctype.h bits/std_cerrno.h bits/std_cfloat.h bits/std_climits.h bits/std_clocale.h bits/std_cmath.h bits/std_csetjmp.h bits/std_csignal.h bits/std_cstdarg.h bits/std_cstddef.h bits/std_cstdio.h bits/std_cstdlib.h bits/std_cstring.h bits/std_ctime.h bits/std_cwchar.h bits/std_cwctype.h bits/cmath.tcc
|
||||
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@c_shadow_headers = @GLIBCPP_USE_CSHADOW_TRUE@\
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@ assert.h ctype.h errno.h float.h limits.h locale.h math.h setjmp.h \
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@ signal.h stdarg.h stddef.h stdio.h stdlib.h string.h time.h wchar.h \
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@ wctype.h fcntl.h libio.h iolibio.h libioP.h pthread.h iconv.h \
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@ features.h langinfo.h \
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@ bits/wrap_libio.h bits/wrap_iolibio.h bits/wrap_libioP.h \
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@ bits/wrap_iconv.h bits/wrap_fcntl.h bits/wrap_pthread.h \
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@ bits/wrap_features.h bits/wrap_langinfo.h \
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@ sys/cdefs.h
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@c_shadow_headers = assert.h ctype.h errno.h float.h limits.h locale.h math.h setjmp.h signal.h stdarg.h stddef.h stdio.h stdlib.h string.h time.h wchar.h wctype.h fcntl.h libio.h iolibio.h libioP.h pthread.h iconv.h features.h langinfo.h bits/wrap_libio.h bits/wrap_iolibio.h bits/wrap_libioP.h bits/wrap_iconv.h bits/wrap_fcntl.h bits/wrap_pthread.h bits/wrap_features.h bits/wrap_langinfo.h sys/cdefs.h
|
||||
@GLIBCPP_USE_CSHADOW_FALSE@c_shadow_headers =
|
||||
|
||||
std_headers = \
|
||||
algorithm bitset complex deque fstream functional \
|
||||
iomanip ios iosfwd iostream istream iterator limits list locale \
|
||||
map memory numeric ostream queue set sstream stack stdexcept \
|
||||
streambuf string utility valarray vector \
|
||||
cassert cctype cerrno cfloat climits clocale ciso646 \
|
||||
cmath csetjmp csignal cstdarg cstddef cstdio cstdlib \
|
||||
cstring ctime cwchar cwctype
|
||||
std_headers = algorithm bitset complex deque fstream functional iomanip ios iosfwd iostream istream iterator limits list locale map memory numeric ostream queue set sstream stack stdexcept streambuf string utility valarray vector cassert cctype cerrno cfloat climits clocale ciso646 cmath csetjmp csignal cstdarg cstddef cstdio cstdlib cstring ctime cwchar cwctype
|
||||
|
||||
@GLIBCPP_NEED_LIBIO_TRUE@libio_headers = @GLIBCPP_NEED_LIBIO_TRUE@\
|
||||
@GLIBCPP_NEED_LIBIO_TRUE@ $(top_srcdir)/libio/_G_config.h $(top_srcdir)/libio/libio.h
|
||||
@GLIBCPP_NEED_LIBIO_TRUE@libio_headers = $(top_srcdir)/libio/_G_config.h $(top_srcdir)/libio/libio.h
|
||||
@GLIBCPP_NEED_LIBIO_FALSE@libio_headers =
|
||||
|
||||
build_headers = \
|
||||
bits/std_limits.h \
|
||||
bits/c++config.h bits/c++io.h bits/c++locale.h bits/c++threads.h \
|
||||
bits/basic_file_model.h \
|
||||
bits/atomicity.h bits/os_defines.h \
|
||||
bits/ctype_base.h bits/ctype_noninline.h bits/ctype_inline.h
|
||||
build_headers = bits/std_limits.h bits/c++config.h bits/c++io.h bits/c++locale.h bits/c++threads.h bits/basic_file_model.h bits/atomicity.h bits/os_defines.h bits/ctype_base.h bits/ctype_noninline.h bits/ctype_inline.h
|
||||
|
||||
|
||||
sources = \
|
||||
limitsMEMBERS.cc \
|
||||
stdexcept.cc functexcept.cc bitset.cc \
|
||||
globals.cc \
|
||||
basic_file.cc ios.cc complex_io.cc strstream.cc \
|
||||
c++locale.cc locale.cc localename.cc codecvt.cc \
|
||||
locale-inst.cc stl-inst.cc misc-inst.cc valarray-inst.cc \
|
||||
string-inst.cc wstring-inst.cc
|
||||
sources = limitsMEMBERS.cc stdexcept.cc functexcept.cc bitset.cc globals.cc basic_file.cc ios.cc complex_io.cc strstream.cc c++locale.cc locale.cc localename.cc codecvt.cc locale-inst.cc stl-inst.cc misc-inst.cc valarray-inst.cc string-inst.cc wstring-inst.cc
|
||||
|
||||
VPATH = $(top_srcdir) $(top_srcdir)/src $(GLIBCPP_INCLUDE_DIR) $(GLIBCPP_INCLUDE_DIR)/std $(C_INCLUDE_DIR)
|
||||
|
||||
libstdc___la_SOURCES = $(sources)
|
||||
|
||||
libstdc___la_LIBADD = \
|
||||
../libmath/libmath.la @libio_la@ \
|
||||
../libsupc++/libsupc++convenience.la
|
||||
libstdc___la_LIBADD = ../libmath/libmath.la @libio_la@ ../libsupc++/libsupc++convenience.la
|
||||
|
||||
|
||||
libstdc___la_LDFLAGS = -version-info 3:0:0 -lm
|
||||
|
||||
libstdc___la_DEPENDENCIES = $(libstdc___la_LIBADD)
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@CSHADOW_H = @GLIBCPP_USE_CSHADOW_TRUE@$(top_builddir)/stamp-cshadow
|
||||
@GLIBCPP_USE_CSHADOW_TRUE@CSHADOW_H = $(top_builddir)/stamp-cshadow
|
||||
@GLIBCPP_USE_CSHADOW_FALSE@CSHADOW_H =
|
||||
|
||||
# Check for various configure bits that change where the headers get installed.
|
||||
@ -283,12 +192,7 @@ c_incdir = @C_INCLUDE_DIR@
|
||||
# set this option because CONFIG_CXXFLAGS has to be after
|
||||
# OPTIMIZE_CXXFLAGS on the compile line so that -O2 can be overridden
|
||||
# as the occasion call for it. (ie, --enable-debug)
|
||||
AM_CXXFLAGS = \
|
||||
-fno-implicit-templates \
|
||||
$(LIBSUPCXX_CXXFLAGS) \
|
||||
$(WARN_CXXFLAGS) \
|
||||
$(OPTIMIZE_CXXFLAGS) \
|
||||
$(CONFIG_CXXFLAGS)
|
||||
AM_CXXFLAGS = -fno-implicit-templates $(LIBSUPCXX_CXXFLAGS) $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS)
|
||||
|
||||
|
||||
# libstdc++ libtool notes
|
||||
@ -309,8 +213,7 @@ AM_CXXFLAGS = \
|
||||
# correct solution is to add `--tag CXX' to LTCXXCOMPILE and maybe
|
||||
# CXXLINK, just after $(LIBTOOL), so that libtool doesn't have to
|
||||
# attempt to infer which configuration to use
|
||||
LTCXXCOMPILE = $(LIBTOOL) --tag CXX --mode=compile $(CXX) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(AM_CXXFLAGS)
|
||||
LTCXXCOMPILE = $(LIBTOOL) --tag CXX --mode=compile $(CXX) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(AM_CXXFLAGS)
|
||||
|
||||
|
||||
# 3) We'd have a problem when building the shared libstdc++ object if
|
||||
@ -319,8 +222,7 @@ LTCXXCOMPILE = $(LIBTOOL) --tag CXX --mode=compile $(CXX) $(INCLUDES) \
|
||||
# course is problematic at this point. So, we get the top-level
|
||||
# directory to configure libstdc++-v3 to use gcc as the C++
|
||||
# compilation driver.
|
||||
CXXLINK = $(LIBTOOL) --tag CXX --mode=link $(CXX) \
|
||||
@OPT_LDFLAGS@ @SECTION_LDFLAGS@ $(AM_CXXFLAGS) $(LDFLAGS) -o $@
|
||||
CXXLINK = $(LIBTOOL) --tag CXX --mode=link $(CXX) @OPT_LDFLAGS@ @SECTION_LDFLAGS@ $(AM_CXXFLAGS) $(LDFLAGS) -o $@
|
||||
|
||||
CONFIG_HEADER = ../config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
@ -475,7 +377,7 @@ distdir: $(DISTFILES)
|
||||
@for file in $(DISTFILES); do \
|
||||
if test -f $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
cp -pr $$d/$$file $(distdir)/$$file; \
|
||||
cp -pr $$/$$file $(distdir)/$$file; \
|
||||
else \
|
||||
test -f $(distdir)/$$file \
|
||||
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|
||||
|
Loading…
Reference in New Issue
Block a user