Ejemplo n.º 1
0
void
check_for_initialization (tree body, tree mdecl)
{
  tree decl;
  word buf[2];
  words before = buf;
  tree owner = DECL_CONTEXT (mdecl);
  int is_static_method = METHOD_STATIC (mdecl);
  /* We don't need to check final fields of <init> it it calls this(). */
  int is_finit_method = DECL_FINIT_P (mdecl) || DECL_INSTINIT_P (mdecl);
  int is_init_method
    = (is_finit_method || DECL_CLINIT_P (mdecl)
       || (DECL_INIT_P (mdecl) && ! DECL_INIT_CALLS_THIS (mdecl)));

  start_current_locals = num_current_locals = 0;
  num_current_words = 2;

  if (is_init_method)
    {
      int words_needed, i;
      for (decl = TYPE_FIELDS (owner);
	   decl != NULL_TREE;  decl = TREE_CHAIN (decl))
	{
	  if (DECL_FINAL (decl) && FIELD_STATIC (decl) == is_static_method)
	    {
	      if (DECL_FIELD_FINAL_IUD (decl))
		DECL_BIT_INDEX (decl) = -1;
	      else
		DECL_BIT_INDEX (decl) = num_current_locals++;
	    }
	}
      words_needed = WORDS_NEEDED (2 * num_current_locals);
      if (words_needed > 2)
	{
	  num_current_words = words_needed;
	  before = ALLOC_WORDS(words_needed);
	}
      i = 0;
      for (decl = TYPE_FIELDS (owner);
	   decl != NULL_TREE;  decl = TREE_CHAIN (decl))
	{
	  if (FIELD_FINAL (decl) && FIELD_STATIC (decl) == is_static_method)
	    {
	      if (! DECL_FIELD_FINAL_IUD (decl))
		{
		  CLEAR_ASSIGNED (before, i);
		  SET_UNASSIGNED (before, i);
		  i++;
		}
	    }
	}

    }

  check_init (body, before);

  if (is_init_method)
    {
      for (decl = TYPE_FIELDS (owner);
	   decl != NULL_TREE;  decl = TREE_CHAIN (decl))
	{
	  if (FIELD_FINAL (decl) && FIELD_STATIC (decl) == is_static_method)
	    {
	      int index = DECL_BIT_INDEX (decl);
	      if (index >= 0 && ! ASSIGNED_P (before, index))
		{
		  if (! is_finit_method)
		    error ("%Jfinal field %qD may not have been initialized",
                           decl, decl);
		}
	      else if (is_finit_method)
		DECL_FIELD_FINAL_IUD (decl) = 1;

	      /* Re-set to initial state, since we later may use the
		 same bit for DECL_POINTER_ALIAS_SET. */
	      DECL_BIT_INDEX (decl) = -1;
	    }
	}
    }

  start_current_locals = num_current_locals = 0;
}
Ejemplo n.º 2
0
/* Recursively mark reference fields.  */
static void
mark_reference_fields (tree field,
		       wide_int *mask,
		       unsigned int ubit,
		       int *pointer_after_end,
		       int *all_bits_set,
		       int *last_set_index,
		       HOST_WIDE_INT *last_view_index)
{
  /* See if we have fields from our superclass.  */
  if (DECL_NAME (field) == NULL_TREE)
    {
      mark_reference_fields (TYPE_FIELDS (TREE_TYPE (field)),
			     mask, ubit,
			     pointer_after_end, all_bits_set,
			     last_set_index, last_view_index);
      field = DECL_CHAIN (field);
    }

  for (; field != NULL_TREE; field = DECL_CHAIN (field))
    {
      HOST_WIDE_INT offset;
      HOST_WIDE_INT size_bytes;

      if (FIELD_STATIC (field))
	continue;

      offset = int_byte_position (field);
      size_bytes = int_size_in_bytes (TREE_TYPE (field));

      if (JREFERENCE_TYPE_P (TREE_TYPE (field))
	  /* An `object' of type gnu.gcj.RawData is actually non-Java
	     data.  */
	  && TREE_TYPE (field) != rawdata_ptr_type_node)
	{
	  unsigned int count;
	  unsigned int size_words;
	  unsigned int i;

	  /* If this reference slot appears to overlay a slot we think
	     we already covered, then we are doomed.  */
	  gcc_assert (offset > *last_view_index);

	  if (offset % (HOST_WIDE_INT) (POINTER_SIZE / BITS_PER_UNIT))
	    {
	      *all_bits_set = -1;
	      *pointer_after_end = 1;
	      break;
	    }

	  count = offset * BITS_PER_UNIT / POINTER_SIZE;
	  size_words = size_bytes * BITS_PER_UNIT / POINTER_SIZE;

	  *last_set_index = count;
	     
	  if (count >= ubit - 2)
	    *pointer_after_end = 1;
	  else
	    /* First word in object corresponds to most significant byte of 
	       bitmap. 
	     
	       In the case of a multiple-word record, we set pointer 
	       bits for all words in the record. This is conservative, but the 
	       size_words != 1 case is impossible in regular java code. */
	    for (i = 0; i < size_words; ++i)
	      *mask = wi::set_bit (*mask, ubit - count - i - 1);

	  /* If we saw a non-reference field earlier, then we can't
	     use the count representation.  We keep track of that in
	     *ALL_BITS_SET.  */
	  if (! *all_bits_set)
	    *all_bits_set = -1;
	}
      else if (*all_bits_set > 0)
	*all_bits_set = 0;

      *last_view_index = offset;
    }
}
Ejemplo n.º 3
0
static void
check_init (tree exp, words before)
{
  tree tmp;
 again:
  switch (TREE_CODE (exp))
    {
    case VAR_DECL:
    case PARM_DECL:
      if (! FIELD_STATIC (exp) && DECL_NAME (exp) != NULL_TREE
	  && DECL_NAME (exp) != this_identifier_node)
	{
	  int index = DECL_BIT_INDEX (exp);
	  /* We don't want to report and mark as non-initialized class
	     initialization flags. */
	  if (! LOCAL_CLASS_INITIALIZATION_FLAG_P (exp)
	      && index >= 0 && ! ASSIGNED_P (before, index))
	    {
	      parse_error_context 
		(wfl, "Variable %qs may not have been initialized",
		 IDENTIFIER_POINTER (DECL_NAME (exp)));
	      /* Suppress further errors. */
	      DECL_BIT_INDEX (exp) = -2;
	    }
	}
      break;

    case COMPONENT_REF:
      check_init (TREE_OPERAND (exp, 0), before);
      if ((tmp = get_variable_decl (exp)) != NULL_TREE)
	{
	  int index = DECL_BIT_INDEX (tmp);
	  if (index >= 0 && ! ASSIGNED_P (before, index))
	    {
	      parse_error_context 
		(wfl, "variable %qs may not have been initialized",
		 IDENTIFIER_POINTER (DECL_NAME (tmp)));
	      /* Suppress further errors. */
	      DECL_BIT_INDEX (tmp) = -2;
	    }
	}
      break;
      
    case MODIFY_EXPR:
      tmp = TREE_OPERAND (exp, 0);
      /* We're interested in variable declaration and parameter
         declaration when they're declared with the `final' modifier. */
      if ((tmp = get_variable_decl (tmp)) != NULL_TREE)
	{
	  int index;
	  check_init (TREE_OPERAND (exp, 1), before);
	  check_final_reassigned (tmp, before);
	  index = DECL_BIT_INDEX (tmp);
	  if (index >= 0)
	    {
	      SET_ASSIGNED (before, index);
	      CLEAR_UNASSIGNED (before, index);
	    }
	  /* Minor optimization.  See comment for start_current_locals.
	     If we're optimizing for class initialization, we keep
	     this information to check whether the variable is
	     definitely assigned when once we checked the whole
	     function. */
	  if (! STATIC_CLASS_INIT_OPT_P () /* FIXME */
	      && ! DECL_FINAL (tmp)
	      && index >= start_current_locals
	      && index == num_current_locals - 1)
	    {
	      num_current_locals--;
	      DECL_BIT_INDEX (tmp) = -1;
	    }
	 break;
       }
      else if (TREE_CODE (tmp = TREE_OPERAND (exp, 0)) == COMPONENT_REF)
	{
	  tree decl;
	  check_init (tmp, before);
	  check_init (TREE_OPERAND (exp, 1), before);
	  decl = TREE_OPERAND (tmp, 1);
	  if (DECL_FINAL (decl))
	    final_assign_error (DECL_NAME (decl));
	  break;
	}
      else if (TREE_CODE (tmp) == COMPONENT_REF && IS_ARRAY_LENGTH_ACCESS (tmp))
	{
	  /* We can't emit a more specific message here, because when
	     compiling to bytecodes we don't get here. */
	  final_assign_error (length_identifier_node);
	}
     else
       goto binop;
    case BLOCK:
      if (BLOCK_EXPR_BODY (exp))
	{
	  tree decl = BLOCK_EXPR_DECLS (exp);
	  int words_needed;
	  word* tmp;
	  int i;
	  int save_start_current_locals = start_current_locals;
	  int save_num_current_words = num_current_words;
	  start_current_locals = num_current_locals;
	  for (;  decl != NULL_TREE;  decl = TREE_CHAIN (decl))
	    {
	      DECL_BIT_INDEX (decl) = num_current_locals++;
	    }
	  words_needed = WORDS_NEEDED (2 * num_current_locals);
	  if (words_needed > num_current_words)
	    {
	      tmp = ALLOC_WORDS (words_needed);
	      COPY (tmp, before);
	      num_current_words = words_needed;
	    }
	  else
	    tmp = before;
	  for (i = start_current_locals;  i < num_current_locals;  i++)
	    {
	      CLEAR_ASSIGNED (tmp, i);
	      SET_UNASSIGNED (tmp, i);
	    }
	  check_init (BLOCK_EXPR_BODY (exp), tmp);

	  /* Re-set DECL_BIT_INDEX since it is also DECL_POINTER_ALIAS_SET. */
	  for (decl = BLOCK_EXPR_DECLS (exp);
	       decl != NULL_TREE;  decl = TREE_CHAIN (decl))
	    {
	      if (LOCAL_CLASS_INITIALIZATION_FLAG_P (decl))
		{
		  int index = DECL_BIT_INDEX (decl);
		  tree fndecl = DECL_CONTEXT (decl);
		  if (fndecl && METHOD_STATIC (fndecl)
		      && (DECL_INITIAL (decl) == boolean_true_node
			  || (index >= 0 && ASSIGNED_P (tmp, index))))
		    *(htab_find_slot 
		      (DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl),
		       DECL_FUNCTION_INIT_TEST_CLASS (decl), INSERT)) =
		      DECL_FUNCTION_INIT_TEST_CLASS (decl);
		}
	      DECL_BIT_INDEX (decl) = -1;
	    }

	  num_current_locals = start_current_locals;
	  start_current_locals = save_start_current_locals;
	  if (tmp != before)
	    {
	      num_current_words = save_num_current_words;
	      COPY (before, tmp);
	      FREE_WORDS (tmp);
	    }
	}
      break;
    case LOOP_EXPR:
      {
	/* The JLS 2nd edition discusses a complication determining
	   definite unassignment of loop statements.  They define a
	   "hypothetical" analysis model.  We do something much
	   simpler: We just disallow assignments inside loops to final
	   variables declared outside the loop.  This means we may
	   disallow some contrived assignments that the JLS allows, but I
	   can't see how anything except a very contrived testcase (a
	   do-while whose condition is false?) would care. */

	struct alternatives alt;
	int save_loop_current_locals = loop_current_locals;
	int save_start_current_locals = start_current_locals;
	loop_current_locals = num_current_locals;
	start_current_locals = num_current_locals;
	BEGIN_ALTERNATIVES (before, alt);
	alt.block = exp;
	check_init (TREE_OPERAND (exp, 0), before);
	END_ALTERNATIVES (before, alt);
	loop_current_locals = save_loop_current_locals;
	start_current_locals = save_start_current_locals;
	return;
      }
    case EXIT_EXPR:
      {
	struct alternatives *alt = alternatives;
	DECLARE_BUFFERS(when_true, 2);
	words when_false = when_true + num_current_words;
#ifdef ENABLE_JC1_CHECKING
	if (TREE_CODE (alt->block) != LOOP_EXPR)
	  abort ();
#endif
	check_bool_init (TREE_OPERAND (exp, 0), before, when_false, when_true);
	done_alternative (when_true, alt);
	COPY (before, when_false);
	RELEASE_BUFFERS(when_true);
	return;
      }
    case LABELED_BLOCK_EXPR:
      {
	struct alternatives alt;
	BEGIN_ALTERNATIVES (before, alt);
	alt.block = exp;
	if (LABELED_BLOCK_BODY (exp))
	  check_init (LABELED_BLOCK_BODY (exp), before);
	done_alternative (before, &alt);
	END_ALTERNATIVES (before, alt);
	return;
      }
    case EXIT_BLOCK_EXPR:
      {
	tree block = TREE_OPERAND (exp, 0);
	struct alternatives *alt = alternatives;
	while (alt->block != block)
	  alt = alt->outer;
	done_alternative (before, alt);
	SET_ALL (before);
	return;
      }
    case SWITCH_EXPR:
      {
	struct alternatives alt;
	word buf[2];
	check_init (TREE_OPERAND (exp, 0), before);
	BEGIN_ALTERNATIVES (before, alt);
	alt.saved = ALLOC_BUFFER(buf, num_current_words);
	COPY (alt.saved, before);
	alt.block = exp;
	check_init (TREE_OPERAND (exp, 1), before);
	done_alternative (before, &alt);
	if (! SWITCH_HAS_DEFAULT (exp))
	  done_alternative (alt.saved, &alt);
	FREE_BUFFER(alt.saved, buf);
	END_ALTERNATIVES (before, alt);
	return;
      }
    case CASE_EXPR:
    case DEFAULT_EXPR:
      {
	int i;
	struct alternatives *alt = alternatives;
	while (TREE_CODE (alt->block) != SWITCH_EXPR)
	  alt = alt->outer;
	COPYN (before, alt->saved, WORDS_NEEDED (2 * alt->num_locals));
	for (i = alt->num_locals;  i < num_current_locals;  i++)
	  CLEAR_ASSIGNED (before, i);
	break;
      }

    case TRY_EXPR:
      {
	tree try_clause = TREE_OPERAND (exp, 0);
	tree clause = TREE_OPERAND (exp, 1);
	word buf[2*2];
	words tmp = (num_current_words <= 2 ? buf
		    : ALLOC_WORDS (2 * num_current_words));
	words save = tmp + num_current_words;
	struct alternatives alt;
	BEGIN_ALTERNATIVES (before, alt);
	COPY (save, before);
	COPY (tmp, save);
	check_init (try_clause, tmp);
	done_alternative (tmp, &alt);
	for ( ; clause != NULL_TREE;  clause = TREE_CHAIN (clause))
	  {
	    tree catch_clause = TREE_OPERAND (clause, 0);
	    COPY (tmp, save);
	    check_init (catch_clause, tmp);
	    done_alternative (tmp, &alt);
	  }
	if (tmp != buf)
	  {
	    FREE_WORDS (tmp);
	  }
	END_ALTERNATIVES (before, alt);
      }
    return;

    case TRY_FINALLY_EXPR:
      {
	DECLARE_BUFFERS(tmp, 1);
	COPY (tmp, before);
	check_init (TREE_OPERAND (exp, 0), before);
	check_init (TREE_OPERAND (exp, 1), tmp);
	UNION (before, before, tmp);
	RELEASE_BUFFERS(tmp);
      }
      return;

    case RETURN_EXPR:
    case THROW_EXPR:
      if (TREE_OPERAND (exp, 0))
	check_init (TREE_OPERAND (exp, 0), before);
      goto never_continues;

    case ERROR_MARK:
    never_continues:
      SET_ALL (before);
      return;
      
    case COND_EXPR:
    case TRUTH_ANDIF_EXPR:
    case TRUTH_ORIF_EXPR:
      {
	DECLARE_BUFFERS(when_true, 2);
	words when_false = when_true + num_current_words;
	check_bool_init (exp, before, when_false, when_true);
	INTERSECT (before, when_false, when_true);
	RELEASE_BUFFERS(when_true);
      }
      break;

    case NOP_EXPR:
      if (IS_EMPTY_STMT (exp))
	break;
      /* ... else fall through ... */
    case UNARY_PLUS_EXPR:
    case NEGATE_EXPR:
    case TRUTH_AND_EXPR:
    case TRUTH_OR_EXPR:
    case TRUTH_XOR_EXPR:
    case TRUTH_NOT_EXPR:
    case BIT_NOT_EXPR:
    case CONVERT_EXPR:
    case BIT_FIELD_REF:
    case FLOAT_EXPR:
    case FIX_TRUNC_EXPR:
    case INDIRECT_REF:
    case ADDR_EXPR:
    case NON_LVALUE_EXPR:
    case INSTANCEOF_EXPR:
    case FIX_CEIL_EXPR:
    case FIX_FLOOR_EXPR:
    case FIX_ROUND_EXPR:
    case ABS_EXPR:
      /* Avoid needless recursion. */
      exp = TREE_OPERAND (exp, 0);
      goto again;

    case PREDECREMENT_EXPR:
    case PREINCREMENT_EXPR:
    case POSTDECREMENT_EXPR:
    case POSTINCREMENT_EXPR:
      tmp = get_variable_decl (TREE_OPERAND (exp, 0));
      if (tmp != NULL_TREE && DECL_FINAL (tmp))
	final_assign_error (DECL_NAME (tmp));      

      /* Avoid needless recursion.  */
      exp = TREE_OPERAND (exp, 0);
      goto again;

    case SAVE_EXPR:
      if (IS_INIT_CHECKED (exp))
	return;
      IS_INIT_CHECKED (exp) = 1;
      exp = TREE_OPERAND (exp, 0);
      goto again;

    case COMPOUND_EXPR:
    case PLUS_EXPR:
    case MINUS_EXPR:
    case MULT_EXPR:
    case TRUNC_DIV_EXPR:
    case TRUNC_MOD_EXPR:
    case RDIV_EXPR:
    case LSHIFT_EXPR:
    case RSHIFT_EXPR:
    case URSHIFT_EXPR:
    case BIT_AND_EXPR:
    case BIT_XOR_EXPR:
    case BIT_IOR_EXPR:
    case EQ_EXPR: 
    case NE_EXPR:
    case GT_EXPR:
    case GE_EXPR:
    case LT_EXPR:
    case LE_EXPR:
    case MAX_EXPR:
    case MIN_EXPR:
    case ARRAY_REF:
    case LROTATE_EXPR:
    case RROTATE_EXPR:
    case CEIL_DIV_EXPR:
    case FLOOR_DIV_EXPR:
    case ROUND_DIV_EXPR:
    case CEIL_MOD_EXPR:
    case FLOOR_MOD_EXPR:
    case ROUND_MOD_EXPR:
    case EXACT_DIV_EXPR:
    case UNLT_EXPR:
    case UNLE_EXPR:
    case UNGT_EXPR:
    case UNGE_EXPR:
    case UNEQ_EXPR:
    case LTGT_EXPR:
    binop:
      check_init (TREE_OPERAND (exp, 0), before);
      /* Avoid needless recursion, especially for COMPOUND_EXPR. */
      exp = TREE_OPERAND (exp, 1);
      goto again;

    case RESULT_DECL:
    case FUNCTION_DECL:
    case INTEGER_CST:
    case REAL_CST:
    case STRING_CST:
    case JAVA_EXC_OBJ_EXPR:
      break;

    case NEW_CLASS_EXPR:
    case CALL_EXPR:
      {
	tree func = TREE_OPERAND (exp, 0);
	tree x = TREE_OPERAND (exp, 1);
	if (TREE_CODE (func) == ADDR_EXPR)
	  func = TREE_OPERAND (func, 0);
	check_init (func, before);

	for ( ;  x != NULL_TREE;  x = TREE_CHAIN (x))
	  check_init (TREE_VALUE (x), before);
	if (func == throw_node)
	  goto never_continues;
      }
      break;

    case NEW_ARRAY_INIT:
      {
	tree x = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0));
	for ( ;  x != NULL_TREE;  x = TREE_CHAIN (x))
	  check_init (TREE_VALUE (x), before);
      }
      break;

    case EXPR_WITH_FILE_LOCATION:
      {
	location_t saved_location = input_location;
	tree saved_wfl = wfl;
	tree body = EXPR_WFL_NODE (exp);
	if (IS_EMPTY_STMT (body))
	  break;
	wfl = exp;
#ifdef USE_MAPPED_LOCATION
	input_location = EXPR_LOCATION (exp);
#else
	input_filename = EXPR_WFL_FILENAME (exp);
	input_line = EXPR_WFL_LINENO (exp);
#endif
	check_init (body, before);
	input_location = saved_location;
	wfl = saved_wfl;
      }
      break;
      
    default:
      internal_error
	("internal error in check-init: tree code not implemented: %s",
	 tree_code_name [(int) TREE_CODE (exp)]);
    }
}