Patch: FYI: verifier fix

Tom Tromey tromey@redhat.com
Thu Jul 24 17:16:00 GMT 2003


I'm checking this in on the trunk.

This fixes PR 7482.  It is a big patch because it changes how types
are represented in the verifier.

The idea comes from Per, though of course I'm to blame for anything in
the implementation.  The basic plan is not to merge types at all, but
instead to record the complete list of possible types.  Then when any
type compatibility is checked, we can check against the exact list.

This lets us handle situations where the merge will strip interfaces
from the actual classes, leaving us with something that looks invalid
(for instance as a return type or as the object used with
invokeinterface).

I've included a test case, derived from PR 7482.
With this patch we still pass the Mauve verifier tests.

With this patch you should be able to run Eclipse without first
disabling the verifier.  This worked for me.


This patch isn't perfect; the new type representation requires (imo)
too many allocations.  I've added a FIXME comment for this problem.


There are still a couple existing verifier bugs.  There's a FIXME
concerning calling <init> -- I added this but the comment is
potentially incorrect; investigation is needed.  Also there are a few
checks unrelated to the actual bytcode chasing that we need to
implement.  (Unfortunately I don't know of the existence of an
exhaustive list of such checks, so knowing when we're done isn't easy.
And of course there are no tests for this.)

Tom


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

	For PR libgcj/7482:
	* verify.cc (ref_intersection): New class.
	(type_val): Removed unresolved_reference_type,
	uninitialized_unresolved_reference_type.
	(is_assignable_from_slow): Rewrote.
	(type::data): Removed.
	(type::klass): New field.
	(type::type): Added verifier argument.
	(type::resolve): Removed.
	(type::set_uninitialized): Updated for change to type_val.
	(type::set_initialized): Likewise.
	(type::isinitialized): Likewise.
	(type::print): Likewise.
	(construct_primitive_array_type): Likewise.
	(type::compatible): Updated for change to type_val and to use
	ref_intersection.
	(type::isarray): Updated to use ref_intersection.
	(type::isinterface): Likewise.
	(type::element_type): Likewise.
	(type::to_array): Likewise.
	(type::verify_dimensions): Rewrote.
	(type::merge): Likewise.
	(check_class_constant): Updated for type constructor change.
	(check_constant): Likewise.
	(check_field_constant): Likewise.
	(get_one_type): Likewise.
	(initialize_stack): Likewise.
	(verify_instructions_0): Likewise.
	(verify_instructions_0) [op_invokeinterface]: Removed special
	case.
	(isect_list): New field.
	(_Jv_BytecodeVerifier): Initialize it.
	(~_Jv_BytecodeVerifier): Destroy ref_intersection objects. 

Index: verify.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/verify.cc,v
retrieving revision 1.55
diff -u -r1.55 verify.cc
--- verify.cc 7 May 2003 01:25:20 -0000 1.55
+++ verify.cc 24 Jul 2003 17:10:00 -0000
@@ -1,4 +1,4 @@
-// defineclass.cc - defining a class from .class format.
+// verify.cc - verify bytecode
 
 /* Copyright (C) 2001, 2002, 2003  Free Software Foundation
 
@@ -58,6 +58,7 @@
   struct subr_info;
   struct subr_entry_info;
   struct linked_utf8;
+  struct ref_intersection;
 
   // The current PC.
   int PC;
@@ -104,6 +105,9 @@
   // but without this our utf8 objects would be collected.
   linked_utf8 *utf8_list;
 
+  // A linked list of all ref_intersection objects we allocate.
+  ref_intersection *isect_list;
+
   struct linked_utf8
   {
     _Jv_Utf8Const *val;
@@ -189,9 +193,219 @@
     // Everything after `reference_type' must be a reference type.
     reference_type,
     null_type,
-    unresolved_reference_type,
-    uninitialized_reference_type,
-    uninitialized_unresolved_reference_type
+    uninitialized_reference_type
+  };
+
+  // This represents a merged class type.  Some verifiers (including
+  // earlier versions of this one) will compute the intersection of
+  // two class types when merging states.  However, this loses
+  // critical information about interfaces implemented by the various
+  // classes.  So instead we keep track of all the actual classes that
+  // have been merged.
+  struct ref_intersection
+  {
+    // Whether or not this type has been resolved.
+    bool is_resolved;
+
+    // Actual type data.
+    union
+    {
+      // For a resolved reference type, this is a pointer to the class.
+      jclass klass;
+      // For other reference types, this it the name of the class.
+      _Jv_Utf8Const *name;
+    } data;
+
+    // Link to the next reference in the intersection.
+    ref_intersection *ref_next;
+
+    // This is used to keep track of all the allocated
+    // ref_intersection objects, so we can free them.
+    // FIXME: we should allocate these in chunks.
+    ref_intersection *alloc_next;
+
+    ref_intersection (jclass klass, _Jv_BytecodeVerifier *verifier)
+      : ref_next (NULL)
+    {
+      is_resolved = true;
+      data.klass = klass;
+      alloc_next = verifier->isect_list;
+      verifier->isect_list = this;
+    }
+
+    ref_intersection (_Jv_Utf8Const *name, _Jv_BytecodeVerifier *verifier)
+      : ref_next (NULL)
+    {
+      is_resolved = false;
+      data.name = name;
+      alloc_next = verifier->isect_list;
+      verifier->isect_list = this;
+    }
+
+    ref_intersection (ref_intersection *dup, ref_intersection *tail,
+		      _Jv_BytecodeVerifier *verifier)
+      : ref_next (tail)
+    {
+      is_resolved = dup->is_resolved;
+      data = dup->data;
+      alloc_next = verifier->isect_list;
+      verifier->isect_list = this;
+    }
+
+    bool equals (ref_intersection *other, _Jv_BytecodeVerifier *verifier)
+    {
+      if (! is_resolved && ! other->is_resolved
+	  && _Jv_equalUtf8Consts (data.name, other->data.name))
+	return true;
+      if (! is_resolved)
+	resolve (verifier);
+      if (! other->is_resolved)
+	other->resolve (verifier);
+      return data.klass == other->data.klass;
+    }
+
+    // Merge THIS type into OTHER, returning the result.  This will
+    // return OTHER if all the classes in THIS already appear in
+    // OTHER.
+    ref_intersection *merge (ref_intersection *other,
+			     _Jv_BytecodeVerifier *verifier)
+    {
+      ref_intersection *tail = other;
+      for (ref_intersection *self = this; self != NULL; self = self->ref_next)
+	{
+	  bool add = true;
+	  for (ref_intersection *iter = other; iter != NULL;
+	       iter = iter->ref_next)
+	    {
+	      if (iter->equals (self, verifier))
+		{
+		  add = false;
+		  break;
+		}
+	    }
+
+	  if (add)
+	    tail = new ref_intersection (self, tail, verifier);
+	}
+      return tail;
+    }
+
+    void resolve (_Jv_BytecodeVerifier *verifier)
+    {
+      if (is_resolved)
+	return;
+
+      using namespace java::lang;
+      java::lang::ClassLoader *loader
+	= verifier->current_class->getClassLoaderInternal();
+      // We might see either kind of name.  Sigh.
+      if (data.name->data[0] == 'L'
+	  && data.name->data[data.name->length - 1] == ';')
+	data.klass = _Jv_FindClassFromSignature (data.name->data, loader);
+      else
+	data.klass = Class::forName (_Jv_NewStringUtf8Const (data.name),
+				     false, loader);
+      is_resolved = true;
+    }
+
+    // See if an object of type OTHER can be assigned to an object of
+    // type *THIS.  This might resolve classes in one chain or the
+    // other.
+    bool compatible (ref_intersection *other,
+		     _Jv_BytecodeVerifier *verifier)
+    {
+      ref_intersection *self = this;
+
+      for (; self != NULL; self = self->ref_next)
+	{
+	  ref_intersection *other_iter = other;
+
+	  for (; other_iter != NULL; other_iter = other_iter->ref_next)
+	    {
+	      // Avoid resolving if possible.
+	      if (! self->is_resolved
+		  && ! other_iter->is_resolved
+		  && _Jv_equalUtf8Consts (self->data.name,
+					  other_iter->data.name))
+		continue;
+
+	      if (! self->is_resolved)
+		self->resolve(verifier);
+	      if (! other_iter->is_resolved)
+		other_iter->resolve(verifier);
+
+	      if (! is_assignable_from_slow (self->data.klass,
+					     other_iter->data.klass))
+		return false;
+	    }
+	}
+
+      return true;
+    }
+
+    bool isarray ()
+    {
+      // assert (ref_next == NULL);
+      if (is_resolved)
+	return data.klass->isArray ();
+      else
+	return data.name->data[0] == '[';
+    }
+
+    bool isinterface (_Jv_BytecodeVerifier *verifier)
+    {
+      // assert (ref_next == NULL);
+      if (! is_resolved)
+	resolve (verifier);
+      return data.klass->isInterface ();
+    }
+
+    bool isabstract (_Jv_BytecodeVerifier *verifier)
+    {
+      // assert (ref_next == NULL);
+      if (! is_resolved)
+	resolve (verifier);
+      using namespace java::lang::reflect;
+      return Modifier::isAbstract (data.klass->getModifiers ());
+    }
+
+    jclass getclass (_Jv_BytecodeVerifier *verifier)
+    {
+      if (! is_resolved)
+	resolve (verifier);
+      return data.klass;
+    }
+
+    int count_dimensions ()
+    {
+      int ndims = 0;
+      if (is_resolved)
+	{
+	  jclass k = data.klass;
+	  while (k->isArray ())
+	    {
+	      k = k->getComponentType ();
+	      ++ndims;
+	    }
+	}
+      else
+	{
+	  char *p = data.name->data;
+	  while (*p++ == '[')
+	    ++ndims;
+	}
+      return ndims;
+    }
+
+    void *operator new (size_t bytes)
+    {
+      return _Jv_Malloc (bytes);
+    }
+
+    void operator delete (void *mem)
+    {
+      _Jv_Free (mem);
+    }
   };
 
   // Return the type_val corresponding to a primitive signature
@@ -244,8 +458,21 @@
   // TARGET haven't been prepared.
   static bool is_assignable_from_slow (jclass target, jclass source)
   {
-    // This will terminate when SOURCE==Object.
-    while (true)
+    // First, strip arrays.
+    while (target->isArray ())
+      {
+	// If target is array, source must be as well.
+	if (! source->isArray ())
+	  return false;
+	target = target->getComponentType ();
+	source = source->getComponentType ();
+      }
+
+    // Quick success.
+    if (target == &java::lang::Object::class$)
+      return true;
+
+    do
       {
 	if (source == target)
 	  return true;
@@ -253,49 +480,21 @@
 	if (target->isPrimitive () || source->isPrimitive ())
 	  return false;
 
-	if (target->isArray ())
-	  {
-	    if (! source->isArray ())
-	      return false;
-	    target = target->getComponentType ();
-	    source = source->getComponentType ();
-	  }
-	else if (target->isInterface ())
+	if (target->isInterface ())
 	  {
 	    for (int i = 0; i < source->interface_count; ++i)
 	      {
 		// We use a recursive call because we also need to
 		// check superinterfaces.
 		if (is_assignable_from_slow (target, source->interfaces[i]))
-		    return true;
-	      }
-	    source = source->getSuperclass ();
-	    if (source == NULL)
-	      return false;
-	  }
-	// We must do this check before we check to see if SOURCE is
-	// an interface.  This way we know that any interface is
-	// assignable to an Object.
-	else if (target == &java::lang::Object::class$)
-	  return true;
-	else if (source->isInterface ())
-	  {
-	    for (int i = 0; i < target->interface_count; ++i)
-	      {
-		// We use a recursive call because we also need to
-		// check superinterfaces.
-		if (is_assignable_from_slow (target->interfaces[i], source))
 		  return true;
 	      }
-	    target = target->getSuperclass ();
-	    if (target == NULL)
-	      return false;
 	  }
-	else if (source == &java::lang::Object::class$)
-	  return false;
-	else
-	  source = source->getSuperclass ();
+	source = source->getSuperclass ();
       }
+    while (source != NULL);
+
+    return false;
   }
 
   // This is used to keep track of which `jsr's correspond to a given
@@ -324,16 +523,12 @@
   // verifier.
   struct type
   {
-    // The type.
+    // The type key.
     type_val key;
-    // Some associated data.
-    union
-    {
-      // For a resolved reference type, this is a pointer to the class.
-      jclass klass;
-      // For other reference types, this it the name of the class.
-      _Jv_Utf8Const *name;
-    } data;
+
+    // For reference types, the representation of the type.
+    ref_intersection *klass;
+
     // This is used when constructing a new object.  It is the PC of the
     // `new' instruction which created the object.  We use the special
     // value -2 to mean that this is uninitialized, and the special
@@ -348,7 +543,7 @@
     type ()
     {
       key = unsuitable_type;
-      data.klass = NULL;
+      klass = NULL;
       pc = UNINIT;
     }
 
@@ -357,25 +552,26 @@
     type (type_val k)
     {
       key = k;
-      data.klass = NULL;
-      if (key == reference_type)
-	data.klass = &java::lang::Object::class$;
+      // For reference_type, if KLASS==NULL then that means we are
+      // looking for a generic object of any kind, including an
+      // uninitialized reference.
+      klass = NULL;
       pc = UNINIT;
     }
 
     // Make a new instance given a class.
-    type (jclass klass)
+    type (jclass k, _Jv_BytecodeVerifier *verifier)
     {
       key = reference_type;
-      data.klass = klass;
+      klass = new ref_intersection (k, verifier);
       pc = UNINIT;
     }
 
     // Make a new instance given the name of a class.
-    type (_Jv_Utf8Const *n)
+    type (_Jv_Utf8Const *n, _Jv_BytecodeVerifier *verifier)
     {
-      key = unresolved_reference_type;
-      data.name = n;
+      key = reference_type;
+      klass = new ref_intersection (n, verifier);
       pc = UNINIT;
     }
 
@@ -383,7 +579,7 @@
     type (const type &t)
     {
       key = t.key;
-      data = t.data;
+      klass = t.klass;
       pc = t.pc;
     }
 
@@ -402,7 +598,7 @@
     type& operator= (type_val k)
     {
       key = k;
-      data.klass = NULL;
+      klass = NULL;
       pc = UNINIT;
       return *this;
     }
@@ -410,7 +606,7 @@
     type& operator= (const type& t)
     {
       key = t.key;
-      data = t.data;
+      klass = t.klass;
       pc = t.pc;
       return *this;
     }
@@ -424,35 +620,11 @@
       return *this;
     }
 
-    // If *THIS is an unresolved reference type, resolve it.
-    void resolve (_Jv_BytecodeVerifier *verifier)
-    {
-      if (key != unresolved_reference_type
-	  && key != uninitialized_unresolved_reference_type)
-	return;
-
-      using namespace java::lang;
-      java::lang::ClassLoader *loader
-	= verifier->current_class->getClassLoaderInternal();
-      // We might see either kind of name.  Sigh.
-      if (data.name->data[0] == 'L'
-	  && data.name->data[data.name->length - 1] == ';')
-	data.klass = _Jv_FindClassFromSignature (data.name->data, loader);
-      else
-	data.klass = Class::forName (_Jv_NewStringUtf8Const (data.name),
-				     false, loader);
-      key = (key == unresolved_reference_type
-	     ? reference_type
-	     : uninitialized_reference_type);
-    }
-
     // Mark this type as the uninitialized result of `new'.
     void set_uninitialized (int npc, _Jv_BytecodeVerifier *verifier)
     {
       if (key == reference_type)
 	key = uninitialized_reference_type;
-      else if (key == unresolved_reference_type)
-	key = uninitialized_unresolved_reference_type;
       else
 	verifier->verify_fail ("internal error in type::uninitialized");
       pc = npc;
@@ -461,13 +633,9 @@
     // Mark this type as now initialized.
     void set_initialized (int npc)
     {
-      if (npc != UNINIT && pc == npc
-	  && (key == uninitialized_reference_type
-	      || key == uninitialized_unresolved_reference_type))
-	{
-	  key = (key == uninitialized_reference_type
-		 ? reference_type
-		 : unresolved_reference_type);
+      if (npc != UNINIT && pc == npc && key == uninitialized_reference_type)
+	{
+	  key = reference_type;
 	  pc = UNINIT;
 	}
     }
@@ -488,14 +656,16 @@
 
       // The `null' type is convertible to any initialized reference
       // type.
-      if (key == null_type || k.key == null_type)
-	return true;
+      if (key == null_type)
+	return k.key != uninitialized_reference_type;
+      if (k.key == null_type)
+	return key != uninitialized_reference_type;
 
-      // Any reference type is convertible to Object.  This is a special
-      // case so we don't need to unnecessarily resolve a class.
-      if (key == reference_type
-	  && data.klass == &java::lang::Object::class$)
+      // A special case for a generic reference.
+      if (klass == NULL)
 	return true;
+      if (k.klass == NULL)
+	verifier->verify_fail ("programmer error in type::compatible");
 
       // An initialized type and an uninitialized type are not
       // compatible.
@@ -511,16 +681,7 @@
 	    return false;
 	}
 
-      // Two unresolved types are equal if their names are the same.
-      if (! isresolved ()
-	  && ! k.isresolved ()
-	  && _Jv_equalUtf8Consts (data.name, k.data.name))
-	return true;
-
-      // We must resolve both types and check assignability.
-      resolve (verifier);
-      k.resolve (verifier);
-      return is_assignable_from_slow (data.klass, k.data.klass);
+      return klass->compatible(k.klass, verifier);
     }
 
     bool isvoid () const
@@ -545,9 +706,7 @@
       // We treat null_type as not an array.  This is ok based on the
       // current uses of this method.
       if (key == reference_type)
-	return data.klass->isArray ();
-      else if (key == unresolved_reference_type)
-	return data.name->data[0] == '[';
+	return klass->isarray ();
       return false;
     }
 
@@ -558,33 +717,28 @@
 
     bool isinterface (_Jv_BytecodeVerifier *verifier)
     {
-      resolve (verifier);
       if (key != reference_type)
 	return false;
-      return data.klass->isInterface ();
+      return klass->isinterface (verifier);
     }
 
     bool isabstract (_Jv_BytecodeVerifier *verifier)
     {
-      resolve (verifier);
       if (key != reference_type)
 	return false;
-      using namespace java::lang::reflect;
-      return Modifier::isAbstract (data.klass->getModifiers ());
+      return klass->isabstract (verifier);
     }
 
     // Return the element type of an array.
     type element_type (_Jv_BytecodeVerifier *verifier)
     {
-      // FIXME: maybe should do string manipulation here.
-      resolve (verifier);
       if (key != reference_type)
 	verifier->verify_fail ("programmer error in type::element_type()", -1);
 
-      jclass k = data.klass->getComponentType ();
+      jclass k = klass->getclass (verifier)->getComponentType ();
       if (k->isPrimitive ())
 	return type (verifier->get_type_val_for_signature (k));
-      return type (k);
+      return type (k, verifier);
     }
 
     // Return the array type corresponding to an initialized
@@ -592,16 +746,12 @@
     // types, but currently we don't need to.
     type to_array (_Jv_BytecodeVerifier *verifier)
     {
-      // Resolving isn't ideal, because it might force us to load
-      // another class, but it's easy.  FIXME?
-      if (key == unresolved_reference_type)
-	resolve (verifier);
-
-      if (key == reference_type)
-	return type (_Jv_GetArrayClass (data.klass,
-					data.klass->getClassLoaderInternal()));
-      else
+      if (key != reference_type)
 	verifier->verify_fail ("internal error in type::to_array()");
+
+      jclass k = klass->getclass (verifier);
+      return type (_Jv_GetArrayClass (k, k->getClassLoaderInternal()),
+		   verifier);
     }
 
     bool isreference () const
@@ -616,9 +766,7 @@
 
     bool isinitialized () const
     {
-      return (key == reference_type
-	      || key == null_type
-	      || key == unresolved_reference_type);
+      return key == reference_type || key == null_type;
     }
 
     bool isresolved () const
@@ -631,24 +779,10 @@
     void verify_dimensions (int ndims, _Jv_BytecodeVerifier *verifier)
     {
       // The way this is written, we don't need to check isarray().
-      if (key == reference_type)
-	{
-	  jclass k = data.klass;
-	  while (k->isArray () && ndims > 0)
-	    {
-	      k = k->getComponentType ();
-	      --ndims;
-	    }
-	}
-      else
-	{
-	  // We know KEY == unresolved_reference_type.
-	  char *p = data.name->data;
-	  while (*p++ == '[' && ndims-- > 0)
-	    ;
-	}
+      if (key != reference_type)
+	verifier->verify_fail ("internal error in verify_dimensions: not a reference type");
 
-      if (ndims > 0)
+      if (klass->count_dimensions () < ndims)
 	verifier->verify_fail ("array type has fewer dimensions than required");
     }
 
@@ -682,53 +816,12 @@
 		    verifier->verify_fail ("merging different uninitialized types");
 		}
 
-	      if (! isresolved ()
-		  && ! old_type.isresolved ()
-		  && _Jv_equalUtf8Consts (data.name, old_type.data.name))
+	      ref_intersection *merged = old_type.klass->merge (klass,
+								verifier);
+	      if (merged != klass)
 		{
-		  // Types are identical.
-		}
-	      else
-		{
-		  resolve (verifier);
-		  old_type.resolve (verifier);
-
-		  jclass k = data.klass;
-		  jclass oldk = old_type.data.klass;
-
-		  int arraycount = 0;
-		  while (k->isArray () && oldk->isArray ())
-		    {
-		      ++arraycount;
-		      k = k->getComponentType ();
-		      oldk = oldk->getComponentType ();
-		    }
-
-		  // Ordinarily this terminates when we hit Object...
-		  while (k != NULL)
-		    {
-		      if (is_assignable_from_slow (k, oldk))
-			break;
-		      k = k->getSuperclass ();
-		      changed = true;
-		    }
-		  // ... but K could have been an interface, in which
-		  // case we'll end up here.  We just convert this
-		  // into Object.
-		  if (k == NULL)
-		    k = &java::lang::Object::class$;
-
-		  if (changed)
-		    {
-		      while (arraycount > 0)
-			{
-			  java::lang::ClassLoader *loader
-			    = verifier->current_class->getClassLoaderInternal();
-			  k = _Jv_GetArrayClass (k, loader);
-			  --arraycount;
-			}
-		      data.klass = k;
-		    }
+		  klass = merged;
+		  changed = true;
 		}
 	    }
 	}
@@ -782,9 +875,7 @@
 	case unused_by_subroutine_type: c = '_'; break;
 	case reference_type: c = 'L'; break;
 	case null_type: c = '@'; break;
-	case unresolved_reference_type: c = 'l'; break;
 	case uninitialized_reference_type: c = 'U'; break;
-	case uninitialized_unresolved_reference_type: c = 'u'; break;
 	}
       debug_print ("%c", c);
     }
@@ -1624,9 +1715,7 @@
       case unused_by_subroutine_type:
       case reference_type:
       case null_type:
-      case unresolved_reference_type:
       case uninitialized_reference_type:
-      case uninitialized_unresolved_reference_type:
       default:
 	verify_fail ("unknown type in construct_primitive_array_type");
       }
@@ -1997,9 +2086,9 @@
     check_pool_index (index);
     _Jv_Constants *pool = &current_class->constants;
     if (pool->tags[index] == JV_CONSTANT_ResolvedClass)
-      return type (pool->data[index].clazz);
+      return type (pool->data[index].clazz, this);
     else if (pool->tags[index] == JV_CONSTANT_Class)
-      return type (pool->data[index].utf8);
+      return type (pool->data[index].utf8, this);
     verify_fail ("expected class constant", start_PC);
   }
 
@@ -2009,7 +2098,7 @@
     _Jv_Constants *pool = &current_class->constants;
     if (pool->tags[index] == JV_CONSTANT_ResolvedString
 	|| pool->tags[index] == JV_CONSTANT_String)
-      return type (&java::lang::String::class$);
+      return type (&java::lang::String::class$, this);
     else if (pool->tags[index] == JV_CONSTANT_Integer)
       return type (int_type);
     else if (pool->tags[index] == JV_CONSTANT_Float)
@@ -2065,7 +2154,7 @@
     if (class_type)
       *class_type = ct;
     if (field_type->data[0] == '[' || field_type->data[0] == 'L')
-      return type (field_type);
+      return type (field_type, this);
     return get_type_val_for_signature (field_type->data[0]);
   }
 
@@ -2099,7 +2188,7 @@
 	  ++p;
 	++p;
 	_Jv_Utf8Const *name = make_utf8_const (start, p - start);
-	return type (name);
+	return type (name, this);
       }
 
     // Casting to jchar here is ok since we are looking at an ASCII
@@ -2116,7 +2205,7 @@
     jclass k = construct_primitive_array_type (rt);
     while (--arraycount > 0)
       k = _Jv_GetArrayClass (k, NULL);
-    return type (k);
+    return type (k, this);
   }
 
   void compute_argument_types (_Jv_Utf8Const *signature,
@@ -2160,7 +2249,7 @@
     using namespace java::lang::reflect;
     if (! Modifier::isStatic (current_method->self->accflags))
       {
-	type kurr (current_class);
+	type kurr (current_class, this);
 	if (is_init)
 	  {
 	    kurr.set_uninitialized (type::SELF, this);
@@ -2287,7 +2376,7 @@
 	  {
 	    if (PC >= exception[i].start_pc.i && PC < exception[i].end_pc.i)
 	      {
-		type handler (&java::lang::Throwable::class$);
+		type handler (&java::lang::Throwable::class$, this);
 		if (exception[i].handler_type.i != 0)
 		  handler = check_class_constant (exception[i].handler_type.i);
 		push_exception_jump (handler, exception[i].handler_pc.i);
@@ -2959,33 +3048,13 @@
 		    {
 		      // In this case the PC doesn't matter.
 		      t.set_uninitialized (type::UNINIT, this);
+		      // FIXME: check to make sure that the <init>
+		      // call is to the right class.
+		      // It must either be super or an exact class
+		      // match.
 		    }
 		  type raw = pop_raw ();
-		  bool ok = false;
-		  if (! is_init && ! raw.isinitialized ())
-		    {
-		      // This is a failure.
-		    }
-		  else if (is_init && raw.isnull ())
-		    {
-		      // Another failure.
-		    }
-		  else if (t.compatible (raw, this))
-		    {
-		      ok = true;
-		    }
-		  else if (opcode == op_invokeinterface)
-		    {
-		      // This is a hack.  We might have merged two
-		      // items and gotten `Object'.  This can happen
-		      // because we don't keep track of where merges
-		      // come from.  This is safe as long as the
-		      // interpreter checks interfaces at runtime.
-		      type obj (&java::lang::Object::class$);
-		      ok = raw.compatible (obj, this);
-		    }
-
-		  if (! ok)
+		  if (! t.compatible (raw, this))
 		    verify_fail ("incompatible type on stack");
 
 		  if (is_init)
@@ -3017,7 +3086,8 @@
 	      if (atype < boolean_type || atype > long_type)
 		verify_fail ("type not primitive", start_PC);
 	      pop_type (int_type);
-	      push_type (construct_primitive_array_type (type_val (atype)));
+	      type t (construct_primitive_array_type (type_val (atype)), this);
+	      push_type (t);
 	    }
 	    break;
 	  case op_anewarray:
@@ -3033,7 +3103,7 @@
 	    }
 	    break;
 	  case op_athrow:
-	    pop_type (type (&java::lang::Throwable::class$));
+	    pop_type (type (&java::lang::Throwable::class$, this));
 	    invalidate_pc ();
 	    break;
 	  case op_checkcast:
@@ -3178,6 +3248,7 @@
     flags = NULL;
     jsr_ptrs = NULL;
     utf8_list = NULL;
+    isect_list = NULL;
     entry_points = NULL;
   }
 
@@ -3219,6 +3290,13 @@
 	subr_entry_info *next = entry_points->next;
 	_Jv_Free (entry_points);
 	entry_points = next;
+      }
+
+    while (isect_list != NULL)
+      {
+	ref_intersection *next = isect_list->alloc_next;
+	delete isect_list;
+	isect_list = next;
       }
   }
 };
Index: testsuite/ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	For PR libgcj/7482:
	* libjava.lang/PR7482.java: New file.
	* libjava.lang/PR7482.out: New file.

Index: testsuite/libjava.lang/PR7482.java
===================================================================
RCS file: testsuite/libjava.lang/PR7482.java
diff -N testsuite/libjava.lang/PR7482.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/libjava.lang/PR7482.java 24 Jul 2003 17:10:05 -0000
@@ -0,0 +1,35 @@
+public class PR7482
+{
+  private interface I { }
+  private static class B { }
+  private static class U extends B implements I { }
+  private static class V extends B implements I { }
+
+  static I field;
+
+  private static void g1(Object o)
+  {
+    I val;
+    if (o == null)
+      val = new U();
+    else
+      val = new V();
+    field = val;
+  }
+
+  private static I g2(Object o)
+  {
+    I val;
+    if (o == null)
+      val = new U();
+    else
+      val = new V();
+    return val;
+  }
+
+  public static void main(String[] args)
+  {
+    g1(null);
+    g2(null);
+  }
+}
Index: testsuite/libjava.lang/PR7482.out
===================================================================
RCS file: testsuite/libjava.lang/PR7482.out
diff -N testsuite/libjava.lang/PR7482.out



More information about the Java-patches mailing list