📄 except.c
字号:
build_eh_type_type (type) tree type;{ char *typestring; tree exp; if (type == error_mark_node) return error_mark_node; /* peel back references, so they match. */ if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); /* Peel off cv qualifiers. */ type = TYPE_MAIN_VARIANT (type); if (flag_rtti) { return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type)); } typestring = build_overload_name (type, 1, 1); exp = combine_strings (build_string (strlen (typestring)+1, typestring)); return build1 (ADDR_EXPR, ptr_type_node, exp);}/* Build a type value for use at runtime for a exp that is thrown or matched against by the exception handling system. */static treebuild_eh_type (exp) tree exp;{ if (flag_rtti) { exp = build_typeid (exp); return build1 (ADDR_EXPR, ptr_type_node, exp); } return build_eh_type_type (TREE_TYPE (exp));}/* 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; rtx protect_label_rtx; tree decl = NULL_TREE; tree init; if (! doing_eh (1)) return; /* Create a binding level for the parm. */ expand_start_bindings (0); false_label_rtx = gen_label_rtx (); /* This is saved for the exception table. */ push_rtl_perm (); protect_label_rtx = gen_label_rtx (); pop_rtl_from_perm (); push_label_entry (&false_label_stack, false_label_rtx); push_label_entry (&false_label_stack, protect_label_rtx); if (declspecs) { tree exp; rtx call_rtx, return_value_rtx; tree init_type; decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE, NULL_TREE); if (decl == NULL_TREE) { error ("invalid catch parameter"); return; } /* Figure out the type that the initializer is. */ init_type = TREE_TYPE (decl); if (TREE_CODE (init_type) != REFERENCE_TYPE && TREE_CODE (init_type) != POINTER_TYPE) init_type = build_reference_type (init_type); exp = saved_throw_value; exp = tree_cons (NULL_TREE, build_eh_type_type (TREE_TYPE (decl)), tree_cons (NULL_TREE, saved_throw_type, tree_cons (NULL_TREE, exp, NULL_TREE))); exp = build_function_call (CatchMatch, exp); call_rtx = expand_call (exp, NULL_RTX, 0); assemble_external (TREE_OPERAND (CatchMatch, 0)); return_value_rtx = hard_function_value (ptr_type_node, exp); /* did the throw type match function return TRUE? */ emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX, GET_MODE (return_value_rtx), 0, 0); /* if it returned FALSE, jump over the catch block, else fall into it */ emit_jump_insn (gen_beq (false_label_rtx)); init = convert_from_reference (save_expr (make_tree (init_type, call_rtx))); /* Do we need the below two lines? */ /* Let `cp_finish_decl' know that this initializer is ok. */ DECL_INITIAL (decl) = init; decl = pushdecl (decl); cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING); } else { /* Fall into the catch all section. */ } /* This is the starting of something to protect. */ emit_label (protect_label_rtx); emit_line_note (input_filename, lineno);}/* this is called from expand_exception_blocks and expand_end_catch_block to expand the toplevel finalizations for a function. We return the first label emitted, if any, otherwise return NULL_RTX. */static rtxexpand_leftover_cleanups (){ struct ehEntry *entry; rtx first_label = NULL_RTX; while ((entry = dequeue_eh_entry (&ehqueue)) != 0) { if (! first_label) first_label = entry->exception_handler_label; emit_label (entry->exception_handler_label); expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); /* The below can be optimized away, and we could just fall into the next EH handler, if we are certain they are nested. */ /* Code to throw out to outer context, if we fall off end of the handler. */ expand_internal_throw (gen_rtx (LABEL_REF, Pmode, entry->end_label)); /* leftover try block, opps. */ if (entry->finalization == integer_zero_node) abort (); free (entry); } return first_label;}/* Call this to end a catch block. Its responsible for emitting the code to handle jumping back to the correct place, and for emitting the label to jump to if this catch block didn't match. */void expand_end_catch_block (){ rtx start_protect_label_rtx; rtx end_protect_label_rtx; tree decls; struct ehEntry entry; if (! doing_eh (1)) return; /* fall to outside the try statement when done executing handler and we fall off end of handler. This is jump Lresume in the documentation. */ emit_jump (top_label_entry (&caught_return_label_stack)); /* We end the rethrow protection region as soon as we hit a label. */ end_protect_label_rtx = expand_leftover_cleanups (); /* Code to throw out to outer context, if we get a throw from within our catch handler. */ /* These are saved for the exception table. */ push_rtl_perm (); entry.exception_handler_label = gen_label_rtx (); pop_rtl_from_perm (); /* This label is Lhandler in the documentation. */ emit_label (entry.exception_handler_label); expand_internal_throw (gen_rtx (LABEL_REF, Pmode, top_label_entry (&caught_return_label_stack))); /* No associated finalization. */ entry.finalization = NULL_TREE; entry.context = current_function_decl; if (end_protect_label_rtx == NULL_RTX) end_protect_label_rtx = entry.exception_handler_label; /* Because we are emitted out of line, we have to protect this. */ /* label for the start of the protection region. */ start_protect_label_rtx = pop_label_entry (&false_label_stack); /* Cleanup the EH parameter. */ decls = getdecls (); expand_end_bindings (decls, decls != NULL_TREE, 0); /* label we emit to jump to if this catch block didn't match. */ /* This the closing } in the `if (eq) {' of the documentation. */ emit_label (pop_label_entry (&false_label_stack)); /* Because we are reordered out of line, we have to protect this. */ entry.start_label = start_protect_label_rtx; entry.end_label = end_protect_label_rtx; LABEL_PRESERVE_P (entry.start_label) = 1; LABEL_PRESERVE_P (entry.end_label) = 1; LABEL_PRESERVE_P (entry.exception_handler_label) = 1; /* These set up a call to throw the caught exception into the outer context. */ enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));}/* unwind the stack. */static voiddo_unwind (inner_throw_label) rtx inner_throw_label;{#if defined(SPARC_STACK_ALIGN) /* was sparc */ tree fcall; tree params; rtx return_val_rtx; rtx temp; /* call to __builtin_return_address () */ params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); fcall = build_function_call (BuiltinReturnAddress, params); return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0); /* In the return, the new pc is pc+8, as the value coming in is really the address of the call insn, not the next insn. */ temp = gen_reg_rtx (Pmode); emit_move_insn (temp, inner_throw_label); emit_move_insn (return_val_rtx, plus_constant (temp, -8)); easy_expand_asm ("ret"); easy_expand_asm ("restore"); emit_barrier ();#endif#if defined(ARM_FRAME_RTX) /* was __arm */ if (flag_omit_frame_pointer) sorry ("this implementation of exception handling requires a frame pointer"); emit_move_insn (stack_pointer_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8))); emit_move_insn (hard_frame_pointer_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));#endif#if defined(TARGET_88000) /* was m88k */ rtx temp_frame = frame_pointer_rtx; temp_frame = memory_address (Pmode, temp_frame); temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame)); /* hopefully this will successfully pop the frame! */ emit_move_insn (frame_pointer_rtx, temp_frame); emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); emit_move_insn (arg_pointer_rtx, frame_pointer_rtx); emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));#if 0 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0)))); emit_move_insn (stack_pointer_rtx, arg_pointer_rtx); emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode, (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));#endif#endif#if !defined(TARGET_88000) && !defined(ARM_FRAME_RTX) && !defined(SPARC_STACK_ALIGN) tree fcall; tree params; rtx return_val_rtx; /* call to __builtin_return_address () */ params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); fcall = build_function_call (BuiltinReturnAddress, params); return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);#if 0 /* I would like to do this here, but doesn't seem to work. */ emit_move_insn (return_val_rtx, inner_throw_label); /* So, for now, just pass throw label to stack unwinder. */#endif params = tree_cons (NULL_TREE, make_tree (ptr_type_node, inner_throw_label), NULL_TREE); do_function_call (Unwind, params, NULL_TREE); assemble_external (TREE_OPERAND (Unwind, 0)); emit_barrier ();#endif}/* is called from expand_exception_blocks () to generate the code in a function to "throw" if anything in the function needs to perform a throw. expands "throw" as the following pseudo code: throw: eh = find_first_exception_match (saved_pc); if (!eh) goto gotta_rethrow_it; goto eh; gotta_rethrow_it: saved_pc = __builtin_return_address (0); pop_to_previous_level (); goto throw; */voidexpand_builtin_throw (){ tree fcall; tree params; rtx return_val_rtx; rtx gotta_rethrow_it; rtx gotta_call_terminate; rtx unwind_and_throw; rtx goto_unwind_and_throw; rtx top_of_loop; rtx unwind_first; tree t; if (! doing_eh (0)) return; if (! throw_used) return; params = void_list_node; t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE); start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"), void_list_node), t, NULL_TREE, 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 (); unwind_and_throw = gen_label_rtx (); goto_unwind_and_throw = gen_label_rtx (); top_of_loop = gen_label_rtx (); unwind_first = gen_label_rtx (); emit_jump (unwind_first); emit_label (top_of_loop); /* search for an exception handler for the saved_pc */ return_val_rtx = do_function_call (FirstExceptionMatch, tree_cons (NULL_TREE, saved_pc, NULL_TREE), ptr_type_node); assemble_external (TREE_OPERAND (FirstExceptionMatch, 0)); /* did we find one? */ emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX, GET_MODE (return_val_rtx), 0, 0); /* if not, jump to gotta_rethrow_it */ emit_jump_insn (gen_beq (gotta_rethrow_it)); /* we found it, so jump to it */ emit_indirect_jump (return_val_rtx); /* code to deal with unwinding and looking for it again */ emit_label (gotta_rethrow_it); /* call to __builtin_return_address () */#if defined(ARM_FRAME_RTX) /* was __arm *//* This replaces a 'call' to __builtin_return_address */ return_val_rtx = gen_reg_rtx (Pmode); emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));#else params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); fcall = build_function_call (BuiltinReturnAddress, params); return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);#endif /* did __builtin_return_address () return a valid address? */ emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX, GET_MODE (return_val_rtx), 0, 0); emit_jump_insn (gen_beq (gotta_call_terminate));#if defined(ARM_FRAME_RTX) /* was __arm */ /* On the ARM, '__builtin_return_address', must have 4 subtracted from it. */ emit_insn (gen_add2_insn (return_val_rtx, GEN_INT (-4))); /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 in 26 bit mode, the condition codes must be masked out of the return value, or else they will confuse BuiltinReturnAddress. This does not apply to ARM6 and later processors when running in 32 bit mode. */ if (!TARGET_6) emit_insn (gen_rtx (SET, Pmode, return_val_rtx, gen_rtx (AND, Pmode, return_val_rtx, GEN_INT (0x03fffffc))));#else#if !defined(SPARC_STACK_ALIGN) /* was sparc */ /* On the SPARC, __builtin_return_address is already -8, no need to subtract any more from it. */ return_val_rtx = plus_constant (return_val_rtx, -1);#endif#endif /* yes it did */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -