except.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,417 行 · 第 1/3 页
C
1,417 行
/* Yes it did. */#ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE if (DONT_ACCESS_GBLS_AFTER_EPILOGUE) { rtx x; x = validize_mem (gen_rtx (MEM, Pmode, saved_pcnthrow)); emit_move_insn (validize_mem (gen_rtx (MEM, Pmode, x)), next_pc);#ifdef FUNCTION_OUTGOING_VALUE emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE), validize_mem (gen_rtx (MEM, Pmode, plus_constant (saved_pcnthrow, GET_MODE_SIZE (Pmode))))); emit_insn (gen_rtx (USE, VOIDmode, FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));#endif } else#endif emit_move_insn (eh_saved_pc_rtx, next_pc); after_unwind = gen_label_rtx (); do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind)); emit_label (after_unwind);#ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE if (DONT_ACCESS_GBLS_AFTER_EPILOGUE) { t = build_function_type (void_type_node, void_list_node); t = make_tree (build_pointer_type (t), hard_function_value (ptr_type_node, NULL_TREE)); t = build_function_call (t, NULL_TREE); expand_expr (t, const0_rtx, VOIDmode, 0); } else#endif emit_throw (); /* no it didn't --> therefore we need to call terminate */ emit_label (gotta_call_terminate); do_function_call (Terminate, NULL_TREE, NULL_TREE); assemble_external (TREE_OPERAND (Terminate, 0)); { rtx ret_val, x; /* code to deal with unwinding and looking for it again */ emit_label (gotta_rethrow_it); ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, 0, hard_frame_pointer_rtx); /* Set it up so that we continue inside, at the top of the loop. */ emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));#ifdef RETURN_ADDR_OFFSET x = plus_constant (ret_val, -RETURN_ADDR_OFFSET); if (x != ret_val) emit_move_insn (ret_val, x);#endif#ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE if (DONT_ACCESS_GBLS_AFTER_EPILOGUE) { rtx x = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, "__eh_pcnthrow"), NULL_RTX, 1, Pmode, 0); /* This is to get a version of throw that will throw properly. */ emit_move_insn (validize_mem (gen_rtx (MEM, Pmode, plus_constant (x, GET_MODE_SIZE (Pmode)))), throw_libfunc);#ifdef FUNCTION_OUTGOING_VALUE emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE), x); emit_insn (gen_rtx (USE, VOIDmode, FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));#endif }#endif /* Fall into epilogue to unwind prologue. */ } expand_end_bindings (getdecls (), 1, 0); poplevel (1, 0, 0); pop_momentary (); finish_function (lineno, 0, 0);#endif /* DWARF2_UNWIND_INFO */}voidexpand_start_eh_spec (){ expand_eh_region_start ();}static voidexpand_end_eh_spec (raises) tree raises;{ tree expr, second_try; rtx check = gen_label_rtx (); rtx cont; rtx ret = gen_reg_rtx (Pmode); rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node)); rtx end = gen_label_rtx (); expr = make_node (RTL_EXPR); TREE_TYPE (expr) = void_type_node; RTL_EXPR_RTL (expr) = const0_rtx; TREE_SIDE_EFFECTS (expr) = 1; do_pending_stack_adjust (); start_sequence_for_rtl_expr (expr); cont = gen_label_rtx (); emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont)); emit_jump (check); emit_label (cont); jumpif (make_tree (integer_type_node, flag), end); do_function_call (Terminate, NULL_TREE, NULL_TREE); assemble_external (TREE_OPERAND (Terminate, 0)); emit_barrier (); do_pending_stack_adjust (); RTL_EXPR_SEQUENCE (expr) = get_insns (); end_sequence (); second_try = expr; expr = make_node (RTL_EXPR); TREE_TYPE (expr) = void_type_node; RTL_EXPR_RTL (expr) = const0_rtx; TREE_SIDE_EFFECTS (expr) = 1; do_pending_stack_adjust (); start_sequence_for_rtl_expr (expr); cont = gen_label_rtx (); emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont)); emit_jump (check); emit_label (cont); jumpif (make_tree (integer_type_node, flag), end); expand_eh_region_start (); do_function_call (Unexpected, NULL_TREE, NULL_TREE); assemble_external (TREE_OPERAND (Unexpected, 0)); emit_barrier (); expand_eh_region_end (second_try); emit_label (check); emit_move_insn (flag, const1_rtx); cont = gen_label_rtx (); push_eh_info (); while (raises) { tree exp; tree match_type = TREE_VALUE (raises); if (match_type) { /* check TREE_VALUE (raises) here */ exp = get_eh_value (); exp = expr_tree_cons (NULL_TREE, build_eh_type_type (match_type), expr_tree_cons (NULL_TREE, get_eh_type (), expr_tree_cons (NULL_TREE, exp, NULL_TREE))); exp = build_function_call (CatchMatch, exp); assemble_external (TREE_OPERAND (CatchMatch, 0)); jumpif (exp, cont); } raises = TREE_CHAIN (raises); } emit_move_insn (flag, const0_rtx); emit_label (cont); emit_indirect_jump (ret); emit_label (end); do_pending_stack_adjust (); RTL_EXPR_SEQUENCE (expr) = get_insns (); end_sequence (); expand_eh_region_end (expr);}/* This is called to expand all the toplevel exception handling finalization for a function. It should only be called once per function. */voidexpand_exception_blocks (){ do_pending_stack_adjust (); push_to_sequence (catch_clauses); expand_leftover_cleanups (); do_pending_stack_adjust (); catch_clauses = get_insns (); end_sequence (); /* Do this after we expand leftover cleanups, so that the expand_eh_region_end that expand_end_eh_spec does will match the right expand_eh_region_start, and make sure it comes out before the terminate protected region. */ if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) { expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))); do_pending_stack_adjust (); push_to_sequence (catch_clauses); expand_leftover_cleanups (); do_pending_stack_adjust (); catch_clauses = get_insns (); end_sequence (); } if (catch_clauses) { rtx funcend = gen_label_rtx (); emit_jump (funcend); /* We cannot protect n regions this way if we must flow into the EH region through the top of the region, as we have to with the setjmp/longjmp approach. */ if (exceptions_via_longjmp == 0) { /* Is this necessary? */ assemble_external (TREE_OPERAND (Terminate, 0)); expand_eh_region_start (); } emit_insns (catch_clauses); catch_clauses = NULL_RTX; if (exceptions_via_longjmp == 0) expand_eh_region_end (TerminateFunctionCall); expand_leftover_cleanups (); emit_label (funcend); }}treestart_anon_func (){ static int counter = 0; int old_interface_unknown = interface_unknown; char name[32]; tree params; tree t; push_cp_function_context (NULL_TREE); push_to_top_level (); /* No need to mangle this. */ push_lang_context (lang_name_c); interface_unknown = 1; params = void_list_node; /* tcf stands for throw clean function. */ sprintf (name, "__tcf_%d", counter++); t = make_call_declarator (get_identifier (name), params, NULL_TREE, NULL_TREE); start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"), void_list_node), t, NULL_TREE, 0); store_parm_decls (); pushlevel (0); clear_last_expr (); push_momentary (); expand_start_bindings (0); emit_line_note (input_filename, lineno); interface_unknown = old_interface_unknown; pop_lang_context (); return current_function_decl;}voidend_anon_func (){ expand_end_bindings (getdecls (), 1, 0); poplevel (1, 0, 0); pop_momentary (); finish_function (lineno, 0, 0); pop_from_top_level (); pop_cp_function_context (NULL_TREE);}/* Expand a throw statement. This follows the following algorithm: 1. Allocate space to save the current PC onto the stack. 2. Generate and emit a label and save its address into the newly allocated stack space since we can't save the pc directly. 3. If this is the first call to throw in this function: generate a label for the throw block 4. jump to the throw block label. */voidexpand_throw (exp) tree exp;{ rtx label; tree fn; static tree cleanup_type; if (! doing_eh (1)) return; if (exp) { tree throw_type; tree cleanup = NULL_TREE, e; /* throw expression */ /* First, decay it. */ exp = decay_conversion (exp); /* cleanup_type is void (*)(void *, int), the internal type of a destructor. */ if (cleanup_type == NULL_TREE) { push_obstacks_nochange (); end_temporary_allocation (); cleanup_type = build_pointer_type (build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, void_list_node)))); pop_obstacks (); } if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE) { throw_type = build_eh_type (exp); exp = build_reinterpret_cast (ptr_type_node, exp); } else { tree object; /* Make a copy of the thrown object. WP 15.1.5 */ exp = build_new (NULL_TREE, TREE_TYPE (exp), build_expr_list (NULL_TREE, exp), 0); if (exp == error_mark_node) error (" in thrown expression"); object = build_indirect_ref (exp, NULL_PTR); throw_type = build_eh_type (object); if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object))) { cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), dtor_identifier, 0); cleanup = TREE_VALUE (cleanup); mark_addressable (cleanup); /* Pretend it's a normal function. */ cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup); } } if (cleanup == NULL_TREE) { cleanup = build_int_2 (0, 0); TREE_TYPE (cleanup) = cleanup_type; } fn = get_identifier ("__cp_push_exception"); if (IDENTIFIER_GLOBAL_VALUE (fn)) fn = IDENTIFIER_GLOBAL_VALUE (fn); else { /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)), as defined in exception.cc. */ tree tmp; push_obstacks_nochange (); end_temporary_allocation (); tmp = tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, cleanup_type, void_list_node))); fn = build_lang_decl (FUNCTION_DECL, fn, build_function_type (void_type_node, tmp)); 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 (); } /* The throw expression is a full-expression. */ exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp); e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons (NULL_TREE, throw_type, expr_tree_cons (NULL_TREE, cleanup, NULL_TREE))); e = build_function_call (fn, e); expand_expr (e, const0_rtx, VOIDmode, 0); } else { /* rethrow current exception; note that it's no longer caught. */ tree fn = get_identifier ("__uncatch_exception"); if (IDENTIFIER_GLOBAL_VALUE (fn)) fn = IDENTIFIER_GLOBAL_VALUE (fn); else { /* Declare void __uncatch_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, 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 (); } exp = build_function_call (fn, NULL_TREE); expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL); } if (exceptions_via_longjmp) emit_throw (); else { /* This is the label that represents where in the code we were, when we got an exception. This needs to be updated when we rethrow an exception, so that the matching routine knows to search out. */ label = gen_label_rtx (); emit_label (label); expand_internal_throw (label); }}/* Build a throw expression. */treebuild_throw (e) tree e;{ if (e != error_mark_node) { if (processing_template_decl) return build_min (THROW_EXPR, void_type_node, e); e = build1 (THROW_EXPR, void_type_node, e); TREE_SIDE_EFFECTS (e) = 1; TREE_USED (e) = 1; } return e;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?