OSDN Git Service

* verify.cc (verify_fail): Change from being a top-level function
authorbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 26 Jan 2002 06:32:55 +0000 (06:32 +0000)
committerbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 26 Jan 2002 06:32:55 +0000 (06:32 +0000)
to e method of _Jv_BytecodeVerifier.  Emit current method name.
Pass the current verifier to type: and state: methods as needed,
for better error messages, and for resolve.
(resolve):  Pass current class's loader for Class.forName and
_Jv_FindClassFromSignature, rather than using the default loader.
(various type: and state: methods):  Take _Jv_BytecodeVerifier* arg.
(get_type_val_for_signature):  Make non-static.
(various methods):  Pass start_PC implicitly, not explicitly.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@49240 138bc75d-0d04-0410-961f-82ee72b054a4

libjava/verify.cc

index 24350ef..ac380cb 100644 (file)
@@ -39,11 +39,6 @@ details.  */
 // * at least one GC problem :-(
 
 
-// This is global because __attribute__ doesn't seem to work on static
-// methods.
-static void verify_fail (char *msg, jint pc = -1)
-  __attribute__ ((__noreturn__));
-
 static void debug_print (const char *fmt, ...)
   __attribute__ ((format (printf, 1, 2)));
 
@@ -180,7 +175,7 @@ private:
 
   // Return the type_val corresponding to a primitive signature
   // character.  For instance `I' returns `int.class'.
-  static type_val get_type_val_for_signature (jchar sig)
+  type_val get_type_val_for_signature (jchar sig)
   {
     type_val rt;
     switch (sig)
@@ -219,7 +214,7 @@ private:
   }
 
   // Return the type_val corresponding to a primitive class.
-  static type_val get_type_val_for_signature (jclass k)
+  type_val get_type_val_for_signature (jclass k)
   {
     return get_type_val_for_signature ((jchar) k->method_count);
   }
@@ -390,35 +385,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");
+       verifier->verify_fail ("internal error in type::uninitialized");
       pc = npc;
     }
 
@@ -441,7 +437,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)
@@ -482,8 +478,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);
     }
 
@@ -515,17 +511,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;
@@ -533,34 +529,34 @@ 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()");
+       verifier->verify_fail ("programmer error in type::element_type()", -1);
 
       jclass k = data.klass->getComponentType ();
       if (k->isPrimitive ())
-       return type (get_type_val_for_signature (k));
+       return type (verifier->get_type_val_for_signature (k));
       return type (k);
     }
 
     // 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()");
+       verifier->verify_fail ("internal error in type::to_array()");
     }
 
     bool isreference () const
@@ -587,7 +583,7 @@ private:
              || key == uninitialized_reference_type);
     }
 
-    void verify_dimensions (int ndims)
+    void verify_dimensions (int ndims, _Jv_BytecodeVerifier *verifier)
     {
       // The way this is written, we don't need to check isarray().
       if (key == reference_type)
@@ -608,11 +604,11 @@ private:
        }
 
       if (ndims > 0)
-       verify_fail ("array type has fewer dimensions than required");
+       verifier->verify_fail ("array type has fewer dimensions than required");
     }
 
     // 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 ();
@@ -627,7 +623,7 @@ private:
              changed = true;
            }
          else if (isinitialized () != old_type.isinitialized ())
-           verify_fail ("merging initialized and uninitialized types");
+           verifier->verify_fail ("merging initialized and uninitialized types");
          else
            {
              if (! isinitialized ())
@@ -637,7 +633,7 @@ private:
                  else if (old_type.pc == UNINIT)
                    ;
                  else if (pc != old_type.pc)
-                   verify_fail ("merging different uninitialized types");
+                   verifier->verify_fail ("merging different uninitialized types");
                }
 
              if (! isresolved ()
@@ -648,8 +644,8 @@ private:
                }
              else
                {
-                 resolve ();
-                 old_type.resolve ();
+                 resolve (verifier);
+                 old_type.resolve (verifier);
 
                  jclass k = data.klass;
                  jclass oldk = old_type.data.klass;
@@ -708,7 +704,7 @@ private:
                }
            }
          else
-           verify_fail ("unmergeable type");
+           verifier->verify_fail ("unmergeable type");
        }
       return changed;
     }
@@ -886,7 +882,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;
 
@@ -908,14 +904,14 @@ private:
          changed = true;
        }
       else
-       verify_fail ("subroutines merged");
+       verifier->verify_fail ("subroutines merged");
 
       // Merge stacks.
       if (state_old->stacktop != stacktop)
-       verify_fail ("stack sizes differ");
+       verifier->verify_fail ("stack sizes differ");
       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;
        }
 
@@ -924,7 +920,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);
@@ -945,27 +941,28 @@ private:
     // whether we're using backwards-branch or exception-handing
     // semantics.
     void check_no_uninitialized_objects (int max_locals,
+                                        _Jv_BytecodeVerifier *verifier,
                                         bool exception_semantics = false)
     {
       if (! exception_semantics)
        {
          for (int i = 0; i < stacktop; ++i)
            if (stack[i].isreference () && ! stack[i].isinitialized ())
-             verify_fail ("uninitialized object on stack");
+             verifier->verify_fail ("uninitialized object on stack");
        }
 
       for (int i = 0; i < max_locals; ++i)
        if (locals[i].isreference () && ! locals[i].isinitialized ())
-         verify_fail ("uninitialized object in local variable");
+         verifier->verify_fail ("uninitialized object in local variable");
 
-      check_this_initialized ();
+      check_this_initialized (verifier);
     }
 
     // Ensure that `this' has been initialized.
-    void check_this_initialized ()
+    void check_this_initialized (_Jv_BytecodeVerifier *verifier)
     {
       if (this_type.isreference () && ! this_type.isinitialized ())
-       verify_fail ("`this' is uninitialized");
+       verifier->verify_fail ("`this' is uninitialized");
     }
 
     // Set type of `this'.
@@ -1028,7 +1025,7 @@ private:
   type pop_raw ()
   {
     if (current_state->stacktop <= 0)
-      verify_fail ("stack empty", start_PC);
+      verify_fail ("stack empty");
     type r = current_state->stack[--current_state->stacktop];
     current_state->stackdepth -= r.depth ();
     if (current_state->stackdepth < 0)
@@ -1040,7 +1037,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");
     return r;
   }
 
@@ -1048,7 +1045,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");
     return r;
   }
 
@@ -1056,8 +1053,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");
     return t;
   }
 
@@ -1066,7 +1063,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");
     return t;
   }
 
@@ -1109,14 +1106,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");
+    if (! t.compatible (current_state->locals[index], this))
+      verify_fail ("incompatible type in local variable");
     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");
       }
     return current_state->locals[index];
   }
@@ -1128,8 +1125,8 @@ private:
     if (! array.isarray ())
       verify_fail ("array required");
 
-    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.
@@ -1137,7 +1134,7 @@ 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");
@@ -1217,7 +1214,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);
       }
@@ -1235,14 +1232,14 @@ private:
   {
     int npc = compute_jump (offset);
     if (npc < PC)
-      current_state->check_no_uninitialized_objects (current_method->max_locals);
+      current_state->check_no_uninitialized_objects (current_method->max_locals, this);
     push_jump_merge (npc, current_state);
   }
 
   void push_exception_jump (type t, int pc)
   {
     current_state->check_no_uninitialized_objects (current_method->max_locals,
-                                                 true);
+                                                  this, true);
     state s (current_state, current_method->max_stack,
             current_method->max_locals);
     s.set_exception (t, current_method->max_stack);
@@ -1336,7 +1333,7 @@ private:
        // in the enclosing context.
        current_state->subroutine = get_subroutine (subr->pc);
        if (subr->pc < PC)
-         current_state->check_no_uninitialized_objects (current_method->max_locals);
+         current_state->check_no_uninitialized_objects (current_method->max_locals, this);
        push_jump_merge (subr->pc, current_state, true);
       }
 
@@ -1361,7 +1358,7 @@ private:
     int npc = compute_jump (offset);
 
     if (npc < PC)
-      current_state->check_no_uninitialized_objects (current_method->max_locals);
+      current_state->check_no_uninitialized_objects (current_method->max_locals, this);
     check_nonrecursive_call (current_state->subroutine, npc);
 
     // Temporarily modify the current state so that it looks like we are
@@ -1899,8 +1896,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");
   }
 
   // Initialize the stack for the new method.  Returns true if this
@@ -1916,7 +1913,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);
@@ -1997,7 +1994,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");
@@ -2610,7 +2607,7 @@ private:
            // We only need to check this when the return type is
            // void, because all instance initializers return void.
            if (this_is_init)
-             current_state->check_this_initialized ();
+             current_state->check_this_initialized (this);
            check_return_type (void_type);
            invalidate_pc ();
            break;
@@ -2639,7 +2636,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;
@@ -2660,14 +2657,11 @@ private:
                {
                  int nargs = get_byte ();
                  if (nargs == 0)
-                   verify_fail ("too few arguments to invokeinterface",
-                                start_PC);
+                   verify_fail ("too few arguments to invokeinterface");
                  if (get_byte () != 0)
-                   verify_fail ("invokeinterface dummy byte is wrong",
-                                start_PC);
+                   verify_fail ("invokeinterface dummy byte is wrong");
                  if (nargs - 1 != arg_count)
-                   verify_fail ("wrong argument count for invokeinterface",
-                                start_PC);
+                   verify_fail ("wrong argument count for invokeinterface");
                }
 
              bool is_init = false;
@@ -2675,11 +2669,10 @@ private:
                {
                  is_init = true;
                  if (opcode != op_invokespecial)
-                   verify_fail ("can't invoke <init>", start_PC);
+                   verify_fail ("can't invoke <init>");
                }
              else if (method_name->data[0] == '<')
-               verify_fail ("can't invoke method starting with `<'",
-                            start_PC);
+               verify_fail ("can't invoke method starting with `<'");
 
              // Pop arguments and check types.
              type arg_types[arg_count];
@@ -2693,7 +2686,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)
@@ -2710,10 +2703,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");
+             t.set_uninitialized (start_PC, this);
              push_type (t);
            }
            break;
@@ -2731,13 +2723,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");
              push_type (int_type);
            }
            break;
@@ -2812,7 +2804,7 @@ private:
              int dim = get_byte ();
              if (dim < 1)
                verify_fail ("too few dimensions to multianewarray", start_PC);
-             atype.verify_dimensions (dim);
+             atype.verify_dimensions (dim, this);
              for (int i = 0; i < dim; ++i)
                pop_type (int_type);
              push_type (atype);
@@ -2839,6 +2831,34 @@ private:
       }
   }
 
+  __attribute__ ((__noreturn__)) void verify_fail (char *s, jint pc = -1)
+  {
+    using namespace java::lang;
+    StringBuffer *buf = new StringBuffer ();
+
+    buf->append (JvNewStringLatin1 ("verification failed"));
+    if (pc == -1)
+      pc = start_PC;
+    if (pc != -1)
+      {
+       buf->append (JvNewStringLatin1 (" at PC "));
+       buf->append (pc);
+      }
+
+    _Jv_InterpMethod *method = current_method;
+    buf->append (JvNewStringLatin1 (" in "));
+    buf->append (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 ());
+  }
+
 public:
 
   void verify_instructions ()
@@ -2889,23 +2909,4 @@ _Jv_VerifyMethod (_Jv_InterpMethod *meth)
   _Jv_BytecodeVerifier v (meth);
   v.verify_instructions ();
 }
-
-// FIXME: add more info, like PC, when required.
-static void
-verify_fail (char *s, jint pc)
-{
-  using namespace java::lang;
-  StringBuffer *buf = new StringBuffer ();
-
-  buf->append (JvNewStringLatin1 ("verification failed"));
-  if (pc != -1)
-    {
-      buf->append (JvNewStringLatin1 (" at PC "));
-      buf->append (pc);
-    }
-  buf->append (JvNewStringLatin1 (": "));
-  buf->append (JvNewStringLatin1 (s));
-  throw new java::lang::VerifyError (buf->toString ());
-}
-
 #endif /* INTERPRETER */