src/share/vm/oops/instanceKlass.cpp

changeset 9286
2c4cecfa5ce5
parent 9285
b955bd18e8fe
child 9291
a2c8195708cc
     1.1 --- a/src/share/vm/oops/instanceKlass.cpp	Tue Apr 08 09:51:25 2014 +0200
     1.2 +++ b/src/share/vm/oops/instanceKlass.cpp	Mon Jan 08 08:32:04 2018 -0800
     1.3 @@ -2582,16 +2582,6 @@
     1.4      assert(breakpoints() == 0x0, "should have cleared breakpoints");
     1.5    }
     1.6  
     1.7 -  // deallocate information about previous versions
     1.8 -  if (_previous_versions != NULL) {
     1.9 -    for (int i = _previous_versions->length() - 1; i >= 0; i--) {
    1.10 -      PreviousVersionNode * pv_node = _previous_versions->at(i);
    1.11 -      delete pv_node;
    1.12 -    }
    1.13 -    delete _previous_versions;
    1.14 -    _previous_versions = NULL;
    1.15 -  }
    1.16 -
    1.17    // deallocate the cached class file
    1.18    if (_cached_class_file != NULL) {
    1.19      os::free(_cached_class_file, mtClass);
    1.20 @@ -3187,16 +3177,17 @@
    1.21    st->print(BULLET"field type annotations:  "); fields_type_annotations()->print_value_on(st); st->cr();
    1.22    {
    1.23      bool have_pv = false;
    1.24 -    PreviousVersionWalker pvw(Thread::current(), (InstanceKlass*)this);
    1.25 -    for (PreviousVersionNode * pv_node = pvw.next_previous_version();
    1.26 -         pv_node != NULL; pv_node = pvw.next_previous_version()) {
    1.27 +    // previous versions are linked together through the InstanceKlass
    1.28 +    for (InstanceKlass* pv_node = _previous_versions;
    1.29 +         pv_node != NULL;
    1.30 +         pv_node = pv_node->previous_versions()) {
    1.31        if (!have_pv)
    1.32          st->print(BULLET"previous version:  ");
    1.33        have_pv = true;
    1.34 -      pv_node->prev_constant_pool()->print_value_on(st);
    1.35 +      pv_node->constants()->print_value_on(st);
    1.36      }
    1.37      if (have_pv) st->cr();
    1.38 -  } // pvw is cleaned up
    1.39 +  }
    1.40  
    1.41    if (generic_signature() != NULL) {
    1.42      st->print(BULLET"generic signature: ");
    1.43 @@ -3610,92 +3601,93 @@
    1.44  // RedefineClasses() support for previous versions:
    1.45  
    1.46  // Purge previous versions
    1.47 -static void purge_previous_versions_internal(InstanceKlass* ik, int emcp_method_count) {
    1.48 +void InstanceKlass::purge_previous_versions(InstanceKlass* ik) {
    1.49    if (ik->previous_versions() != NULL) {
    1.50      // This klass has previous versions so see what we can cleanup
    1.51      // while it is safe to do so.
    1.52  
    1.53      int deleted_count = 0;    // leave debugging breadcrumbs
    1.54      int live_count = 0;
    1.55 -    ClassLoaderData* loader_data = ik->class_loader_data() == NULL ?
    1.56 -                       ClassLoaderData::the_null_class_loader_data() :
    1.57 -                       ik->class_loader_data();
    1.58 +    ClassLoaderData* loader_data = ik->class_loader_data();
    1.59 +    assert(loader_data != NULL, "should never be null");
    1.60  
    1.61      // RC_TRACE macro has an embedded ResourceMark
    1.62 -    RC_TRACE(0x00000200, ("purge: %s: previous version length=%d",
    1.63 -      ik->external_name(), ik->previous_versions()->length()));
    1.64 -
    1.65 -    for (int i = ik->previous_versions()->length() - 1; i >= 0; i--) {
    1.66 -      // check the previous versions array
    1.67 -      PreviousVersionNode * pv_node = ik->previous_versions()->at(i);
    1.68 -      ConstantPool* cp_ref = pv_node->prev_constant_pool();
    1.69 -      assert(cp_ref != NULL, "cp ref was unexpectedly cleared");
    1.70 -
    1.71 -      ConstantPool* pvcp = cp_ref;
    1.72 +    RC_TRACE(0x00000200, ("purge: %s: previous versions", ik->external_name()));
    1.73 +
    1.74 +    // previous versions are linked together through the InstanceKlass
    1.75 +    InstanceKlass* pv_node = ik->previous_versions();
    1.76 +    InstanceKlass* last = ik;
    1.77 +    int version = 0;
    1.78 +
    1.79 +    // check the previous versions list
    1.80 +    for (; pv_node != NULL; ) {
    1.81 +
    1.82 +      ConstantPool* pvcp = pv_node->constants();
    1.83 +      assert(pvcp != NULL, "cp ref was unexpectedly cleared");
    1.84 +
    1.85 +
    1.86        if (!pvcp->on_stack()) {
    1.87          // If the constant pool isn't on stack, none of the methods
    1.88 -        // are executing.  Delete all the methods, the constant pool and
    1.89 -        // and this previous version node.
    1.90 -        GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods();
    1.91 -        if (method_refs != NULL) {
    1.92 -          for (int j = method_refs->length() - 1; j >= 0; j--) {
    1.93 -            Method* method = method_refs->at(j);
    1.94 -            assert(method != NULL, "method ref was unexpectedly cleared");
    1.95 -            method_refs->remove_at(j);
    1.96 -            // method will be freed with associated class.
    1.97 -          }
    1.98 -        }
    1.99 -        // Remove the constant pool
   1.100 -        delete pv_node;
   1.101 -        // Since we are traversing the array backwards, we don't have to
   1.102 -        // do anything special with the index.
   1.103 -        ik->previous_versions()->remove_at(i);
   1.104 +        // are executing.  Unlink this previous_version.
   1.105 +        // The previous version InstanceKlass is on the ClassLoaderData deallocate list
   1.106 +        // so will be deallocated during the next phase of class unloading.
   1.107 +        pv_node = pv_node->previous_versions();
   1.108 +        last->link_previous_versions(pv_node);
   1.109          deleted_count++;
   1.110 +        version++;
   1.111          continue;
   1.112        } else {
   1.113 -        RC_TRACE(0x00000200, ("purge: previous version @%d is alive", i));
   1.114 +        RC_TRACE(0x00000200, ("purge: previous version " INTPTR_FORMAT " is alive",
   1.115 +                              pv_node));
   1.116          assert(pvcp->pool_holder() != NULL, "Constant pool with no holder");
   1.117          guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack");
   1.118          live_count++;
   1.119        }
   1.120  
   1.121 -      // At least one method is live in this previous version, clean out
   1.122 -      // the others or mark them as obsolete.
   1.123 -      GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods();
   1.124 +      // At least one method is live in this previous version so clean its MethodData.
   1.125 +      // Reset dead EMCP methods not to get breakpoints.
   1.126 +      // All methods are deallocated when all of the methods for this class are no
   1.127 +      // longer running.
   1.128 +      Array<Method*>* method_refs = pv_node->methods();
   1.129        if (method_refs != NULL) {
   1.130          RC_TRACE(0x00000200, ("purge: previous methods length=%d",
   1.131            method_refs->length()));
   1.132 -        for (int j = method_refs->length() - 1; j >= 0; j--) {
   1.133 +        for (int j = 0; j < method_refs->length(); j++) {
   1.134            Method* method = method_refs->at(j);
   1.135 -          assert(method != NULL, "method ref was unexpectedly cleared");
   1.136 -
   1.137 -          // Remove the emcp method if it's not executing
   1.138 -          // If it's been made obsolete by a redefinition of a non-emcp
   1.139 -          // method, mark it as obsolete but leave it to clean up later.
   1.140 +
   1.141            if (!method->on_stack()) {
   1.142 -            method_refs->remove_at(j);
   1.143 -          } else if (emcp_method_count == 0) {
   1.144 -            method->set_is_obsolete();
   1.145 +            // no breakpoints for non-running methods
   1.146 +            if (method->is_running_emcp()) {
   1.147 +              method->set_running_emcp(false);
   1.148 +            }
   1.149            } else {
   1.150 +            assert (method->is_obsolete() || method->is_running_emcp(),
   1.151 +                    "emcp method cannot run after emcp bit is cleared");
   1.152              // RC_TRACE macro has an embedded ResourceMark
   1.153              RC_TRACE(0x00000200,
   1.154                ("purge: %s(%s): prev method @%d in version @%d is alive",
   1.155                method->name()->as_C_string(),
   1.156 -              method->signature()->as_C_string(), j, i));
   1.157 +              method->signature()->as_C_string(), j, version));
   1.158              if (method->method_data() != NULL) {
   1.159 -              // Clean out any weak method links
   1.160 +              // Clean out any weak method links for running methods
   1.161 +              // (also should include not EMCP methods)
   1.162                method->method_data()->clean_weak_method_links();
   1.163              }
   1.164            }
   1.165          }
   1.166        }
   1.167 +      // next previous version
   1.168 +      last = pv_node;
   1.169 +      pv_node = pv_node->previous_versions();
   1.170 +      version++;
   1.171      }
   1.172 -    assert(ik->previous_versions()->length() == live_count, "sanity check");
   1.173      RC_TRACE(0x00000200,
   1.174        ("purge: previous version stats: live=%d, deleted=%d", live_count,
   1.175        deleted_count));
   1.176    }
   1.177  
   1.178 +  // Clean MethodData of this class's methods so they don't refer to
   1.179 +  // old methods that are no longer running.
   1.180    Array<Method*>* methods = ik->methods();
   1.181    int num_methods = methods->length();
   1.182    for (int index2 = 0; index2 < num_methods; ++index2) {
   1.183 @@ -3705,122 +3697,30 @@
   1.184    }
   1.185  }
   1.186  
   1.187 -// External interface for use during class unloading.
   1.188 -void InstanceKlass::purge_previous_versions(InstanceKlass* ik) {
   1.189 -  // Call with >0 emcp methods since they are not currently being redefined.
   1.190 -  purge_previous_versions_internal(ik, 1);
   1.191 -}
   1.192 -
   1.193 -
   1.194 -// Potentially add an information node that contains pointers to the
   1.195 -// interesting parts of the previous version of the_class.
   1.196 -// This is also where we clean out any unused references.
   1.197 -// Note that while we delete nodes from the _previous_versions
   1.198 -// array, we never delete the array itself until the klass is
   1.199 -// unloaded. The has_been_redefined() query depends on that fact.
   1.200 -//
   1.201 -void InstanceKlass::add_previous_version(instanceKlassHandle ikh,
   1.202 -       BitMap* emcp_methods, int emcp_method_count) {
   1.203 -  assert(Thread::current()->is_VM_thread(),
   1.204 -         "only VMThread can add previous versions");
   1.205 -
   1.206 -  if (_previous_versions == NULL) {
   1.207 -    // This is the first previous version so make some space.
   1.208 -    // Start with 2 elements under the assumption that the class
   1.209 -    // won't be redefined much.
   1.210 -    _previous_versions =  new (ResourceObj::C_HEAP, mtClass)
   1.211 -                            GrowableArray<PreviousVersionNode *>(2, true);
   1.212 -  }
   1.213 -
   1.214 -  ConstantPool* cp_ref = ikh->constants();
   1.215 -
   1.216 -  // RC_TRACE macro has an embedded ResourceMark
   1.217 -  RC_TRACE(0x00000400, ("adding previous version ref for %s @%d, EMCP_cnt=%d "
   1.218 -                        "on_stack=%d",
   1.219 -    ikh->external_name(), _previous_versions->length(), emcp_method_count,
   1.220 -    cp_ref->on_stack()));
   1.221 -
   1.222 -  // If the constant pool for this previous version of the class
   1.223 -  // is not marked as being on the stack, then none of the methods
   1.224 -  // in this previous version of the class are on the stack so
   1.225 -  // we don't need to create a new PreviousVersionNode. However,
   1.226 -  // we still need to examine older previous versions below.
   1.227 -  Array<Method*>* old_methods = ikh->methods();
   1.228 -
   1.229 -  if (cp_ref->on_stack()) {
   1.230 -    PreviousVersionNode * pv_node = NULL;
   1.231 -    if (emcp_method_count == 0) {
   1.232 -      // non-shared ConstantPool gets a reference
   1.233 -      pv_node = new PreviousVersionNode(cp_ref, NULL);
   1.234 -      RC_TRACE(0x00000400,
   1.235 -          ("add: all methods are obsolete; flushing any EMCP refs"));
   1.236 -    } else {
   1.237 -      int local_count = 0;
   1.238 -      GrowableArray<Method*>* method_refs = new (ResourceObj::C_HEAP, mtClass)
   1.239 -          GrowableArray<Method*>(emcp_method_count, true);
   1.240 -      for (int i = 0; i < old_methods->length(); i++) {
   1.241 -        if (emcp_methods->at(i)) {
   1.242 -            // this old method is EMCP. Save it only if it's on the stack
   1.243 -            Method* old_method = old_methods->at(i);
   1.244 -            if (old_method->on_stack()) {
   1.245 -              method_refs->append(old_method);
   1.246 -            }
   1.247 -          if (++local_count >= emcp_method_count) {
   1.248 -            // no more EMCP methods so bail out now
   1.249 -            break;
   1.250 -          }
   1.251 -        }
   1.252 -      }
   1.253 -      // non-shared ConstantPool gets a reference
   1.254 -      pv_node = new PreviousVersionNode(cp_ref, method_refs);
   1.255 -    }
   1.256 -    // append new previous version.
   1.257 -    _previous_versions->append(pv_node);
   1.258 -  }
   1.259 -
   1.260 -  // Since the caller is the VMThread and we are at a safepoint, this
   1.261 -  // is a good time to clear out unused references.
   1.262 -
   1.263 -  RC_TRACE(0x00000400, ("add: previous version length=%d",
   1.264 -    _previous_versions->length()));
   1.265 -
   1.266 -  // Purge previous versions not executing on the stack
   1.267 -  purge_previous_versions_internal(this, emcp_method_count);
   1.268 -
   1.269 +void InstanceKlass::mark_newly_obsolete_methods(Array<Method*>* old_methods,
   1.270 +                                                int emcp_method_count) {
   1.271    int obsolete_method_count = old_methods->length() - emcp_method_count;
   1.272  
   1.273    if (emcp_method_count != 0 && obsolete_method_count != 0 &&
   1.274 -      _previous_versions->length() > 0) {
   1.275 +      _previous_versions != NULL) {
   1.276      // We have a mix of obsolete and EMCP methods so we have to
   1.277      // clear out any matching EMCP method entries the hard way.
   1.278      int local_count = 0;
   1.279      for (int i = 0; i < old_methods->length(); i++) {
   1.280 -      if (!emcp_methods->at(i)) {
   1.281 +      Method* old_method = old_methods->at(i);
   1.282 +      if (old_method->is_obsolete()) {
   1.283          // only obsolete methods are interesting
   1.284 -        Method* old_method = old_methods->at(i);
   1.285          Symbol* m_name = old_method->name();
   1.286          Symbol* m_signature = old_method->signature();
   1.287  
   1.288 -        // we might not have added the last entry
   1.289 -        for (int j = _previous_versions->length() - 1; j >= 0; j--) {
   1.290 -          // check the previous versions array for non executing obsolete methods
   1.291 -          PreviousVersionNode * pv_node = _previous_versions->at(j);
   1.292 -
   1.293 -          GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods();
   1.294 -          if (method_refs == NULL) {
   1.295 -            // We have run into a PreviousVersion generation where
   1.296 -            // all methods were made obsolete during that generation's
   1.297 -            // RedefineClasses() operation. At the time of that
   1.298 -            // operation, all EMCP methods were flushed so we don't
   1.299 -            // have to go back any further.
   1.300 -            //
   1.301 -            // A NULL method_refs is different than an empty method_refs.
   1.302 -            // We cannot infer any optimizations about older generations
   1.303 -            // from an empty method_refs for the current generation.
   1.304 -            break;
   1.305 -          }
   1.306 -
   1.307 -          for (int k = method_refs->length() - 1; k >= 0; k--) {
   1.308 +        // previous versions are linked together through the InstanceKlass
   1.309 +        int j = 0;
   1.310 +        for (InstanceKlass* prev_version = _previous_versions;
   1.311 +             prev_version != NULL;
   1.312 +             prev_version = prev_version->previous_versions(), j++) {
   1.313 +
   1.314 +          Array<Method*>* method_refs = prev_version->methods();
   1.315 +          for (int k = 0; k < method_refs->length(); k++) {
   1.316              Method* method = method_refs->at(k);
   1.317  
   1.318              if (!method->is_obsolete() &&
   1.319 @@ -3828,14 +3728,11 @@
   1.320                  method->signature() == m_signature) {
   1.321                // The current RedefineClasses() call has made all EMCP
   1.322                // versions of this method obsolete so mark it as obsolete
   1.323 -              // and remove the reference.
   1.324                RC_TRACE(0x00000400,
   1.325                  ("add: %s(%s): flush obsolete method @%d in version @%d",
   1.326                  m_name->as_C_string(), m_signature->as_C_string(), k, j));
   1.327  
   1.328                method->set_is_obsolete();
   1.329 -              // Leave obsolete methods on the previous version list to
   1.330 -              // clean up later.
   1.331                break;
   1.332              }
   1.333            }
   1.334 @@ -3843,9 +3740,9 @@
   1.335            // The previous loop may not find a matching EMCP method, but
   1.336            // that doesn't mean that we can optimize and not go any
   1.337            // further back in the PreviousVersion generations. The EMCP
   1.338 -          // method for this generation could have already been deleted,
   1.339 +          // method for this generation could have already been made obsolete,
   1.340            // but there still may be an older EMCP method that has not
   1.341 -          // been deleted.
   1.342 +          // been made obsolete.
   1.343          }
   1.344  
   1.345          if (++local_count >= obsolete_method_count) {
   1.346 @@ -3855,30 +3752,67 @@
   1.347        }
   1.348      }
   1.349    }
   1.350 -} // end add_previous_version()
   1.351 -
   1.352 -
   1.353 -// Determine if InstanceKlass has a previous version.
   1.354 -bool InstanceKlass::has_previous_version() const {
   1.355 -  return (_previous_versions != NULL && _previous_versions->length() > 0);
   1.356 -} // end has_previous_version()
   1.357 -
   1.358 -
   1.359 -InstanceKlass* InstanceKlass::get_klass_version(int version) {
   1.360 -  if (constants()->version() == version) {
   1.361 -    return this;
   1.362 +}
   1.363 +
   1.364 +// Save the scratch_class as the previous version if any of the methods are running.
   1.365 +// The previous_versions are used to set breakpoints in EMCP methods and they are
   1.366 +// also used to clean MethodData links to redefined methods that are no longer running.
   1.367 +void InstanceKlass::add_previous_version(instanceKlassHandle scratch_class,
   1.368 +                                         int emcp_method_count) {
   1.369 +  assert(Thread::current()->is_VM_thread(),
   1.370 +         "only VMThread can add previous versions");
   1.371 +
   1.372 +  // RC_TRACE macro has an embedded ResourceMark
   1.373 +  RC_TRACE(0x00000400, ("adding previous version ref for %s, EMCP_cnt=%d",
   1.374 +    scratch_class->external_name(), emcp_method_count));
   1.375 +
   1.376 +  // Clean out old previous versions
   1.377 +  purge_previous_versions(this);
   1.378 +
   1.379 +  // Mark newly obsolete methods in remaining previous versions.  An EMCP method from
   1.380 +  // a previous redefinition may be made obsolete by this redefinition.
   1.381 +  Array<Method*>* old_methods = scratch_class->methods();
   1.382 +  mark_newly_obsolete_methods(old_methods, emcp_method_count);
   1.383 +
   1.384 +  // If the constant pool for this previous version of the class
   1.385 +  // is not marked as being on the stack, then none of the methods
   1.386 +  // in this previous version of the class are on the stack so
   1.387 +  // we don't need to add this as a previous version.
   1.388 +  ConstantPool* cp_ref = scratch_class->constants();
   1.389 +  if (!cp_ref->on_stack()) {
   1.390 +    RC_TRACE(0x00000400, ("add: scratch class not added; no methods are running"));
   1.391 +    return;
   1.392    }
   1.393 -  PreviousVersionWalker pvw(Thread::current(), (InstanceKlass*)this);
   1.394 -  for (PreviousVersionNode * pv_node = pvw.next_previous_version();
   1.395 -       pv_node != NULL; pv_node = pvw.next_previous_version()) {
   1.396 -    ConstantPool* prev_cp = pv_node->prev_constant_pool();
   1.397 -    if (prev_cp->version() == version) {
   1.398 -      return prev_cp->pool_holder();
   1.399 +
   1.400 +  if (emcp_method_count != 0) {
   1.401 +    // At least one method is still running, check for EMCP methods
   1.402 +    for (int i = 0; i < old_methods->length(); i++) {
   1.403 +      Method* old_method = old_methods->at(i);
   1.404 +      if (!old_method->is_obsolete() && old_method->on_stack()) {
   1.405 +        // if EMCP method (not obsolete) is on the stack, mark as EMCP so that
   1.406 +        // we can add breakpoints for it.
   1.407 +
   1.408 +        // We set the method->on_stack bit during safepoints for class redefinition and
   1.409 +        // class unloading and use this bit to set the is_running_emcp bit.
   1.410 +        // After the safepoint, the on_stack bit is cleared and the running emcp
   1.411 +        // method may exit.   If so, we would set a breakpoint in a method that
   1.412 +        // is never reached, but this won't be noticeable to the programmer.
   1.413 +        old_method->set_running_emcp(true);
   1.414 +        RC_TRACE(0x00000400, ("add: EMCP method %s is on_stack " INTPTR_FORMAT,
   1.415 +                              old_method->name_and_sig_as_C_string(), old_method));
   1.416 +      } else if (!old_method->is_obsolete()) {
   1.417 +        RC_TRACE(0x00000400, ("add: EMCP method %s is NOT on_stack " INTPTR_FORMAT,
   1.418 +                              old_method->name_and_sig_as_C_string(), old_method));
   1.419 +      }
   1.420      }
   1.421    }
   1.422 -  return NULL; // None found
   1.423 -}
   1.424 -
   1.425 +
   1.426 +  // Add previous version if any methods are still running.
   1.427 +  RC_TRACE(0x00000400, ("add: scratch class added; one of its methods is on_stack"));
   1.428 +  assert(scratch_class->previous_versions() == NULL, "shouldn't have a previous version");
   1.429 +  scratch_class->link_previous_versions(previous_versions());
   1.430 +  link_previous_versions(scratch_class());
   1.431 +} // end add_previous_version()
   1.432  
   1.433  Method* InstanceKlass::method_with_idnum(int idnum) {
   1.434    Method* m = NULL;
   1.435 @@ -3936,61 +3870,3 @@
   1.436  unsigned char * InstanceKlass::get_cached_class_file_bytes() {
   1.437    return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file);
   1.438  }
   1.439 -
   1.440 -
   1.441 -// Construct a PreviousVersionNode entry for the array hung off
   1.442 -// the InstanceKlass.
   1.443 -PreviousVersionNode::PreviousVersionNode(ConstantPool* prev_constant_pool,
   1.444 -  GrowableArray<Method*>* prev_EMCP_methods) {
   1.445 -
   1.446 -  _prev_constant_pool = prev_constant_pool;
   1.447 -  _prev_EMCP_methods = prev_EMCP_methods;
   1.448 -}
   1.449 -
   1.450 -
   1.451 -// Destroy a PreviousVersionNode
   1.452 -PreviousVersionNode::~PreviousVersionNode() {
   1.453 -  if (_prev_constant_pool != NULL) {
   1.454 -    _prev_constant_pool = NULL;
   1.455 -  }
   1.456 -
   1.457 -  if (_prev_EMCP_methods != NULL) {
   1.458 -    delete _prev_EMCP_methods;
   1.459 -  }
   1.460 -}
   1.461 -
   1.462 -// Construct a helper for walking the previous versions array
   1.463 -PreviousVersionWalker::PreviousVersionWalker(Thread* thread, InstanceKlass *ik) {
   1.464 -  _thread = thread;
   1.465 -  _previous_versions = ik->previous_versions();
   1.466 -  _current_index = 0;
   1.467 -  _current_p = NULL;
   1.468 -  _current_constant_pool_handle = constantPoolHandle(thread, ik->constants());
   1.469 -}
   1.470 -
   1.471 -
   1.472 -// Return the interesting information for the next previous version
   1.473 -// of the klass. Returns NULL if there are no more previous versions.
   1.474 -PreviousVersionNode* PreviousVersionWalker::next_previous_version() {
   1.475 -  if (_previous_versions == NULL) {
   1.476 -    // no previous versions so nothing to return
   1.477 -    return NULL;
   1.478 -  }
   1.479 -
   1.480 -  _current_p = NULL;  // reset to NULL
   1.481 -  _current_constant_pool_handle = NULL;
   1.482 -
   1.483 -  int length = _previous_versions->length();
   1.484 -
   1.485 -  while (_current_index < length) {
   1.486 -    PreviousVersionNode * pv_node = _previous_versions->at(_current_index++);
   1.487 -
   1.488 -    // Save a handle to the constant pool for this previous version,
   1.489 -    // which keeps all the methods from being deallocated.
   1.490 -    _current_constant_pool_handle = constantPoolHandle(_thread, pv_node->prev_constant_pool());
   1.491 -    _current_p = pv_node;
   1.492 -    return pv_node;
   1.493 -  }
   1.494 -
   1.495 -  return NULL;
   1.496 -} // end next_previous_version()

mercurial