This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java 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]

pre-patch to run-time verifier


This isn't a patch I want to check in, yet.  The main
part of the patch is carrying the _Jv_BytecodeVerifier
around everywhere so we can emit better error messages.
A secondary benefit of this is that we can pass the
current's class classloader to classes that need to be
resolved (Class:forName and _Jv_FindClassFromSignature),
so classloaders work.

Finally, this also fixes searching interfaces; that
should probably be a separate patch.

Before checking it in, I'd to clean it up some more by making
verify_fail a method of _Jv_BytecodeVerifier.  One benefit is
that I can remove the kludge exporting some internal fields.
Another benefit is we no longer have to explicity pass 'this'
to verify_fail.  It may also make sense to move some of the
methos from struct type or struct state - since they need
access ot the verifier anyway, we might as well make it
explicit.

A dis-advantage is that I don't know if it is possible to
specify __noreturn__ on a method or what the syntax for that is.
However, I don't think that is an important issue, unless the
__noreturn__ makes a difference for the optimizer.
that is

Comments Tom (or anyone else)?
-- 
	--Per Bothner
per@bothner.com   http://www.bothner.com/per/
Index: verify.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/verify.cc,v
retrieving revision 1.25
diff -u -p -r1.25 verify.cc
--- verify.cc	2001/12/10 01:18:30	1.25
+++ verify.cc	2002/01/23 20:04:12
@@ -44,6 +44,9 @@ details.  */
 static void verify_fail (char *msg, jint pc = -1)
   __attribute__ ((__noreturn__));
 
+static void verify_fail (char *msg, _Jv_BytecodeVerifier *verifier, jint pc = -1)
+  __attribute__ ((__noreturn__));
+
 static void debug_print (const char *fmt, ...)
   __attribute__ ((format (printf, 1, 2)));
 
@@ -73,7 +76,9 @@ private:
   // The current PC.
   int PC;
   // The PC corresponding to the start of the current instruction.
+public: // FIXME
   int start_PC;
+private:
 
   // The current state of the stack, locals, etc.
   state *current_state;
@@ -107,10 +112,12 @@ private:
   // The exceptions.
   _Jv_InterpException *exception;
 
+public:
   // Defining class.
   jclass current_class;
   // This method.
   _Jv_InterpMethod *current_method;
+private:
 
   // A linked list of utf8 objects we allocate.  This is really ugly,
   // but without this our utf8 objects would be collected.
@@ -261,7 +268,9 @@ private:
 		if (is_assignable_from_slow (target, source->interfaces[i]))
 		    return true;
 	      }
-	    return false;
+	    source = source->getSuperclass ();
+	    if (source == NULL)
+	      return false;
 	  }
 	else if (target == &java::lang::Object::class$)
 	  return true;
@@ -388,35 +397,36 @@ private:
     }
 
     // If *THIS is an unresolved reference type, resolve it.
-    void resolve ()
+    void resolve (_Jv_BytecodeVerifier *verifier)
     {
       if (key != unresolved_reference_type
 	  && key != uninitialized_unresolved_reference_type)
 	return;
 
-      // FIXME: class loader
       using namespace java::lang;
+      java::lang::ClassLoader *loader
+	= verifier->current_class->getClassLoader();
       // 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, NULL);
+	data.klass = _Jv_FindClassFromSignature (data.name->data, loader);
       else
 	data.klass = Class::forName (_Jv_NewStringUtf8Const (data.name),
-				     false, NULL);
+				     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)
+    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
-	verify_fail ("internal error in type::uninitialized");
+	verify_fail ("internal error in type::uninitialized", verifier);
       pc = npc;
     }
 
@@ -439,7 +449,7 @@ private:
     // of type *THIS.  Handle various special cases too.  Might modify
     // *THIS or K.  Note however that this does not perform numeric
     // promotion.
-    bool compatible (type &k)
+    bool compatible (type &k, _Jv_BytecodeVerifier *verifier)
     {
       // Any type is compatible with the unsuitable type.
       if (key == unsuitable_type)
@@ -480,8 +490,8 @@ private:
 	return true;
 
       // We must resolve both types and check assignability.
-      resolve ();
-      k.resolve ();
+      resolve (verifier);
+      k.resolve (verifier);
       return is_assignable_from_slow (data.klass, k.data.klass);
     }
 
@@ -513,17 +523,17 @@ private:
       return false;
     }
 
-    bool isinterface ()
+    bool isinterface (_Jv_BytecodeVerifier *verifier)
     {
-      resolve ();
+      resolve (verifier);
       if (key != reference_type)
 	return false;
       return data.klass->isInterface ();
     }
 
-    bool isabstract ()
+    bool isabstract (_Jv_BytecodeVerifier *verifier)
     {
-      resolve ();
+      resolve (verifier);
       if (key != reference_type)
 	return false;
       using namespace java::lang::reflect;
@@ -531,12 +541,12 @@ private:
     }
 
     // Return the element type of an array.
-    type element_type ()
+    type element_type (_Jv_BytecodeVerifier *verifier)
     {
       // FIXME: maybe should do string manipulation here.
-      resolve ();
+      resolve (verifier);
       if (key != reference_type)
-	verify_fail ("programmer error in type::element_type()");
+	verify_fail ("programmer error in type::element_type()", verifier, -1);
 
       jclass k = data.klass->getComponentType ();
       if (k->isPrimitive ())
@@ -547,18 +557,18 @@ private:
     // Return the array type corresponding to an initialized
     // reference.  We could expand this to work for other kinds of
     // types, but currently we don't need to.
-    type to_array ()
+    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 ();
+	resolve (verifier);
 
       if (key == reference_type)
 	return type (_Jv_GetArrayClass (data.klass,
 					data.klass->getClassLoader ()));
       else
-	verify_fail ("internal error in type::to_array()");
+	verify_fail ("internal error in type::to_array()", verifier);
     }
 
     bool isreference () const
@@ -610,7 +620,7 @@ private:
     }
 
     // Merge OLD_TYPE into this.  On error throw exception.
-    bool merge (type& old_type, bool local_semantics = false)
+    bool merge (type& old_type, bool local_semantics, _Jv_BytecodeVerifier *verifier)
     {
       bool changed = false;
       bool refo = old_type.isreference ();
@@ -646,8 +656,8 @@ private:
 		}
 	      else
 		{
-		  resolve ();
-		  old_type.resolve ();
+		  resolve (verifier);
+		  old_type.resolve (verifier);
 
 		  jclass k = data.klass;
 		  jclass oldk = old_type.data.klass;
@@ -706,7 +716,7 @@ private:
 		}
 	    }
 	  else
-	    verify_fail ("unmergeable type");
+	    verify_fail ("unmergeable type", verifier);
 	}
       return changed;
     }
@@ -884,7 +894,7 @@ private:
     // state.  Returns true if the new state was in fact changed.
     // Will throw an exception if the states are not mergeable.
     bool merge (state *state_old, bool ret_semantics,
-		int max_locals)
+		int max_locals, _Jv_BytecodeVerifier *verifier)
     {
       bool changed = false;
 
@@ -906,14 +916,14 @@ private:
 	  changed = true;
 	}
       else
-	verify_fail ("subroutines merged");
+	verify_fail ("subroutines merged", verifier);
 
       // Merge stacks.
       if (state_old->stacktop != stacktop)
-	verify_fail ("stack sizes differ");
+	verify_fail ("stack sizes differ", verifier);
       for (int i = 0; i < state_old->stacktop; ++i)
 	{
-	  if (stack[i].merge (state_old->stack[i]))
+	  if (stack[i].merge (state_old->stack[i], false, verifier))
 	    changed = true;
 	}
 
@@ -922,7 +932,7 @@ private:
 	{
 	  if (! ret_semantics || local_changed[i])
 	    {
-	      if (locals[i].merge (state_old->locals[i], true))
+	      if (locals[i].merge (state_old->locals[i], true, verifier))
 		{
 		  changed = true;
 		  note_variable (i);
@@ -1026,7 +1036,7 @@ private:
   type pop_raw ()
   {
     if (current_state->stacktop <= 0)
-      verify_fail ("stack empty", start_PC);
+      verify_fail ("stack empty", this);
     type r = current_state->stack[--current_state->stacktop];
     current_state->stackdepth -= r.depth ();
     if (current_state->stackdepth < 0)
@@ -1038,7 +1048,7 @@ private:
   {
     type r = pop_raw ();
     if (r.iswide ())
-      verify_fail ("narrow pop of wide type", start_PC);
+      verify_fail ("narrow pop of wide type", this);
     return r;
   }
 
@@ -1046,7 +1056,7 @@ private:
   {
     type r = pop_raw ();
     if (! r.iswide ())
-      verify_fail ("wide pop of narrow type", start_PC);
+      verify_fail ("wide pop of narrow type", this);
     return r;
   }
 
@@ -1054,8 +1064,8 @@ private:
   {
     match.promote ();
     type t = pop_raw ();
-    if (! match.compatible (t))
-      verify_fail ("incompatible type on stack", start_PC);
+    if (! match.compatible (t, this))
+      verify_fail ("incompatible type on stack", this);
     return t;
   }
 
@@ -1064,7 +1074,7 @@ private:
   {
     type t = pop_raw ();
     if (! t.isreference () && t.key != return_address_type)
-      verify_fail ("expected reference or return address on stack", start_PC);
+      verify_fail ("expected reference or return address on stack", this);
     return t;
   }
 
@@ -1075,7 +1085,7 @@ private:
 
     int depth = t.depth ();
     if (current_state->stackdepth + depth > current_method->max_stack)
-      verify_fail ("stack overflow");
+      verify_fail ("stack overflow", this);
     current_state->stack[current_state->stacktop++] = t;
     current_state->stackdepth += depth;
   }
@@ -1087,7 +1097,7 @@ private:
 
     int depth = t.depth ();
     if (index > current_method->max_locals - depth)
-      verify_fail ("invalid local variable");
+      verify_fail ("invalid local variable", this);
     current_state->locals[index] = t;
     current_state->note_variable (index);
 
@@ -1107,14 +1117,14 @@ private:
   {
     int depth = t.depth ();
     if (index > current_method->max_locals - depth)
-      verify_fail ("invalid local variable", start_PC);
-    if (! t.compatible (current_state->locals[index]))
-      verify_fail ("incompatible type in local variable", start_PC);
+      verify_fail ("invalid local variable", this);
+    if (! t.compatible (current_state->locals[index], this))
+      verify_fail ("incompatible type in local variable", this);
     if (depth == 2)
       {
 	type t (continuation_type);
-	if (! current_state->locals[index + 1].compatible (t))
-	  verify_fail ("invalid local variable", start_PC);
+	if (! current_state->locals[index + 1].compatible (t, this))
+	  verify_fail ("invalid local variable", this);
       }
     return current_state->locals[index];
   }
@@ -1124,10 +1134,10 @@ private:
   type require_array_type (type array, type element)
   {
     if (! array.isarray ())
-      verify_fail ("array required");
+      verify_fail ("array required", this);
 
-    type t = array.element_type ();
-    if (! element.compatible (t))
+    type t = array.element_type (this);
+    if (! element.compatible (t, this))
       {
 	// Special case for byte arrays, which must also be boolean
 	// arrays.
@@ -1135,10 +1145,10 @@ private:
 	if (element.key == byte_type)
 	  {
 	    type e2 (boolean_type);
-	    ok = e2.compatible (t);
+	    ok = e2.compatible (t, this);
 	  }
 	if (! ok)
-	  verify_fail ("incompatible array element type");
+	  verify_fail ("incompatible array element type", this);
       }
 
     // Return T and not ELEMENT, because T might be specialized.
@@ -1215,7 +1225,7 @@ private:
 	states[npc]->print (" To", npc, current_method->max_stack,
 			    current_method->max_locals);
 	changed = states[npc]->merge (nstate, ret_semantics,
-				      current_method->max_locals);
+				      current_method->max_locals, this);
 	states[npc]->print ("New", npc, current_method->max_stack,
 			    current_method->max_locals);
       }
@@ -1326,7 +1336,7 @@ private:
 
     int csub = current_state->subroutine;
     if (csub == 0)
-      verify_fail ("no subroutine");
+      verify_fail ("no subroutine", this);
 
     for (subr_info *subr = jsr_ptrs[csub]; subr != NULL; subr = subr->next)
       {
@@ -1897,8 +1907,8 @@ private:
   void check_return_type (type onstack)
   {
     type rt = compute_return_type (current_method->self->signature);
-    if (! rt.compatible (onstack))
-      verify_fail ("incompatible return type", start_PC);
+    if (! rt.compatible (onstack, this))
+      verify_fail ("incompatible return type", this);
   }
 
   // Initialize the stack for the new method.  Returns true if this
@@ -1914,7 +1924,7 @@ private:
 	type kurr (current_class);
 	if (_Jv_equalUtf8Consts (current_method->self->name, gcj::init_name))
 	  {
-	    kurr.set_uninitialized (type::SELF);
+	    kurr.set_uninitialized (type::SELF, this);
 	    is_init = true;
 	  }
 	set_variable (0, kurr);
@@ -1995,7 +2005,7 @@ private:
 		current_state->print ("Cur", PC, current_method->max_stack,
 				      current_method->max_locals);
 		if (! current_state->merge (states[PC], false,
-					    current_method->max_locals)
+					    current_method->max_locals, this)
 		    && ! states[PC]->is_unmerged_ret_state (current_method->max_locals))
 		  {
 		    debug_print ("== Fall through optimization\n");
@@ -2637,7 +2647,7 @@ private:
 	      // `this' has not yet been initialized.
 	      if (! current_state->this_type.isinitialized ()
 		  && current_state->this_type.pc == type::SELF)
-		klass.set_uninitialized (type::SELF);
+		klass.set_uninitialized (type::SELF, this);
 	      pop_type (klass);
 	    }
 	    break;
@@ -2659,13 +2669,13 @@ private:
 		  int nargs = get_byte ();
 		  if (nargs == 0)
 		    verify_fail ("too few arguments to invokeinterface",
-				 start_PC);
+				 this);
 		  if (get_byte () != 0)
 		    verify_fail ("invokeinterface dummy byte is wrong",
-				 start_PC);
+				 this);
 		  if (nargs - 1 != arg_count)
 		    verify_fail ("wrong argument count for invokeinterface",
-				 start_PC);
+				 this);
 		}
 
 	      bool is_init = false;
@@ -2673,11 +2683,10 @@ private:
 		{
 		  is_init = true;
 		  if (opcode != op_invokespecial)
-		    verify_fail ("can't invoke <init>", start_PC);
+		    verify_fail ("can't invoke <init>", this);
 		}
 	      else if (method_name->data[0] == '<')
-		verify_fail ("can't invoke method starting with `<'",
-			     start_PC);
+		verify_fail ("can't invoke method starting with `<'", this);
 
 	      // Pop arguments and check types.
 	      type arg_types[arg_count];
@@ -2691,7 +2700,7 @@ private:
 		  if (is_init)
 		    {
 		      // In this case the PC doesn't matter.
-		      t.set_uninitialized (type::UNINIT);
+		      t.set_uninitialized (type::UNINIT, this);
 		    }
 		  t = pop_type (t);
 		  if (is_init)
@@ -2708,10 +2717,9 @@ private:
 	  case op_new:
 	    {
 	      type t = check_class_constant (get_ushort ());
-	      if (t.isarray () || t.isinterface () || t.isabstract ())
-		verify_fail ("type is array, interface, or abstract",
-			     start_PC);
-	      t.set_uninitialized (start_PC);
+	      if (t.isarray () || t.isinterface (this) || t.isabstract (this))
+		verify_fail ("type is array, interface, or abstract", this);
+	      t.set_uninitialized (start_PC, this);
 	      push_type (t);
 	    }
 	    break;
@@ -2729,13 +2737,13 @@ private:
 	    break;
 	  case op_anewarray:
 	    pop_type (int_type);
-	    push_type (check_class_constant (get_ushort ()).to_array ());
+	    push_type (check_class_constant (get_ushort ()).to_array (this));
 	    break;
 	  case op_arraylength:
 	    {
 	      type t = pop_type (reference_type);
 	      if (! t.isarray ())
-		verify_fail ("array type expected", start_PC);
+		verify_fail ("array type expected", this);
 	      push_type (int_type);
 	    }
 	    break;
@@ -2892,15 +2900,33 @@ _Jv_VerifyMethod (_Jv_InterpMethod *meth
 static void
 verify_fail (char *s, jint pc)
 {
+  verify_fail(s, NULL, pc);
+}
+
+static void
+verify_fail (char *s, _Jv_BytecodeVerifier *verifier, jint pc)
+{
   using namespace java::lang;
   StringBuffer *buf = new StringBuffer ();
 
   buf->append (JvNewStringLatin1 ("verification failed"));
+  if (pc == -1 && verifier != NULL)
+    pc = verifier->start_PC;
   if (pc != -1)
     {
       buf->append (JvNewStringLatin1 (" at PC "));
       buf->append (pc);
     }
+
+  _Jv_InterpMethod *method = verifier->current_method;
+  buf->append (JvNewStringLatin1 (" in "));
+  buf->append (verifier->current_class->getName());
+  buf->append ((jchar) ':');
+  buf->append (JvNewStringUTF (method->get_method()->name->data));
+  buf->append ((jchar) '(');
+  buf->append (JvNewStringUTF (method->get_method()->signature->data));
+  buf->append ((jchar) ')');
+
   buf->append (JvNewStringLatin1 (": "));
   buf->append (JvNewStringLatin1 (s));
   throw new java::lang::VerifyError (buf->toString ());

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