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]

Patch: FYI: PR 20056


I'm checking this in.

The verifier has a special case for putfield, as it is valid to use
putfield on a locally-declared field before 'this' has been
initialized in a constructor.

We weren't checking all the preconditions properly, resulting in a
spurious verification error in the test case in the PR.

This patch adds the other preconditions.  Tested against the PR, and
also by recompiling Eclipse's bytecode.  We don't really have any
other better tests of bytecode compilation.

Tom

Index: gcc/java/ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	PR java/20056:
	* verify-glue.c (vfy_class_has_field): New function.
	* verify.h (vfy_class_has_field): Declare.
	* verify-impl.c (check_field_constant): Added 'putfield'
	argument.
	(verify_instructions_0): Updated.
	(types_equal): New function.

Index: libjava/ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	PR java/20056:
	* include/jvm.h (_Jv_Linker::has_field_p): Declare.
	* link.cc (has_field_p): New function.
	* verify.cc (check_field_constant): Added 'putfield' argument.
	(verify_instructions_0): Updated.
	(type::equals): New method.

Index: libjava/verify.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/verify.cc,v
retrieving revision 1.65
diff -u -r1.65 verify.cc
--- libjava/verify.cc 25 Nov 2004 03:46:57 -0000 1.65
+++ libjava/verify.cc 19 Feb 2005 00:25:11 -0000
@@ -1,6 +1,6 @@
 // verify.cc - verify bytecode
 
-/* Copyright (C) 2001, 2002, 2003, 2004  Free Software Foundation
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -751,6 +751,20 @@
       return klass->compatible(k.klass, verifier);
     }
 
+    bool equals (const type &other, _Jv_BytecodeVerifier *vfy)
+    {
+      // Only works for reference types.
+      if (key != reference_type
+	  || key != uninitialized_reference_type
+	  || other.key != reference_type
+	  || other.key != uninitialized_reference_type)
+	return false;
+      // Only for single-valued types.
+      if (klass->ref_next || other.klass->ref_next)
+	return false;
+      return klass->equals (other.klass, vfy);
+    }
+
     bool isvoid () const
     {
       return key == void_type;
@@ -1963,7 +1977,9 @@
   }
 
   // Return field's type, compute class' type if requested.
-  type check_field_constant (int index, type *class_type = NULL)
+  // If PUTFIELD is true, use the special 'putfield' semantics.
+  type check_field_constant (int index, type *class_type = NULL,
+			     bool putfield = false)
   {
     _Jv_Utf8Const *name, *field_type;
     type ct = handle_field_or_method (index,
@@ -1971,9 +1987,25 @@
 				      &name, &field_type);
     if (class_type)
       *class_type = ct;
+    type result;
     if (field_type->first() == '[' || field_type->first() == 'L')
-      return type (field_type, this);
-    return get_type_val_for_signature (field_type->first());
+      result = type (field_type, this);
+    else
+      result = get_type_val_for_signature (field_type->first());
+
+    // We have an obscure special case here: we can use `putfield' on
+    // a field declared in this class, even if `this' has not yet been
+    // initialized.
+    if (putfield
+	&& ! current_state->this_type.isinitialized ()
+	&& current_state->this_type.pc == type::SELF
+	&& current_state->this_type.equals (ct, this)
+	// We don't look at the signature, figuring that if it is
+	// wrong we will fail during linking.  FIXME?
+	&& _Jv_Linker::has_field_p (current_class, name))
+      class_type->set_uninitialized (type::SELF, this);
+
+    return result;
   }
 
   type check_method_constant (int index, bool is_interface,
@@ -2783,15 +2815,8 @@
 	  case op_putfield:
 	    {
 	      type klass;
-	      type field = check_field_constant (get_ushort (), &klass);
+	      type field = check_field_constant (get_ushort (), &klass, true);
 	      pop_type (field);
-
-	      // We have an obscure special case here: we can use
-	      // `putfield' on a field declared in this class, even if
-	      // `this' has not yet been initialized.
-	      if (! current_state->this_type.isinitialized ()
-		  && current_state->this_type.pc == type::SELF)
-		klass.set_uninitialized (type::SELF, this);
 	      pop_type (klass);
 	    }
 	    break;
Index: libjava/link.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/link.cc,v
retrieving revision 1.8
diff -u -r1.8 link.cc
--- libjava/link.cc 17 Feb 2005 19:17:07 -0000 1.8
+++ libjava/link.cc 19 Feb 2005 00:25:11 -0000
@@ -131,6 +131,18 @@
   return NULL;
 }
 
+bool
+_Jv_Linker::has_field_p (jclass search, _Jv_Utf8Const *field_name)
+{
+  for (int i = 0; i < search->field_count; ++i)
+    {
+      _Jv_Field *field = &search->fields[i];
+      if (_Jv_equalUtf8Consts (field->name, field_name))
+	return true;
+    }
+  return false;
+}
+
 // Find a field.
 // KLASS is the class that is requesting the field.
 // OWNER is the class in which the field should be found.
Index: libjava/include/jvm.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/jvm.h,v
retrieving revision 1.76
diff -u -r1.76 jvm.h
--- libjava/include/jvm.h 16 Feb 2005 20:01:41 -0000 1.76
+++ libjava/include/jvm.h 19 Feb 2005 00:25:11 -0000
@@ -278,6 +278,7 @@
 
 public:
 
+  static bool has_field_p (jclass, _Jv_Utf8Const *);
   static void print_class_loaded (jclass);
   static void resolve_class_ref (jclass, jclass *);
   static void wait_for_state(jclass, int);

Index: gcc/java/verify-glue.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/verify-glue.c,v
retrieving revision 1.3
diff -u -r1.3 verify-glue.c
--- gcc/java/verify-glue.c 25 Nov 2004 08:00:33 -0000 1.3
+++ gcc/java/verify-glue.c 19 Feb 2005 00:25:45 -0000
@@ -1,5 +1,5 @@
 /* Glue to interface gcj with bytecode verifier.
-   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -385,6 +385,21 @@
   return TYPE_NULL;
 }
 
+bool
+vfy_class_has_field (vfy_jclass klass, vfy_string name,
+		     vfy_string signature)
+{
+  tree field = TYPE_FIELDS (klass);
+  while (field != NULL_TREE)
+    {
+      if (DECL_NAME (field) == name
+	  && build_java_signature (TREE_TYPE (field)) == signature)
+	return true;
+      field = TREE_CHAIN (field);
+    }
+  return false;
+}
+
 int
 vfy_fail (const char *message, int pc, vfy_jclass ignore1 ATTRIBUTE_UNUSED,
 	  vfy_method *ignore2 ATTRIBUTE_UNUSED)
Index: gcc/java/verify-impl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/verify-impl.c,v
retrieving revision 1.4
diff -u -r1.4 verify-impl.c
--- gcc/java/verify-impl.c 17 Jan 2005 19:29:04 -0000 1.4
+++ gcc/java/verify-impl.c 19 Feb 2005 00:25:46 -0000
@@ -738,6 +738,20 @@
   return ref_compatible (t->klass, k->klass);
 }
 
+/* Return true if two types are equal.  Only valid for reference
+   types.  */
+static bool
+types_equal (type *t1, type *t2)
+{
+  if (t1->key != reference_type || t1->key != uninitialized_reference_type
+      || t2->key != reference_type || t2->key != uninitialized_reference_type)
+    return false;
+  /* Only single-ref types are allowed.  */
+  if (t1->klass->ref_next || t2->klass->ref_next)
+    return false;
+  return refs_equal (t1->klass, t2->klass);
+}
+
 static bool
 type_isvoid (type *t)
 {
@@ -2117,9 +2131,10 @@
   return check_class_constant (class_index);
 }
 
-/* Return field's type, compute class' type if requested.  */
+/* Return field's type, compute class' type if requested.  If
+   PUTFIELD is true, use the special 'putfield' semantics.  */
 static type
-check_field_constant (int index, type *class_type)
+check_field_constant (int index, type *class_type, bool putfield)
 {
   vfy_string name, field_type;
   const char *typec;
@@ -2137,6 +2152,17 @@
     init_type_from_string (&t, field_type);
   else
     init_type_from_tag (&t, get_type_val_for_signature (typec[0]));
+
+  /* We have an obscure special case here: we can use `putfield' on a
+     field declared in this class, even if `this' has not yet been
+     initialized.  */
+  if (putfield
+      && ! type_initialized (&vfr->current_state->this_type)
+      && vfr->current_state->this_type.pc == SELF
+      && types_equal (&vfr->current_state->this_type, &ct)
+      && vfy_class_has_field (vfr->current_class, name, field_type))
+    type_set_uninitialized (class_type, SELF);
+
   return t;
 }
 
@@ -2971,15 +2997,15 @@
 	  invalidate_pc ();
 	  break;
 	case op_getstatic:
-	  push_type_t (check_field_constant (get_ushort (), NULL));
+	  push_type_t (check_field_constant (get_ushort (), NULL, false));
 	  break;
 	case op_putstatic:
-	  pop_type_t (check_field_constant (get_ushort (), NULL));
+	  pop_type_t (check_field_constant (get_ushort (), NULL, false));
 	  break;
 	case op_getfield:
 	  {
 	    type klass;
-	    type field = check_field_constant (get_ushort (), &klass);
+	    type field = check_field_constant (get_ushort (), &klass, false);
 	    pop_type_t (klass);
 	    push_type_t (field);
 	  }
@@ -2987,15 +3013,8 @@
 	case op_putfield:
 	  {
 	    type klass;
-	    type field = check_field_constant (get_ushort (), &klass);
+	    type field = check_field_constant (get_ushort (), &klass, true);
 	    pop_type_t (field);
-
-	    /* We have an obscure special case here: we can use
-	       `putfield' on a field declared in this class, even if
-	       `this' has not yet been initialized.  */
-	    if (! type_initialized (&vfr->current_state->this_type)
-		&& vfr->current_state->this_type.pc == SELF)
-	      type_set_uninitialized (&klass, SELF);
 	    pop_type_t (klass);
 	  }
 	  break;
Index: gcc/java/verify.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/verify.h,v
retrieving revision 1.3
diff -u -r1.3 verify.h
--- gcc/java/verify.h 25 Nov 2004 07:03:55 -0000 1.3
+++ gcc/java/verify.h 19 Feb 2005 00:25:46 -0000
@@ -1,5 +1,5 @@
 /* Declarations to interface gcj with bytecode verifier.
-   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -126,6 +126,8 @@
 void vfy_note_local_type (vfy_method *method, int pc, int slot,
 			  vfy_jclass type);
 void vfy_note_instruction_seen (int pc);
+bool vfy_class_has_field (vfy_jclass klass, vfy_string name,
+			  vfy_string signature);
 
 #define GLOM(name, stuff) name ## stuff
 #define VFY_PRIMITIVE_CLASS(name) \


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