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 + -
显示快捷键?