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