This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

ia64 c++ abi exception handling

The following is an initial implementation of the exception 
handling model proposed by the multi-vendor C++ ABI folks.
The specification is targeted at IA-64, but require only 
minor tweeks to be usable on other targets.

The new implementation has a number of advantages:

  * "Personality" routine controls precise exception handling
    semantics.  Rules exist for managing exceptions between

  * Two pass structure allows a language to cancel an exception
    and continue from the point of throw.

    For C++, the unhandled exception abort happens from the point
    of throw, as opposed to at the beginning of the call chain,
    so its easier to see what went wrong.

  * Generated code and exception handling data is smaller.
    For instance on alpha-linux, goes from

				     OLD       NEW
	.rela.eh_frame             28872     37368
	.rela.gcc_except_table    109584      2016
	.text                     445584    418880
	.eh_frame                  49560     59216
	.gcc_except_table          48272     11728

    I expect to be able to reduce the number of dynamic
    relocations further, but this patch is big enough as is.

  * The optimizers need not worry about exception regions at all.
    The strict logical nesting of exception "regions" only exists
    during initial code generation.  Afterward, each instruction
    that is known to throw is tagged with a REG_EH_REGION note
    which records what actions ought to be taken if an exception
    occurs at that location.  Code may now be reordered as the
    optimizers see fit.  Just before emitting assembly, we look
    to see what order things came out and emit sorted tuples 
    containing pc range, landing pad, and action data.

  * Debugging information for catch handlers should be correct.
    The previous "new exceptions" model generated catch clauses
    out of line so that we didn't have to branch around them.
    In the process, it disassociated the code from the debugging

    This implementation generates the code in line and relies on
    the bb-reorder pass to move it elsewhere and preserve debugging.

There are a number of changes that must be made to targets to
support the new routines.  If a target previously defined
eh_epilogue, then the changes are minimal -- mostly describing
the ABI of the exception handler landing pads.

The old method of using a generic thunk to implement dwarf2
exception return is not supported.  It's not that hard to just
do things properly, and some of the bits involved define the
ABI between throw and catch, so it's a really bad idea for 
generic code to just make something up.

I've not yet re-implemented sjlj exeption handling.  I have a plan
that should greaty reduce the overhead as compared to the existing 
implementation.  I'd really rather deprecate it entirely, but the
non-ability of dwarf2 frame unwind to cope with intermediate
routines not compiled with frame information is probably s show
stopper there.

I have not yet done anything with Java.  I'd been delaying that
until C++ worked.  I'll be talking with them this next week.

This code has been ported to alpha, i386, and powerpc.  It has been
tested on alphaev6-linux, i686-linux, and powerpc-eabisim.  The 
regressions are at an acceptable minimum (IMO):

FAIL: (test for excess errors)
FAIL: (test for excess errors)
FAIL: g++.other/cond5.C (test for excess errors)

   `({...})' has type `void' and is not a throw-expression

   Before the front end somehow magically recognized a post-template
   expansion throw expression.  The new code doesn't look the same,
   and I'm not sure how to update the check.

FAIL: g++.other/goto3.C jumps (test for errors, line 9)
FAIL: g++.other/goto3.C into catch (test for errors, line 10)
FAIL: g++.other/goto3.C  (test for errors, line 16)
FAIL: g++.other/goto3.C  (test for errors, line 17)

   Failure to notice an illegal branch target inside a catch handler.
   I've not yet examined what the front end had been using to notice
   this condition previously.

FAIL: caused compiler crash
FAIL: caused compiler crash

   These tests force -fsjlj-exceptions, which isn't implemented.

Comments welcome.

	* except.c: Rewrite entirely for IA-64 ABI exception handling.
	* except.h: Likewise.

	* (LIB2ADDEH): Mention unwind-dw2*.c
	(LIB2FUNCS_EH): Remove.
	( Pass LIB2ADDEHDEP, don't pass LIB2FUNCS_EH.
	(crt{begin,end}[S].o): Likewise.
	(except.o): Update includes.
	(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.
	* c-common.c (c_common_nodes_and_builtins): Declare it.
	* c-decl.c (init_decl_processing): Update __builtin_eh_return.
	* calls.c (libfunc_nothrow): Recognize unwind_resume_libfunc only.
	(emit_library_call_value_1): Handle LCT_NORETURN.
	* 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.
	* dwarf2asm.c (dw2_asm_output_data_uleb128): Use space instead
	of tab for separator.
	(dw2_asm_output_data_sleb128): Likewise.  Print value in decimal.
	* 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.
	* 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.
	* final.c (final): Don't call check_exception_handler_labels,
	init_insn_eh_region, free_insn_eh_region.
	(final_scan_insn): Always emit debug labels for 
	* 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 eh_region_generates_edges.
	(find_basic_blocks_1): Likewise.
	(move_stray_eh_region_notes): Remove.
	(cleanup_cfg): Remove insns argument.
	(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
	(delete_unreachable_blocks): Don't track deleted handlers.
	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, 
	(init_propagate_block_info): Disable dead frame store optimization
	when current_function_calls_eh_return.
	* function.c (fixup_var_refs): No catch_clauses.
	(expand_function_end): Likewise.  Call expand_eh_return before
	the return register use.
	* function.h (struct function): Collect boolean fields into
	single bit fields at the end of the structure.  Add calls_eh_return,
	* 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): Initialize and emit local_return_label.
	Call duplicate_eh_regions, copy_insn_notes.
	(copy_insn_list): Don't create local_return_label.  Split out ...
	(copy_insn_notes): ... new function.  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.
	* output.h (cleanup_cfg): Update decl.
	* resource.c (find_dead_or_set_registers): Use can_throw_internal.
	* rtl.def (RESX): New.
	* rtl.h (SYMBOL_REF_NEED_ADJUST): Remove.
	* sibcall.c (optimize_sibling_and_tail_recursive_call): Assume
	that the CFG has already been cleaned up.
	* stmt.c (expand_return): Simplify cleanups checks.
	(expand_decl_cleanup): Simplify using_eh_for_cleanups_p checks.
	Update for except.h name changes.
	(expand_cleanups): Likewise.
	(expand_decl_cleanup_no_eh): Remove.
	(expand_dcc_cleanup, expand_dhc_cleanup): Remove.
	* toplev.c (dump_file_index, dump_file): Add dump.
	(flag_new_exceptions): Remove.
	(synchronous_exceptions): Renamed from asynchronous_exceptions.
	(f_options): Update to match.
	(compile_file): Don't output_exception_table here.
	(rest_of_compilation): Call convert_from_eh_region_ranges,
	collect_exception_handler_labels, convert_to_eh_region_ranges,
	output_function_exception_table.  Don't emit_eh_context,
	find_exception_handler_labels.  Update cleanup_cfg arguments.
	(toplev_main): Don't default exceptions_via_longjmp here.
	* tree.def (POPDHC_EXPR, POPDCC_EXPR): Remove.

	* md.texi (eh_epilogue): Remove.
	(eh_return): Document.
	* tm.texi (EH_RETURN_DATA_REGNO): Document.

	* eh-common.h: Remove file.
	* frame-dwarf2.c, frame.c, frame.h: Remove files.
	* gthr-single.h (UNUSED): Define appropriately for C and C++.
	Use it throughout.
	* 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.h, New file.
	* libgcc-std.ver: Update for eh symbols.

	* config/alpha/alpha.c (alpha_sa_mask): Add EH_RETURN_DATA_REGNOs.
	(alpha_mark_machine_status): No eh_epilogue_sp_ofs ...
	(alpha_expand_epilogue): ... use EH_RETURN_STACKADJ_RTX instead.
	* config/alpha/alpha.h (machine_function): Remove eh_epilogue_sp_ofs.
	* config/alpha/ (eh_epilogue): Remove.
	(exception_receiver): Use $26 for ldgp input.

	* config/i386/i386.c (general_no_elim_operand): Disallow virtual regs.
	(ix86_save_reg): True for EH_RETURN_DATA_REGNOs.  True for
	pic register if current_function_calls_eh_return.
	(ix86_expand_epilogue): Use EH_RETURN_STACKADJ_RTX.
	* config/i386/i386.h (EH_RETURN_DATA_REGNO): New.
	* config/i386/ (exception_receiver): Remove.

	* config/rs6000/rs6000.c (rs6000_stack_info): Allocate space
	for eh_return data registers.
	(rs6000_emit_prologue): Save eh_return data registers.
	(rs6000_emit_epilogue): Force inline restores if eh_return.
	Restore eh_return data registers.  Mind EH_RETURN_STACKADJ_RTX.
	* config/rs6000/rs6000.h (rs6000_stack_t): Add ehrd_offset.
	(eh_return): New, from corpse of eh_epilogue.
	(eh_reg_restore): Remove.
	(return_eh_si, return_eh_di): Remove.
	(eh_set_lr_si, eh_set_lr_di): New.

	* tree.def (EH_SPEC_BLOCK): New.
	* cp-tree.h: Update changed function declarations.
	(struct cp_language_function): Rename x_eh_spec_try_block
	to x_eh_spec_block.
	* 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.
	(initialize_handler_parm): Remove Java type handling.
	(expand_start_catch_block): Use do_begin_catch.
	(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.
	* 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.

	* libsupc++/ (sources): Update files list.
	* libsupc++/ Regenerate.
	* libsupc++/, libsupc++/ New files.
	* libsupc++/, libsupc++/ New files.
	* libsupc++/, libsupc++/ New files.
	* libsupc++/, libsupc++/ New files.
	* libsupc++/ Remove.
	* libsupc++/exception_support.h: Remove.
	* libsupc++/ Use std::terminate.
	* libsupc++/ (__throw_type_match_rtti_2): Remove.
	(__is_pointer): Remove.
	* libsupc++/unwind-cxx.h: New file.
	* libsupc++/ (uncatch_exception): Update for new abi.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]