except.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,417 行 · 第 1/3 页
C
1,417 行
}/* Build up a call to __cp_pop_exception, to destroy the exception object for the current catch block. HANDLER is either true or false, telling the library whether or not it is being called from an exception handler; if it is, it avoids destroying the object on rethrow. */static treedo_pop_exception (handler) tree handler;{ tree fn, cleanup; fn = get_identifier ("__cp_pop_exception"); if (IDENTIFIER_GLOBAL_VALUE (fn)) fn = IDENTIFIER_GLOBAL_VALUE (fn); else { /* Declare void __cp_pop_exception (void *), as defined in exception.cc. */ push_obstacks_nochange (); end_temporary_allocation (); fn = build_lang_decl (FUNCTION_DECL, fn, build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, boolean_type_node, void_list_node)))); DECL_EXTERNAL (fn) = 1; TREE_PUBLIC (fn) = 1; DECL_ARTIFICIAL (fn) = 1; pushdecl_top_level (fn); make_function_rtl (fn); assemble_external (fn); pop_obstacks (); } /* Arrange to do a dynamically scoped cleanup upon exit from this region. */ cleanup = lookup_name (get_identifier ("__exception_info"), 0); cleanup = build_function_call (fn, expr_tree_cons (NULL_TREE, cleanup, expr_tree_cons (NULL_TREE, handler, NULL_TREE))); return cleanup;}/* This routine creates the cleanup for the current exception. */static voidpush_eh_cleanup (){ /* All cleanups must last longer than normal. */ int yes = suspend_momentary (); expand_decl_cleanup_no_eh (NULL_TREE, do_pop_exception (boolean_false_node)); resume_momentary (yes); expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1), const0_rtx, VOIDmode, EXPAND_NORMAL); /* We don't destroy the exception object on rethrow, so we can't use the normal cleanup mechanism for it. */ expand_eh_region_start ();}/* call this to start a catch block. Typename is the typename, and identifier is the variable to place the object in or NULL if the variable doesn't matter. If typename is NULL, that means its a "catch (...)" or catch everything. In that case we don't need to do any type checking. (ie: it ends up as the "else" clause rather than an "else if" clause) */voidexpand_start_catch_block (declspecs, declarator) tree declspecs, declarator;{ rtx false_label_rtx; tree decl = NULL_TREE; tree init; if (processing_template_decl) { if (declspecs) { decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE); pushdecl (decl); decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator), copy_to_permanent (declspecs), NULL_TREE); add_tree (decl); } return; } if (! doing_eh (1)) return; /* If we are not doing setjmp/longjmp EH, because we are reordered out of line, we arrange to rethrow in the outer context so as to skip through the terminate region we are nested in, should we encounter an exception in the catch handler. We also need to do this because we are not physically within the try block, if any, that contains this catch block. Matches the end in expand_end_catch_block. */ if (! exceptions_via_longjmp) expand_eh_region_start (); /* Create a binding level for the eh_info and the exception object cleanup. */ pushlevel (0); expand_start_bindings (0); false_label_rtx = gen_label_rtx (); push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE); emit_line_note (input_filename, lineno); push_eh_info (); if (declspecs) { decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE); if (decl == NULL_TREE) error ("invalid catch parameter"); } if (decl) { tree exp; rtx call_rtx, return_value_rtx; tree init_type; /* Make sure we mark the catch param as used, otherwise we'll get a warning about an unused ((anonymous)). */ TREE_USED (decl) = 1; /* Figure out the type that the initializer is. */ init_type = TREE_TYPE (decl); if (TREE_CODE (init_type) != REFERENCE_TYPE && TREE_CODE (init_type) != POINTER_TYPE) init_type = build_reference_type (init_type); exp = get_eh_value (); exp = expr_tree_cons (NULL_TREE, build_eh_type_type (TREE_TYPE (decl)), expr_tree_cons (NULL_TREE, get_eh_type (), expr_tree_cons (NULL_TREE, exp, NULL_TREE))); exp = build_function_call (CatchMatch, exp); call_rtx = expand_call (exp, NULL_RTX, 0); assemble_external (TREE_OPERAND (CatchMatch, 0)); return_value_rtx = hard_function_value (ptr_type_node, exp); /* did the throw type match function return TRUE? */ emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX, GET_MODE (return_value_rtx), 0, 0); /* if it returned FALSE, jump over the catch block, else fall into it */ emit_jump_insn (gen_beq (false_label_rtx)); push_eh_cleanup (); /* Create a binding level for the parm. */ pushlevel (0); expand_start_bindings (0); init = convert_from_reference (make_tree (init_type, call_rtx)); /* If the constructor for the catch parm exits via an exception, we must call terminate. See eh23.C. */ if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) { /* Generate the copy constructor call directly so we can wrap it. See also expand_default_init. */ init = ocp_convert (TREE_TYPE (decl), init, CONV_IMPLICIT|CONV_FORCE_TEMP, 0); init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init, TerminateFunctionCall); } /* Let `cp_finish_decl' know that this initializer is ok. */ DECL_INITIAL (decl) = init; decl = pushdecl (decl); cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING); } else { push_eh_cleanup (); /* Create a binding level for the parm. */ pushlevel (0); expand_start_bindings (0); /* Fall into the catch all section. */ } init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node); expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL); emit_line_note (input_filename, lineno);}/* Call this to end a catch block. Its responsible for emitting the code to handle jumping back to the correct place, and for emitting the label to jump to if this catch block didn't match. */voidexpand_end_catch_block (){ if (! doing_eh (1)) return; /* Cleanup the EH parameter. */ expand_end_bindings (getdecls (), kept_level_p (), 0); poplevel (kept_level_p (), 1, 0); /* Matches push_eh_cleanup. */ expand_eh_region_end (do_pop_exception (boolean_true_node)); /* Cleanup the EH object. */ expand_end_bindings (getdecls (), kept_level_p (), 0); poplevel (kept_level_p (), 1, 0); if (! exceptions_via_longjmp) { /* If we are not doing setjmp/longjmp EH, we need an extra region around the whole catch block to skip through the terminate region we are nested in. */ tree t = make_node (RTL_EXPR); TREE_TYPE (t) = void_type_node; RTL_EXPR_RTL (t) = const0_rtx; TREE_SIDE_EFFECTS (t) = 1; do_pending_stack_adjust (); start_sequence_for_rtl_expr (t); expand_internal_throw (outer_context_label_stack->u.rlabel); do_pending_stack_adjust (); RTL_EXPR_SEQUENCE (t) = get_insns (); end_sequence (); /* For the rethrow region. */ expand_eh_region_end (t); } /* 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)); expand_leftover_cleanups (); /* label we emit to jump to if this catch block didn't match. */ /* This the closing } in the `if (eq) {' of the documentation. */ emit_label (pop_label_entry (&false_label_stack));}/* unwind the stack. */static voiddo_unwind (inner_throw_label) rtx inner_throw_label;{#if defined (SPARC_STACK_ALIGN) /* was sparc */ /* This doesn't work for the flat model sparc, nor does it need to as the default unwinder is only used to unwind non-flat frames. */ tree fcall; tree params; rtx next_pc; rtx temp; /* Call to __builtin_return_address. */ params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); fcall = build_function_call (BuiltinReturnAddress, params); next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0); /* In the return, the new pc is pc+8, as the value coming in is really the address of the call insn, not the next insn. */ temp = gen_reg_rtx (Pmode); emit_move_insn (temp, inner_throw_label); emit_move_insn (next_pc, plus_constant (temp, -8)); emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31))); easy_expand_asm ("ret"); easy_expand_asm ("restore"); emit_barrier ();#endif#if defined (ARM_FRAME_RTX) /* was __arm */ if (flag_omit_frame_pointer) sorry ("this implementation of exception handling requires a frame pointer"); emit_move_insn (stack_pointer_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8))); emit_move_insn (hard_frame_pointer_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));#endif#if defined (TARGET_88000) /* was m88k */ rtx temp_frame = frame_pointer_rtx; temp_frame = memory_address (Pmode, temp_frame); temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame)); /* hopefully this will successfully pop the frame! */ emit_move_insn (frame_pointer_rtx, temp_frame); emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); emit_move_insn (arg_pointer_rtx, frame_pointer_rtx); emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));#if 0 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0)))); emit_move_insn (stack_pointer_rtx, arg_pointer_rtx); emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));#endif#endif#if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN) tree fcall; tree params; rtx next_pc;#if 0 /* I would like to do this here, but the move below doesn't seem to work. */ /* Call to __builtin_return_address. */ params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); fcall = build_function_call (BuiltinReturnAddress, params); next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0); emit_move_insn (next_pc, inner_throw_label); /* So, for now, just pass throw label to stack unwinder. */#endif params = expr_tree_cons (NULL_TREE, make_tree (ptr_type_node, inner_throw_label), NULL_TREE); do_function_call (Unwind, params, NULL_TREE); assemble_external (TREE_OPERAND (Unwind, 0)); emit_barrier ();#endif}/* Is called from expand_exception_blocks to generate the code in a function to "throw" if anything in the function needs to perform a throw. expands "throw" as the following pseudo code: throw: eh = find_first_exception_match (saved_pc); if (!eh) goto gotta_rethrow_it; goto eh; gotta_rethrow_it: saved_pc = __builtin_return_address (0); pop_to_previous_level (); goto throw; */voidexpand_builtin_throw (){#ifndef DWARF2_UNWIND_INFO tree fcall; tree params; rtx handler; rtx saved_pcnthrow; rtx next_pc; rtx gotta_rethrow_it; rtx gotta_call_terminate; rtx after_unwind; rtx top_of_loop; tree t; rtx x; if (! doing_eh (0)) return; if (! throw_used) return; params = void_list_node; t = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE, NULL_TREE); start_function (decl_tree_cons (NULL_TREE, get_identifier ("void"), decl_tree_cons (NULL_TREE, get_identifier ("static"), NULL_TREE)), t, NULL_TREE, 0); store_parm_decls (); pushlevel (0); clear_last_expr (); push_momentary (); expand_start_bindings (0); gotta_rethrow_it = gen_label_rtx (); gotta_call_terminate = gen_label_rtx (); /* These two can be frontend specific. If wanted, they can go in expand_throw. */ /* Do we have a valid object we are throwing? */ t = call_eh_info (); emit_cmp_insn (expand_expr (t, NULL_RTX, Pmode, 0), const0_rtx, EQ, NULL_RTX, GET_MODE (DECL_RTL (t)), 0, 0); emit_jump_insn (gen_beq (gotta_call_terminate)); /* search for an exception handler for the saved_pc */ handler = do_function_call (FirstExceptionMatch, expr_tree_cons (NULL_TREE, saved_pc, NULL_TREE), ptr_type_node); assemble_external (TREE_OPERAND (FirstExceptionMatch, 0)); /* did we find one? */ emit_cmp_insn (handler, const0_rtx, EQ, NULL_RTX, GET_MODE (handler), 0, 0); /* if not, jump to gotta_rethrow_it */ emit_jump_insn (gen_beq (gotta_rethrow_it)); { rtx ret_val, x; ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, 0, hard_frame_pointer_rtx); /* Set it up so that we continue at the handler. */ emit_move_insn (ret_val, handler);#ifdef RETURN_ADDR_OFFSET x = plus_constant (ret_val, -RETURN_ADDR_OFFSET); if (x != ret_val) emit_move_insn (ret_val, x);#endif expand_null_return (); } top_of_loop = gen_label_rtx (); emit_label (top_of_loop); #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE if (DONT_ACCESS_GBLS_AFTER_EPILOGUE) { saved_pcnthrow = gen_reg_rtx (Pmode); emit_move_insn (saved_pcnthrow, hard_function_value (ptr_type_node, NULL_TREE)); }#endif /* Call to __builtin_return_address. */#if defined (ARM_FRAME_RTX) /* was __arm */ /* This should be moved into arm.h:RETURN_ADDR_RTX */ /* This replaces a 'call' to __builtin_return_address */ next_pc = gen_reg_rtx (Pmode); emit_move_insn (next_pc, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));#else params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); fcall = build_function_call (BuiltinReturnAddress, params); next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);#endif /* Did __builtin_return_address return a valid address? */ emit_cmp_insn (next_pc, const0_rtx, EQ, NULL_RTX, GET_MODE (next_pc), 0, 0); emit_jump_insn (gen_beq (gotta_call_terminate)); next_pc = eh_outer_context (next_pc);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?