This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PR 16431: Bytecode compiler silently generates incorrect code


With some class files, debug information can change the code that we
generate.  This is because the structure of the debug information
doesn't necessarily correspond to the structure of the program itself:
for example, a variable might change its name in the debug info, but
the semantics of the bytecode virtual machine require its value to be
preserved.  This is a potential security hole that might be exploited
by carefully crafted class files.

This patch alters the bytecode front end so that we only allocate
variables of reference type based on the slot numbers in the VM, not
the named variables in the debug info.  For debugging, we copy values
from VM slots when in scope.

This has the unfortunate effect that assignments to named debug
variables will be deleted as dead stores when optimizing.  This to a
large extent happens anyway, but can be fixed by tweaking the debug
output data to make the debug variable occupy the same locations as
the corresponding stack slots.  I intend to make that change at some
point in the future.

This patch was motivated by problems compiling JOnAS, a huge piece of
software, and tested on it.

Andrew.

2004-07-19  Andrew Haley  <aph@redhat.com>

	* verify.c (verify_jvm_instructions): Comment change only.

	* typeck.c (build_java_array_type): Add size field to array name.

	* java-tree.h (LOCAL_SLOT_P): New.
	(update_aliases): Add PC argument.
	(pushdecl_function_level): New function.

	* java-gimplify.c (java_gimplify_expr): Handle VAR_DECL,
          MODIFY_EXPR, and SAVE_EXPR.
	(java_gimplify_modify_expr): New function.

	* expr.c (push_type_0): Call find_stack_slot() to create temporary.
	(expand_iinc): Pass PC to update_aliases().
	(STORE_INTERNAL): Likewise.
	(process_jvm_instruction): Likewise.

	* decl.c (base_decl_map): New variable.
	(uniq): New variable.
	(update_aliases): Rewrite with more thorough checking.
	(debug_variable_p): New function.
	(push_jvm_slot): Don't initialize local variable.  Don't pushdecl.
	(check_local_named_variable): Delete whole function.
	(initialize_local_variable): New function.
	(check_local_unnamed_variable): Add checks and comments.
	(find_local_variable): Rewrite.
	(java_replace_reference): New function.
	(function_binding_level): New variable.
	(pushdecl_function_level): New function.
	(maybe_pushlevels): Set DECL_LOCAL_END_PC.
	(maybe_pushlevels): Call pushdecl() on each of the new decls.
	(start_java_method): Reset uniq.  Create base_decl_map.  Set
	function_binding_level.
	(end_java_method): Null unused fields to save memory.

Index: java/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.188
diff -p -2 -c -r1.188 decl.c
*** java/decl.c	18 Jul 2004 13:17:03 -0000	1.188
--- java/decl.c	20 Jul 2004 14:22:54 -0000
*************** static tree push_promoted_type (const ch
*** 58,62 ****
  static struct binding_level *make_binding_level (void);
  static tree create_primitive_vtable (const char *);
- static tree check_local_named_variable (tree, tree, int, int *);
  static tree check_local_unnamed_variable (tree, tree, tree);
  
--- 58,61 ----
*************** tree java_io_serializable_identifier_nod
*** 77,80 ****
--- 76,88 ----
  static GTY(()) tree decl_map;
  
+ /* The base_decl_map is contains one variable of ptr_type: this is
+    used to contain every variable of reference type that is ever
+    stored in a local variable slot.  */
+ 
+ static GTY(()) tree base_decl_map;
+ 
+ /* An index used to make temporary identifiers unique.  */
+ static int uniq;
+ 
  /* A list of local variables VAR_DECLs for this method that we have seen
     debug information, but we have not reached their starting (byte) PC yet. */
*************** static GTY(()) tree decl_map;
*** 82,88 ****
  static GTY(()) tree pending_local_decls;
  
- /* Push a local variable or stack slot into the decl_map,
-    and assign it an rtl. */
- 
  #if defined(DEBUG_JAVA_BINDING_LEVELS)
  int binding_depth = 0;
--- 90,93 ----
*************** indent (void)
*** 100,120 ****
  #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
  
! /* Copy the value in decl into every alias in the same local variable
!    slot.  */
  void 
! update_aliases (tree decl, int index)
  {
!   tree tmp = TREE_VEC_ELT (decl_map, index);
!   tree type = TREE_TYPE (decl);
!   while (tmp != NULL_TREE)
      {
        if (tmp != decl
! 	  && ! LOCAL_VAR_OUT_OF_SCOPE_P (tmp)
! 	  && TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (tmp)))
  	{
! 	  tree src = build1 (NOP_EXPR, TREE_TYPE (tmp), decl);
! 	  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (tmp), tmp, src));
  	}
-       tmp = DECL_LOCAL_SLOT_CHAIN (tmp);      
      }
  }
--- 105,160 ----
  #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
  
! /* True if decl is a named local variable, i.e. if it is an alias
!    that's used only for debugging purposes.  */
! 
! static bool
! debug_variable_p (tree decl)
! {
!   if (TREE_CODE (decl) == PARM_DECL)
!     return false;
! 
!   if (LOCAL_SLOT_P (decl))
!     return false;
! 
!   return true;
! }
!  
! /* Copy the value in decl into every live alias in the same local
!    variable slot.  Some of these will be dead stores removed by the
!    optimizer.  */
! 
  void 
! update_aliases (tree decl, int index, int pc)
  {
!   tree decl_type = TREE_TYPE (decl);
!   tree tmp;
! 
!   if (debug_variable_p (decl))
!     abort ();
! 
!   for (tmp = TREE_VEC_ELT (decl_map, index); 
!        tmp != NULL_TREE; 
!        tmp = DECL_LOCAL_SLOT_CHAIN (tmp))
      {
+       tree tmp_type = TREE_TYPE (tmp);
        if (tmp != decl
! 	  && LOCAL_SLOT_P (tmp) == 0
! 	  && (pc == -1
! 	      || (pc >= DECL_LOCAL_START_PC (tmp)
! 		  && pc <= DECL_LOCAL_END_PC (tmp)))
! 	  && (tmp_type == decl_type
! 	      || (INTEGRAL_TYPE_P (tmp_type)
! 		  && INTEGRAL_TYPE_P (decl_type)
! 		  && TYPE_PRECISION (decl_type) <= 32
! 		  && TYPE_PRECISION (tmp_type) <= 32)
! 	      || (TREE_CODE (tmp_type) == POINTER_TYPE
! 		  && TREE_CODE (decl_type) == POINTER_TYPE)))
  	{
! 	  tree src = build1 (NOP_EXPR, tmp_type, decl);
! 	  if (LOCAL_VAR_OUT_OF_SCOPE_P (tmp))
! 	    abort ();
! 	  java_add_stmt 
! 	    (build (MODIFY_EXPR, tmp_type, tmp, src));
  	}
      }
  }
*************** static tree
*** 123,148 ****
  push_jvm_slot (int index, tree decl)
  {
-   tree type = TREE_TYPE (decl);
-   tree tmp;
- 
    DECL_CONTEXT (decl) = current_function_decl;
    layout_decl (decl, 0);
  
-   /* Look for another variable of the same mode in this slot.  */ 
-   tmp = TREE_VEC_ELT (decl_map, index);
-   while (tmp != NULL_TREE)
-     {
-       if (! LOCAL_VAR_OUT_OF_SCOPE_P (tmp)
- 	  && TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (tmp)))
- 	{
- 	  /* At the point of its creation this decl inherits whatever
- 	     is in the slot.  */
- 	  tree src = build1 (NOP_EXPR, TREE_TYPE (decl), tmp);
- 	  java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, src));	
- 	  break;
- 	}
-       tmp = DECL_LOCAL_SLOT_CHAIN (tmp);
-     }
- 
    /* Now link the decl into the decl_map. */
    if (DECL_LANG_SPECIFIC (decl) == NULL)
--- 163,169 ----
*************** push_jvm_slot (int index, tree decl)
*** 156,184 ****
    TREE_VEC_ELT (decl_map, index) = decl;
  
-   if (TREE_CODE (decl) != PARM_DECL)
-     pushdecl (decl);
    return decl;
  }
  
! /* Find out if 'decl' passed in fits the defined PC location better than
!    'best'.  Return decl if it does, return best if it doesn't.  If decl
!    is returned, then updated is set to true.  */
  
! static tree
! check_local_named_variable (tree best, tree decl, int pc, int *updated)
  {
!   if (pc >= DECL_LOCAL_START_PC (decl)
!       && pc < DECL_LOCAL_END_PC (decl))
      {
!       if (best == NULL_TREE
! 	  || (DECL_LOCAL_START_PC (decl) > DECL_LOCAL_START_PC (best)
! 	      && DECL_LOCAL_END_PC (decl) < DECL_LOCAL_END_PC (best)))
          {
! 	  *updated = 1;
! 	  return decl;
  	}
      }
    
!   return best;
  }
  
--- 177,228 ----
    TREE_VEC_ELT (decl_map, index) = decl;
  
    return decl;
  }
  
! /*  At the point of its creation a local variable decl inherits
!     whatever is already in the same slot.  In the case of a local
!     variable that is declared but unused, we won't find anything.  */
  
! static void
! initialize_local_variable (tree decl, int index)
  {
!   tree decl_type = TREE_TYPE (decl);
!   if (TREE_CODE (decl_type) == POINTER_TYPE)
      {
!       tree tmp = TREE_VEC_ELT (base_decl_map, index);
! 
!       if (tmp)
          {
! 	  /* At the point of its creation this decl inherits whatever
! 	     is in the slot.  */
! 	  tree src = build1 (NOP_EXPR, decl_type, tmp);
! 	  java_add_stmt 
! 	    (build (MODIFY_EXPR, decl_type, decl, src));	
  	}
      }
+   else
+     {
+       tree tmp;
    
!       for (tmp = TREE_VEC_ELT (decl_map, index); 
! 	   tmp != NULL_TREE; 
! 	   tmp = DECL_LOCAL_SLOT_CHAIN (tmp))
! 	{
! 	  tree tmp_type = TREE_TYPE (tmp);
! 	  if (tmp != decl
! 	      && ! debug_variable_p (tmp)
! 	      && (tmp_type == decl_type
! 		  || (INTEGRAL_TYPE_P (tmp_type)
! 		      && INTEGRAL_TYPE_P (decl_type)
! 		      && TYPE_PRECISION (decl_type) <= 32
! 		      && TYPE_PRECISION (tmp_type) <= 32
! 		      && TYPE_PRECISION (tmp_type) >= TYPE_PRECISION (decl_type))))
! 	    {
! 	      java_add_stmt 
! 		(build (MODIFY_EXPR, decl_type, decl, tmp));	
! 	      return;
! 	    }
! 	}  
!     }
  }
  
*************** static tree
*** 189,202 ****
  check_local_unnamed_variable (tree best, tree decl, tree type)
  {
!     if (TREE_TYPE (decl) == type
! 	|| (TREE_CODE (TREE_TYPE (decl)) == TREE_CODE (type)
! 	    && TYPE_PRECISION (TREE_TYPE (decl)) <= 32
  	    && TYPE_PRECISION (type) <= 32
! 	    && TREE_CODE (type) != POINTER_TYPE)
  	|| (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
  	    && type == ptr_type_node))
        {
  	if (best == NULL_TREE
! 	    || (TREE_TYPE (decl) == type && TREE_TYPE (best) != type))
  	  return decl;
        }
--- 233,255 ----
  check_local_unnamed_variable (tree best, tree decl, tree type)
  {
!   tree decl_type = TREE_TYPE (decl);
!   
!   if (LOCAL_VAR_OUT_OF_SCOPE_P (decl))
!     abort ();
! 
!   /* Use the same decl for all integer types <= 32 bits.  This is
!      necessary because sometimes a value is stored as (for example)
!      boolean but loaded as int.  */
!   if (decl_type == type
!       || (INTEGRAL_TYPE_P (decl_type)
! 	  && INTEGRAL_TYPE_P (type)
! 	  && TYPE_PRECISION (decl_type) <= 32
  	    && TYPE_PRECISION (type) <= 32
! 	  && TYPE_PRECISION (decl_type) >= TYPE_PRECISION (type))      
  	|| (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
  	    && type == ptr_type_node))
        {
  	if (best == NULL_TREE
! 	  || (decl_type == type && TREE_TYPE (best) != type))
  	  return decl;
        }
*************** check_local_unnamed_variable (tree best,
*** 211,271 ****
  
  tree
! find_local_variable (int index, tree type, int pc)
  {
!   tree decl = TREE_VEC_ELT (decl_map, index);
!   tree best = NULL_TREE;
!   int found_scoped_var = 0;
! 
!   /* Scan through every declaration that has been created in this slot. */
!   while (decl != NULL_TREE)
!     {
!       bool has_name = false;
!       tree name = DECL_NAME (decl);
!       if (name && IDENTIFIER_POINTER (name))
! 	has_name = IDENTIFIER_POINTER (name)[0] != '#';
!       
!        /* Variables created in give_name_to_locals() have a name and have
!  	 a specified scope, so we can handle them specifically.  We want
!  	 to use the specific decls created for those so they are assigned
!  	 the right variables in the debugging information. */
!       if (has_name)
! 	{
! 	  /* This is a variable we have a name for, so it has a scope
! 	     supplied in the class file.  But it only matters when we
! 	     actually have a PC to use.  If pc<0, then we are asking
! 	     for a stack slot and this decl won't be one of those. */
!  	  if (pc >= 0)
!  	    best = check_local_named_variable (best, decl, pc,
!  					       &found_scoped_var);
!  	}
!       /* We scan for type information unless we found a variable in the
! 	 proper scope already. */
!       else if (!found_scoped_var)
!  	{
!  	  /* If we don't have scoping information for a variable, we use
!  	     a different method to look it up. */
!  	  best = check_local_unnamed_variable (best, decl, type);
!  	}
  
!       decl = DECL_LOCAL_SLOT_CHAIN (decl);
      }
  
-   if (best != NULL_TREE)
-     return best;
- 
    /* If we don't find a match, create one with the type passed in.
!      Ths name of the variable is #n#m, which n is the variable index
       in the local variable area and m is a dummy identifier for
       uniqueness -- multiple variables may share the same local
!      variable index.  */
    {
      char buf[64];
      tree name;
!     static int uniq;
!     sprintf (buf, "#%d#%d", index, uniq++);
!     name = get_identifier (buf);
  
!     return push_jvm_slot (index, build_decl (VAR_DECL, name, type));
!   }
  }
  
--- 264,364 ----
  
  tree
! find_local_variable (int index, tree type, int pc ATTRIBUTE_UNUSED)
  {
!   tree tmp = TREE_VEC_ELT (decl_map, index);
!   tree decl = NULL_TREE;
  
!   /* Scan through every declaration that has been created in this
!      slot.  We're only looking for variables that correspond to local
!      index declarations and PARM_DECLs, not named variables: such
!      local variables are used only for debugging information.  */
!   while (tmp != NULL_TREE)
!     {
!       if (! debug_variable_p (tmp))
! 	decl = check_local_unnamed_variable (decl, tmp, type);
!       tmp = DECL_LOCAL_SLOT_CHAIN (tmp);
      }
  
    /* If we don't find a match, create one with the type passed in.
!      The name of the variable is #n#m, which n is the variable index
       in the local variable area and m is a dummy identifier for
       uniqueness -- multiple variables may share the same local
!      variable index.  We don't call pushdecl() to push pointer types
!      into a binding expr because they'll all be replaced by a single
!      variable that is used for every reference in that local variable
!      slot.  */
!   if (! decl)
    {
      char buf[64];
      tree name;
!       sprintf (buf, "#slot#%d#%d", index, uniq++);
!       name = get_identifier (buf);
!       decl = build_decl (VAR_DECL, name, type);
!       DECL_IGNORED_P (decl) = 1;
!       DECL_ARTIFICIAL (decl) = 1;
!       decl = push_jvm_slot (index, decl);
!       LOCAL_SLOT_P (decl) = 1;
! 
!       if (TREE_CODE (type) != POINTER_TYPE)
! 	pushdecl_function_level (decl);
!     }
! 
!   /* As well as creating a local variable that matches the type, we
!      also create a base variable (of ptr_type) that will hold all its
!      aliases.  */
!   if (TREE_CODE (type) == POINTER_TYPE
!       && ! TREE_VEC_ELT (base_decl_map, index))
!     {
!       char buf[64];
!       tree name;
!       tree base_decl;
!       sprintf (buf, "#ref#%d#%d", index, uniq++);
!       name = get_identifier (buf);
!       base_decl
! 	= TREE_VEC_ELT (base_decl_map, index)
! 	= build_decl (VAR_DECL, name, ptr_type_node);
!       pushdecl_function_level (base_decl);
!       DECL_IGNORED_P (base_decl) = 1;
!       DECL_ARTIFICIAL (base_decl) = 1;
!     }
  
!   return decl;
! }
! 
! /* Called during gimplification for every variable.  If the variable
!    is a temporary of pointer type, replace it with a common variable
!    thath is used to hold all pointer types that are ever stored in
!    that slot.  Set WANT_LVALUE if you want a variable that is to be
!    written to.  */
! 
! tree 
! java_replace_reference (tree var_decl, bool want_lvalue)
! {
!   tree decl_type;
! 
!   if (! base_decl_map)
!     return var_decl;
! 
!   decl_type = TREE_TYPE (var_decl);
! 
!   if (TREE_CODE (decl_type) == POINTER_TYPE)
!     {
!       if (DECL_LANG_SPECIFIC (var_decl)
! 	  && LOCAL_SLOT_P (var_decl))
! 	{
! 	  int index = DECL_LOCAL_SLOT_NUMBER (var_decl);
! 	  tree base_decl = TREE_VEC_ELT (base_decl_map, index); 
! 
! 	  if (! base_decl)
! 	    abort ();
! 
! 	  if (! want_lvalue)
! 	    base_decl = build1 (NOP_EXPR, decl_type, base_decl);
! 
! 	  return base_decl;
! 	}
!     }
! 
!   return var_decl;
  }
  
*************** static GTY(()) struct binding_level *fre
*** 332,335 ****
--- 425,433 ----
  static GTY(()) struct binding_level *global_binding_level;
  
+ /* The binding level that holds variables declared at the outermost
+    level within a function body.  */
+ 
+ static struct binding_level *function_binding_level;
+ 
  /* A PC value bigger than any PC value we may ever may encounter. */
  
*************** pushdecl_top_level (tree x)
*** 1175,1178 ****
--- 1273,1290 ----
  }
  
+ /* Like pushdecl, only it places X in FUNCTION_BINDING_LEVEL, if appropriate.  */
+ 
+ tree
+ pushdecl_function_level (tree x)
+ {
+   tree t;
+   struct binding_level *b = current_binding_level;
+ 
+   current_binding_level = function_binding_level;
+   t = pushdecl (x);
+   current_binding_level = b;
+   return t;
+ }
+ 
  /* Nonzero if we are currently in the global binding level.  */
  
*************** maybe_pushlevels (int pc)
*** 1498,1504 ****
        *ptr = NULL_TREE;
  
!       /* Force non-nested range to be nested in current range. */
        if (end_pc > current_binding_level->end_pc)
! 	end_pc = current_binding_level->end_pc;
  
        maybe_start_try (pc, end_pc);
--- 1610,1620 ----
        *ptr = NULL_TREE;
  
!       /* Force non-nested range to be nested in current range by
! 	 truncating variable lifetimes. */
        if (end_pc > current_binding_level->end_pc)
! 	{
! 	  end_pc = current_binding_level->end_pc;
! 	  DECL_LOCAL_END_PC (decl) = end_pc;
! 	}
  
        maybe_start_try (pc, end_pc);
*************** maybe_pushlevels (int pc)
*** 1513,1516 ****
--- 1629,1634 ----
  	  next = TREE_CHAIN (decl);
  	  push_jvm_slot (DECL_LOCAL_SLOT_NUMBER (decl), decl);
+ 	  pushdecl (decl);
+ 	  initialize_local_variable (decl, DECL_LOCAL_SLOT_NUMBER (decl));
  	}
      }      
*************** start_java_method (tree fndecl)
*** 1699,1702 ****
--- 1817,1822 ----
    int i;
  
+   uniq = 0;
+ 
    current_function_decl = fndecl;
    announce_function (fndecl);
*************** start_java_method (tree fndecl)
*** 1704,1707 ****
--- 1824,1828 ----
    i = DECL_MAX_LOCALS(fndecl) + DECL_MAX_STACK(fndecl);
    decl_map = make_tree_vec (i);
+   base_decl_map = make_tree_vec (i);
    type_map = xrealloc (type_map, i * sizeof (tree));
  
*************** start_java_method (tree fndecl)
*** 1752,1755 ****
--- 1873,1878 ----
    /* Push local variables.  */
    pushlevel (2);
+ 
+   function_binding_level = current_binding_level;
  }
  
*************** end_java_method (void)
*** 1778,1781 ****
--- 1901,1912 ----
        DECL_INITIAL (fndecl) = NULL_TREE;
      }
+   if (! flag_unit_at_a_time)
+     {
+       /* Nulling these fields when we no longer need them saves
+ 	 memory.  */
+       DECL_SAVED_TREE (fndecl) = NULL;
+       DECL_STRUCT_FUNCTION (fndecl) = NULL;
+       DECL_INITIAL (fndecl) = NULL_TREE;
+     }
    current_function_decl = NULL_TREE;
  }
Index: java/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/expr.c,v
retrieving revision 1.199
diff -p -2 -c -r1.199 expr.c
*** java/expr.c	20 Jul 2004 12:25:42 -0000	1.199
--- java/expr.c	20 Jul 2004 14:22:54 -0000
*************** push_type_0 (tree type)
*** 256,259 ****
--- 256,262 ----
    if (stack_pointer + n_words > DECL_MAX_STACK (current_function_decl))
      return 0;
+   /* Allocate decl for this variable now, so we get a temporary that
+      survives the whole method. */
+   find_stack_slot (stack_pointer, type);
    stack_type_map[stack_pointer++] = type;
    n_words--;
*************** pop_type (tree type)
*** 369,373 ****
  }
  
! /* Return 1f if SOURCE_TYPE can be safely widened to TARGET_TYPE.
     Handles array types and interfaces.  */
  
--- 372,376 ----
  }
  
! /* Return 1 if SOURCE_TYPE can be safely widened to TARGET_TYPE.
     Handles array types and interfaces.  */
  
*************** expand_iinc (unsigned int local_var_inde
*** 1290,1294 ****
    res = fold (build2 (PLUS_EXPR, int_type_node, local_var, constant_value));
    java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (local_var), local_var, res));
!   update_aliases (local_var, local_var_index);
  }
  
--- 1293,1297 ----
    res = fold (build2 (PLUS_EXPR, int_type_node, local_var, constant_value));
    java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (local_var), local_var, res));
!   update_aliases (local_var, local_var_index, pc);
  }
  
*************** process_jvm_instruction (int PC, const u
*** 2759,2763 ****
      int saw_index = 0;							\
      int index     = OPERAND_VALUE;					\
!     build_java_ret (find_local_variable (index, ptr_type_node, oldpc));	\
    }
  
--- 2762,2767 ----
      int saw_index = 0;							\
      int index     = OPERAND_VALUE;					\
!     build_java_ret							\
!       (find_local_variable (index, return_address_type_node, oldpc));	\
    }
  
*************** process_jvm_instruction (int PC, const u
*** 2938,2942 ****
      set_local_type (index, type);				\
      java_add_stmt (build2 (MODIFY_EXPR, type, decl, value));	\
!     update_aliases (decl, index);				\
    }
  
--- 2942,2946 ----
      set_local_type (index, type);				\
      java_add_stmt (build2 (MODIFY_EXPR, type, decl, value));	\
!     update_aliases (decl, index, PC);				\
    }
  
Index: java/java-gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-gimplify.c,v
retrieving revision 1.7
diff -p -2 -c -r1.7 java-gimplify.c
*** java/java-gimplify.c	18 Jul 2004 13:17:03 -0000	1.7
--- java/java-gimplify.c	20 Jul 2004 14:22:55 -0000
*************** static tree java_gimplify_block (tree);
*** 38,41 ****
--- 38,42 ----
  static tree java_gimplify_new_array_init (tree);
  static tree java_gimplify_try_expr (tree);
+ static tree java_gimplify_modify_expr (tree);
  
  static void dump_java_tree (enum tree_dump_index, tree);
*************** java_gimplify_expr (tree *expr_p, tree *
*** 118,121 ****
--- 119,137 ----
        break;
  
+     case VAR_DECL:
+       *expr_p = java_replace_reference (*expr_p, /* want_lvalue */ false);
+       return GS_UNHANDLED;
+ 
+     case MODIFY_EXPR:
+       *expr_p = java_gimplify_modify_expr (*expr_p);
+       return GS_UNHANDLED;
+ 
+     case SAVE_EXPR:
+       if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == VAR_DECL)
+ 	TREE_OPERAND (*expr_p, 0) 
+ 	  = java_replace_reference (TREE_OPERAND (*expr_p, 0), 
+ 			       /* want_lvalue */ false);
+       return GS_UNHANDLED;
+ 
      /* These should already be lowered before we get here.  */
      case URSHIFT_EXPR:
*************** java_gimplify_expr (tree *expr_p, tree *
*** 141,144 ****
--- 157,187 ----
  }
  
+ /* This is specific to the bytecode compiler.  If a variable has
+    LOCAL_SLOT_P set, replace an assignment to it with an assignment to
+    the corresponding variable that holds all its aliases.  */
+ 
+ static tree
+ java_gimplify_modify_expr (tree modify_expr)
+ {
+   tree lhs = TREE_OPERAND (modify_expr, 0);
+   tree rhs = TREE_OPERAND (modify_expr, 1);
+   tree lhs_type = TREE_TYPE (lhs);
+   
+   if (TREE_CODE (lhs) == VAR_DECL
+       && DECL_LANG_SPECIFIC (lhs)
+       && LOCAL_SLOT_P (lhs)
+       && TREE_CODE (lhs_type) == POINTER_TYPE)
+     {
+       tree new_lhs = java_replace_reference (lhs, /* want_lvalue */ true);
+       tree new_rhs = build1 (NOP_EXPR, TREE_TYPE (new_lhs), rhs);
+       modify_expr = build (MODIFY_EXPR, TREE_TYPE (new_lhs),
+ 			   new_lhs, new_rhs);
+       modify_expr = build1 (NOP_EXPR, lhs_type, modify_expr);
+     }
+   
+   return modify_expr;
+ }
+ 
+     
  static tree
  java_gimplify_case_expr (tree expr)
Index: java/java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.213
diff -p -2 -c -r1.213 java-tree.h
*** java/java-tree.h	17 Jul 2004 19:35:04 -0000	1.213
--- java/java-tree.h	20 Jul 2004 14:22:55 -0000
*************** union lang_tree_node 
*** 926,929 ****
--- 926,931 ----
  #define LOCAL_VAR_OUT_OF_SCOPE_P(NODE) \
      (DECL_LANG_SPECIFIC (NODE)->u.v.freed)
+ #define LOCAL_SLOT_P(NODE) \
+     (DECL_LANG_SPECIFIC (NODE)->u.v.local_slot)
  /* Create a DECL_LANG_SPECIFIC if necessary. */
  #define MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC(T)			\
*************** struct lang_decl_var GTY(())
*** 1011,1015 ****
    unsigned int final_iud : 1;	/* Final initialized upon declaration */
    unsigned int cif : 1;		/* True: decl is a class initialization flag */
!   unsigned int freed;		/* Decl is no longer in scope.  */
  };
  
--- 1013,1018 ----
    unsigned int final_iud : 1;	/* Final initialized upon declaration */
    unsigned int cif : 1;		/* True: decl is a class initialization flag */
!   unsigned int freed : 1;		/* Decl is no longer in scope.  */
!   unsigned int local_slot : 1;	/* Decl is a temporary in the stack frame.  */
  };
  
*************** extern tree build_static_field_ref (tree
*** 1177,1181 ****
  extern tree build_address_of (tree);
  extern tree find_local_variable (int index, tree type, int pc);
! extern void update_aliases (tree decl, int index);
  extern tree find_stack_slot (int index, tree type);
  extern tree build_prim_array_type (tree, HOST_WIDE_INT);
--- 1180,1184 ----
  extern tree build_address_of (tree);
  extern tree find_local_variable (int index, tree type, int pc);
! extern void update_aliases (tree decl, int index, int pc);
  extern tree find_stack_slot (int index, tree type);
  extern tree build_prim_array_type (tree, HOST_WIDE_INT);
*************** extern void check_for_initialization (tr
*** 1255,1258 ****
--- 1258,1263 ----
  
  extern tree pushdecl_top_level (tree);
+ extern tree pushdecl_function_level (tree);
+ extern tree java_replace_reference (tree, bool);
  extern int alloc_class_constant (tree);
  extern void init_expr_processing (void);
Index: java/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/typeck.c,v
retrieving revision 1.67
diff -p -2 -c -r1.67 typeck.c
*** java/typeck.c	20 Jul 2004 12:25:50 -0000	1.67
--- java/typeck.c	20 Jul 2004 14:22:56 -0000
*************** build_java_array_type (tree element_type
*** 392,398 ****
    if (TREE_CODE (el_name) == TYPE_DECL)
      el_name = DECL_NAME (el_name);
!   TYPE_NAME (t) = build_decl (TYPE_DECL,
!                              identifier_subst (el_name, "", '.', '.', "[]"),
                               t);
  
    set_java_signature (t, sig);
--- 392,406 ----
    if (TREE_CODE (el_name) == TYPE_DECL)
      el_name = DECL_NAME (el_name);
!   {
!     char suffix[12];
!     if (length >= 0)
!       sprintf (suffix, "[%d]", (int)length); 
!     else
!       strcpy (suffix, "[]");
!     TYPE_NAME (t) 
!       = build_decl (TYPE_DECL,
! 		    identifier_subst (el_name, "", '.', '.', suffix),
                               t);
+   }
  
    set_java_signature (t, sig);
Index: java/verify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/verify.c,v
retrieving revision 1.63
diff -p -2 -c -r1.63 verify.c
*** java/verify.c	7 Jul 2004 10:21:03 -0000	1.63
--- java/verify.c	20 Jul 2004 14:22:56 -0000
*************** verify_jvm_instructions (JCF* jcf, const
*** 735,740 ****
  	prev_eh_ranges = NULL_EH_RANGE;
  
! 	/* Allocate decl and rtx for this variable now, so if we're not
! 	   optimizing, we get a temporary that survives the whole method.  */
  	find_local_variable (index, type, oldpc);
  
--- 735,740 ----
  	prev_eh_ranges = NULL_EH_RANGE;
  
! 	/* Allocate decl for this variable now, so we get a temporary
! ! 	   that survives the whole method. */
  	find_local_variable (index, type, oldpc);
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]