OSDN Git Service

* resolve.cc (_Jv_PrepareClass): Verify method here...
authortromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 10 Dec 2001 01:18:30 +0000 (01:18 +0000)
committertromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 10 Dec 2001 01:18:30 +0000 (01:18 +0000)
* defineclass.cc (handleMethodsEnd): ... not here.
* verify.cc (_Jv_BytecodeVerifier::initialize_stack): New method.
(_Jv_BytecodeVerifier::verify_instructions_0) [op_return]: Ensure
there are no uninitialized objects.
(_Jv_BytecodeVerifier::state::this_type): New field.
(_Jv_BytecodeVerifier::state::state): Initialize this_type.
(_Jv_BytecodeVerifier::state::copy): Copy this_type.
(_Jv_BytecodeVerifier::state::merge): Merge this_type.
(_Jv_BytecodeVerifier::state::check_no_uninitialized_objects):
Handle this_type.
(_Jv_BytecodeVerifier::state::check_this_initialized): New
method.
(_Jv_BytecodeVerifier::state::set_initialized): Handle this_type.
(_Jv_BytecodeVerifier::state::set_this_type): New method.
(_Jv_BytecodeVerifier::verify_instructions_0) [op_putfield]: Allow
assignment to fields of `this' before another initializer is run.

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

libjava/ChangeLog
libjava/defineclass.cc
libjava/resolve.cc
libjava/verify.cc

index 4004083..c9d99f5 100644 (file)
@@ -1,5 +1,23 @@
 2001-12-09  Tom Tromey  <tromey@redhat.com>
 
+       * resolve.cc (_Jv_PrepareClass): Verify method here...
+       * defineclass.cc (handleMethodsEnd): ... not here.
+       * verify.cc (_Jv_BytecodeVerifier::initialize_stack): New method.
+       (_Jv_BytecodeVerifier::verify_instructions_0) [op_return]: Ensure
+       there are no uninitialized objects.
+       (_Jv_BytecodeVerifier::state::this_type): New field.
+       (_Jv_BytecodeVerifier::state::state): Initialize this_type.
+       (_Jv_BytecodeVerifier::state::copy): Copy this_type.
+       (_Jv_BytecodeVerifier::state::merge): Merge this_type.
+       (_Jv_BytecodeVerifier::state::check_no_uninitialized_objects):
+       Handle this_type.
+       (_Jv_BytecodeVerifier::state::check_this_initialized): New
+       method.
+       (_Jv_BytecodeVerifier::state::set_initialized): Handle this_type.
+       (_Jv_BytecodeVerifier::state::set_this_type): New method.
+       (_Jv_BytecodeVerifier::verify_instructions_0) [op_putfield]: Allow
+       assignment to fields of `this' before another initializer is run.
+
        * Makefile.in: Rebuilt.
        * Makefile.am (gnu/gcj/runtime/VMClassLoader.h): Use `::java'.
 
index 2901527..df2da09 100644 (file)
@@ -940,7 +940,7 @@ _Jv_ClassReader::handleClassBegin
       pool_data[super_class].clazz = the_super;
       pool_tags[super_class] = JV_CONSTANT_ResolvedClass;
     }
-           
+
   // now we've come past the circularity problem, we can 
   // now say that we're loading...
 
@@ -1315,15 +1315,6 @@ void _Jv_ClassReader::handleMethodsEnd ()
        {
          if (def->interpreted_methods[i] == 0)
            throw_class_format_error ("method with no code");
-
-         if (verify)
-           {
-             _Jv_InterpMethod *m;
-             m = (reinterpret_cast<_Jv_InterpMethod *>
-                  (def->interpreted_methods[i]));
-             // FIXME: enable once verifier is more fully tested.
-             // _Jv_VerifyMethod (m);
-           }
        }
     }
 }
index 2b25b57..ba397c9 100644 (file)
@@ -578,7 +578,7 @@ _Jv_PrepareClass(jclass klass)
 
   // set the instance size for the class
   clz->size_in_bytes = instance_size;
-    
+
   // allocate static memory
   if (static_size != 0)
     {
@@ -628,6 +628,8 @@ _Jv_PrepareClass(jclass klass)
       else if (imeth != 0)             // it could be abstract
        {
          _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth);
+         // FIXME: enable once verifier is more fully tested.
+         // _Jv_VerifyMethod (im);
          clz->methods[i].ncode = im->ncode ();
        }
     }
index 74499ed..8627de5 100644 (file)
@@ -764,6 +764,13 @@ private:
     // This is used to keep a linked list of all the states which
     // require re-verification.  We use the PC to keep track.
     int next;
+    // We keep track of the type of `this' specially.  This is used to
+    // ensure that an instance initializer invokes another initializer
+    // on `this' before returning.  We must keep track of this
+    // specially because otherwise we might be confused by code which
+    // assigns to locals[0] (overwriting `this') and then returns
+    // without really initializing.
+    type this_type;
 
     // INVALID marks a state which is not on the linked list of states
     // requiring reverification.
@@ -772,6 +779,7 @@ private:
     static const int NO_NEXT = -2;
 
     state ()
+      : this_type ()
     {
       stack = NULL;
       locals = NULL;
@@ -779,6 +787,7 @@ private:
     }
 
     state (int max_stack, int max_locals)
+      : this_type ()
     {
       stacktop = 0;
       stackdepth = 0;
@@ -855,6 +864,7 @@ private:
            locals[i] = copy->locals[i];
          local_changed[i] = copy->local_changed[i];
        }
+      this_type = copy->this_type;
       // Don't modify `next'.
     }
 
@@ -870,14 +880,19 @@ private:
       // FIXME: subroutine handling?
     }
 
-    // Merge STATE into this state.  Destructively modifies this state.
-    // Returns true if the new state was in fact changed.  Will throw an
-    // exception if the states are not mergeable.
+    // Merge STATE_OLD into this state.  Destructively modifies this
+    // 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)
     {
       bool changed = false;
 
+      // Special handling for `this'.  If one or the other is
+      // uninitialized, then the merge is uninitialized.
+      if (this_type.isinitialized ())
+       this_type = state_old->this_type;
+
       // Merge subroutine states.  *THIS and *STATE_OLD must be in the
       // same subroutine.  Also, recursive subroutine calls must be
       // avoided.
@@ -940,6 +955,21 @@ private:
       for (int i = 0; i < max_locals; ++i)
        if (locals[i].isreference () && ! locals[i].isinitialized ())
          verify_fail ("uninitialized object in local variable");
+
+      check_this_initialized ();
+    }
+
+    // Ensure that `this' has been initialized.
+    void check_this_initialized ()
+    {
+      if (this_type.isreference () && ! this_type.isinitialized ())
+       verify_fail ("`this' is uninitialized");
+    }
+
+    // Set type of `this'.
+    void set_this_type (const type &k)
+    {
+      this_type = k;
     }
 
     // Note that a local variable was modified.
@@ -957,6 +987,7 @@ private:
        stack[i].set_initialized (pc);
       for (int i = 0; i < max_locals; ++i)
        locals[i].set_initialized (pc);
+      this_type.set_initialized (pc);
     }
 
     // Return true if this state is the unmerged result of a `ret'.
@@ -1870,6 +1901,42 @@ private:
       verify_fail ("incompatible return type", start_PC);
   }
 
+  // Initialize the stack for the new method.  Returns true if this
+  // method is an instance initializer.
+  bool initialize_stack ()
+  {
+    int var = 0;
+    bool is_init = false;
+
+    using namespace java::lang::reflect;
+    if (! Modifier::isStatic (current_method->self->accflags))
+      {
+       type kurr (current_class);
+       if (_Jv_equalUtf8Consts (current_method->self->name, gcj::init_name))
+         {
+           kurr.set_uninitialized (type::SELF);
+           is_init = true;
+         }
+       set_variable (0, kurr);
+       current_state->set_this_type (kurr);
+       ++var;
+      }
+
+    // We have to handle wide arguments specially here.
+    int arg_count = _Jv_count_arguments (current_method->self->signature);
+    type arg_types[arg_count];
+    compute_argument_types (current_method->self->signature, arg_types);
+    for (int i = 0; i < arg_count; ++i)
+      {
+       set_variable (var, arg_types[i]);
+       ++var;
+       if (arg_types[i].iswide ())
+         ++var;
+      }
+
+    return is_init;
+  }
+
   void verify_instructions_0 ()
   {
     current_state = new state (current_method->max_stack,
@@ -1878,31 +1945,8 @@ private:
     PC = 0;
     start_PC = 0;
 
-    {
-      int var = 0;
-
-      using namespace java::lang::reflect;
-      if (! Modifier::isStatic (current_method->self->accflags))
-       {
-         type kurr (current_class);
-         if (_Jv_equalUtf8Consts (current_method->self->name, gcj::init_name))
-           kurr.set_uninitialized (type::SELF);
-         set_variable (0, kurr);
-         ++var;
-       }
-
-      // We have to handle wide arguments specially here.
-      int arg_count = _Jv_count_arguments (current_method->self->signature);
-      type arg_types[arg_count];
-      compute_argument_types (current_method->self->signature, arg_types);
-      for (int i = 0; i < arg_count; ++i)
-       {
-         set_variable (var, arg_types[i]);
-         ++var;
-         if (arg_types[i].iswide ())
-           ++var;
-       }
-    }
+    // True if we are verifying an instance initializer.
+    bool this_is_init = initialize_stack ();
 
     states = (state **) _Jv_Malloc (sizeof (state *)
                                    * current_method->code_length);
@@ -2561,6 +2605,10 @@ private:
            invalidate_pc ();
            break;
          case op_return:
+           // 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 ();
            check_return_type (void_type);
            invalidate_pc ();
            break;
@@ -2583,6 +2631,13 @@ private:
              type klass;
              type field = check_field_constant (get_ushort (), &klass);
              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);
              pop_type (klass);
            }
            break;