[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#987658: unblock: openjdk-11-jre-dcevm/11.0.11+9-1



Hi Paul,

On 14/05/2021 21:46, Paul Gevers wrote:

> I missed so far that apparently DCEVM is a patch set to the same OpenJDK
> we already have in the archive. Is it feasible, i.e. does it make sense
> and would it help us review it, if you generate a diff of patches,
> instead of the source diff that includes all the changes to OpenJDK
> (which we already have in bullseye)?

I've compared DCEVM 11.0.10 [1] and 11.0.11 [2], the version 11.0.10 has
26 commits applied on top of OpenJDK (d0a670c..beb1c75), the version
11.0.11 has the same 26 commits rebased (ef59517..e27e254) plus 10 new
commits (7e0e338..28b9ff6), they add 215 lines and remove 17. I'm
attaching the diff for the extra commits, they can also be reviewed on
GitHub [3].

Emmanuel Bourg

[1]
https://github.com/HotswapProjects/openjdk-jdk11u-dcevm/commits/dcevm-11.0.11+1
[2]
https://github.com/HotswapProjects/openjdk-jdk11u-dcevm/commits/dcevm-11.0.10+1
[3]
https://github.com/HotswapProjects/openjdk-jdk11u-dcevm/compare/7e0e338..28b9ff6
diff --git a/src/hotspot/share/ci/ciKlass.hpp b/src/hotspot/share/ci/ciKlass.hpp
index b15da89732..dc7f05f2c7 100644
--- a/src/hotspot/share/ci/ciKlass.hpp
+++ b/src/hotspot/share/ci/ciKlass.hpp
@@ -131,6 +131,7 @@ public:
   const char* external_name() const;
 
   bool is_deoptimization_excl() { return get_Klass()->is_deoptimization_excl(); }
+  Klass* new_version() { return get_Klass()->new_version(); }
 };
 
 #endif // SHARE_VM_CI_CIKLASS_HPP
diff --git a/src/hotspot/share/ci/ciObjectFactory.cpp b/src/hotspot/share/ci/ciObjectFactory.cpp
index 66bbe835e7..107c16fa5c 100644
--- a/src/hotspot/share/ci/ciObjectFactory.cpp
+++ b/src/hotspot/share/ci/ciObjectFactory.cpp
@@ -70,7 +70,10 @@ GrowableArray<ciMetadata*>* ciObjectFactory::_shared_ci_metadata = NULL;
 ciSymbol*                 ciObjectFactory::_shared_ci_symbols[vmSymbols::SID_LIMIT];
 int                       ciObjectFactory::_shared_ident_limit = 0;
 volatile bool             ciObjectFactory::_initialized = false;
+volatile bool             ciObjectFactory::_reinitialize_wk_klasses = false;
 
+// TODO: review...
+Arena* ciObjectFactory::_initial_arena = NULL;
 
 // ------------------------------------------------------------------
 // ciObjectFactory::ciObjectFactory
@@ -112,6 +115,7 @@ void ciObjectFactory::initialize() {
   // compiler thread that initializes the initial ciObjectFactory which
   // creates the shared ciObjects that all later ciObjectFactories use.
   Arena* arena = new (mtCompiler) Arena(mtCompiler);
+  ciObjectFactory::_initial_arena = arena;
   ciEnv initial(arena);
   ciEnv* env = ciEnv::current();
   env->_factory->init_shared_objects();
@@ -120,6 +124,36 @@ void ciObjectFactory::initialize() {
 
 }
 
+// (DCEVM) wk classes could be modified
+void ciObjectFactory::reinitialize_wk_classes() {
+  ASSERT_IN_VM;
+  JavaThread* thread = JavaThread::current();
+  HandleMark  handle_mark(thread);
+
+  // This Arena is long lived and exists in the resource mark of the
+  // compiler thread that initializes the initial ciObjectFactory which
+  // creates the shared ciObjects that all later ciObjectFactories use.
+  // Arena* arena = new (mtCompiler) Arena(mtCompiler);
+  ciEnv initial(ciObjectFactory::_initial_arena);
+  ciEnv* env = ciEnv::current();
+  env->_factory->do_reinitialize_wk_classes();
+  _reinitialize_wk_klasses = false;
+}
+
+// (DCEVM) wk classes could be modified
+void ciObjectFactory::do_reinitialize_wk_classes() {
+#define WK_KLASS_DEFN(name, ignore_s, opt)   \
+  if (ciEnv::_##name != NULL && ciEnv::_##name->new_version() != NULL) { \
+    int old_ident = ciEnv::_##name->ident(); \
+    ciEnv::_##name = get_metadata(SystemDictionary::name())->as_instance_klass(); \
+    ciEnv::_##name->compute_nonstatic_fields(); \
+    ciEnv::_##name->set_ident(old_ident); \
+  }
+
+  WK_KLASSES_DO(WK_KLASS_DEFN)
+#undef WK_KLASS_DEFN
+}
+
 void ciObjectFactory::init_shared_objects() {
 
   _next_ident = 1;  // start numbering CI objects at 1
diff --git a/src/hotspot/share/ci/ciObjectFactory.hpp b/src/hotspot/share/ci/ciObjectFactory.hpp
index 3e9d48c4cd..79059f6e2e 100644
--- a/src/hotspot/share/ci/ciObjectFactory.hpp
+++ b/src/hotspot/share/ci/ciObjectFactory.hpp
@@ -41,9 +41,11 @@ class ciObjectFactory : public ResourceObj {
 
 private:
   static volatile bool _initialized;
+  static volatile bool _reinitialize_wk_klasses;
   static GrowableArray<ciMetadata*>* _shared_ci_metadata;
   static ciSymbol*                 _shared_ci_symbols[];
   static int                       _shared_ident_limit;
+  static Arena*                    _initial_arena;
 
   Arena*                    _arena;
   GrowableArray<ciMetadata*>*        _ci_metadata;
@@ -89,10 +91,14 @@ private:
   ciInstance* get_unloaded_instance(ciInstanceKlass* klass);
 
   static int compare_cimetadata(ciMetadata** a, ciMetadata** b);
+  void do_reinitialize_wk_classes();
 public:
   static bool is_initialized() { return _initialized; }
+  static bool is_reinitialize_wk_klasses() { return _reinitialize_wk_klasses; }
+  static void set_reinitialize_wk_klasses() { _reinitialize_wk_klasses = true; }
 
   static void initialize();
+  static void reinitialize_wk_classes();
   void init_shared_objects();
   void remove_symbols();
 
diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp
index 8b2deb70e1..f319cca3b2 100644
--- a/src/hotspot/share/classfile/classLoaderData.cpp
+++ b/src/hotspot/share/classfile/classLoaderData.cpp
@@ -1166,6 +1166,16 @@ void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) {
   }
 }
 
+void ClassLoaderDataGraph::anonymous_classes_do(KlassClosure* klass_closure) {
+  Thread* thread = Thread::current();
+  for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
+    if (cld->is_anonymous()) {
+      Handle holder(thread, cld->holder_phantom());
+      cld->classes_do(klass_closure);
+    }
+  }
+}
+
 void ClassLoaderDataGraph::classes_do(void f(Klass* const)) {
   Thread* thread = Thread::current();
   for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
@@ -1274,6 +1284,15 @@ void ClassLoaderDataGraph::rollback_redefinition() {
   }
 }
 
+// (DCEVM) - iterate over all classes in all dictionaries
+bool ClassLoaderDataGraph::dictionary_classes_do_update_klass(Symbol* name, InstanceKlass* k, InstanceKlass* old_klass) {
+  bool ok = false;
+  FOR_ALL_DICTIONARY(cld) {
+    ok = cld->dictionary()->update_klass(name, k, old_klass) || ok;
+  }
+  return ok;
+}
+
 // Walks all entries in the dictionary including entries initiated by this class loader.
 void ClassLoaderDataGraph::dictionary_all_entries_do(void f(InstanceKlass*, ClassLoaderData*)) {
   Thread* thread = Thread::current();
diff --git a/src/hotspot/share/classfile/classLoaderData.hpp b/src/hotspot/share/classfile/classLoaderData.hpp
index 00a84610b4..b10fafa01e 100644
--- a/src/hotspot/share/classfile/classLoaderData.hpp
+++ b/src/hotspot/share/classfile/classLoaderData.hpp
@@ -108,6 +108,10 @@ class ClassLoaderDataGraph : public AllStatic {
   // for redefinition.  These classes are removed during the next class unloading.
   // Walking the ClassLoaderDataGraph also includes anonymous classes.
   static void classes_do(KlassClosure* klass_closure);
+
+  // Enhanced class redefinition
+  static void anonymous_classes_do(KlassClosure* klass_closure);
+
   static void classes_do(void f(Klass* const));
   static void methods_do(void f(Method*));
   static void modules_do(void f(ModuleEntry*));
@@ -130,6 +134,9 @@ class ClassLoaderDataGraph : public AllStatic {
   // Enhanced class redefinition
   static void rollback_redefinition();
 
+  // Enhanced class redefinition
+  static bool dictionary_classes_do_update_klass(Symbol* name, InstanceKlass* k, InstanceKlass* old_klass);
+
   // Iterate all classes and their class loaders, including initiating class loaders.
   static void dictionary_all_entries_do(void f(InstanceKlass*, ClassLoaderData*));
 
diff --git a/src/hotspot/share/classfile/dictionary.cpp b/src/hotspot/share/classfile/dictionary.cpp
index dda5188c37..6c072407fd 100644
--- a/src/hotspot/share/classfile/dictionary.cpp
+++ b/src/hotspot/share/classfile/dictionary.cpp
@@ -345,7 +345,7 @@ DictionaryEntry* Dictionary::get_entry(int index, unsigned int hash,
 }
 
 // (DCEVM) replace old_class by new class in dictionary
-bool Dictionary::update_klass(unsigned int hash, Symbol* name, ClassLoaderData* loader_data, InstanceKlass* k, InstanceKlass* old_klass) {
+bool Dictionary::update_klass(Symbol* name, InstanceKlass* k, InstanceKlass* old_klass) {
   // There are several entries for the same class in the dictionary: One extra entry for each parent classloader of the classloader of the class.
   bool found = false;
   for (int index = 0; index < table_size(); index++) {
@@ -381,7 +381,7 @@ InstanceKlass* Dictionary::find(unsigned int hash, Symbol* name,
   int index = hash_to_index(hash);
   DictionaryEntry* entry = get_entry(index, hash, name);
   if (entry != NULL && entry->is_valid_protection_domain(protection_domain)) {
-    return old_if_redefined(entry->instance_klass());
+    return old_if_redefining(entry->instance_klass());
   } else {
     return NULL;
   }
@@ -394,7 +394,7 @@ InstanceKlass* Dictionary::find_class(int index, unsigned int hash,
   assert (index == index_for(name), "incorrect index?");
 
   DictionaryEntry* entry = get_entry(index, hash, name);
-  return old_if_redefined((entry != NULL) ? entry->instance_klass() : NULL);
+  return old_if_redefining((entry != NULL) ? entry->instance_klass() : NULL);
 }
 
 
@@ -406,7 +406,7 @@ InstanceKlass* Dictionary::find_shared_class(int index, unsigned int hash,
   assert (index == index_for(name), "incorrect index?");
 
   DictionaryEntry* entry = get_entry(index, hash, name);
-  return old_if_redefined((entry != NULL) ? entry->instance_klass() : NULL);
+  return old_if_redefining((entry != NULL) ? entry->instance_klass() : NULL);
 }
 
 
diff --git a/src/hotspot/share/classfile/dictionary.hpp b/src/hotspot/share/classfile/dictionary.hpp
index 5eaa741d50..2932cc9c32 100644
--- a/src/hotspot/share/classfile/dictionary.hpp
+++ b/src/hotspot/share/classfile/dictionary.hpp
@@ -115,12 +115,12 @@ public:
   void free_entry(DictionaryEntry* entry);
 
   // Enhanced class redefinition
-  bool update_klass(unsigned int hash, Symbol* name, ClassLoaderData* loader_data, InstanceKlass* k, InstanceKlass* old_klass);
+  bool update_klass(Symbol* name, InstanceKlass* k, InstanceKlass* old_klass);
 
   void rollback_redefinition();
 
   // (DCEVM) return old class if redefining in AllowEnhancedClassRedefinition, otherwise return "k"
-  static InstanceKlass* old_if_redefined(InstanceKlass* k) {
+  static InstanceKlass* old_if_redefining(InstanceKlass* k) {
     return (k != NULL && k->is_redefining()) ? ((InstanceKlass* )k->old_version()) : k;
   }
 };
diff --git a/src/hotspot/share/classfile/metadataOnStackMark.cpp b/src/hotspot/share/classfile/metadataOnStackMark.cpp
index 9d7bdbde74..66049f1162 100644
--- a/src/hotspot/share/classfile/metadataOnStackMark.cpp
+++ b/src/hotspot/share/classfile/metadataOnStackMark.cpp
@@ -49,10 +49,11 @@ NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;)
 MetadataOnStackMark::MetadataOnStackMark(bool redefinition_walk, bool ignore) : _ignore(ignore) {
   assert(SafepointSynchronize::is_at_safepoint(), "sanity check");
   assert(_used_buffers == NULL, "sanity check");
-  assert(!_is_active, "MetadataOnStackMarks do not nest");
-  NOT_PRODUCT(_is_active = true;)
 
   if (!ignore) {
+    assert(!_is_active, "MetadataOnStackMarks do not nest");
+    NOT_PRODUCT(_is_active = true;)
+
     Threads::metadata_handles_do(Metadata::mark_on_stack);
 
     if (redefinition_walk) {
diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp
index 6e8515c02a..3368b74217 100644
--- a/src/hotspot/share/classfile/systemDictionary.cpp
+++ b/src/hotspot/share/classfile/systemDictionary.cpp
@@ -1611,7 +1611,9 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, InstanceKlass* ol
   Dictionary* dictionary = loader_data->dictionary();
   unsigned int d_hash = dictionary->compute_hash(name_h);
   if (is_redefining) {
-    bool ok = dictionary->update_klass(d_hash, name_h, loader_data, k, old_klass);
+    // Update all dictionaries containing old_class to new_class
+    // outcome must be same as result of standard redefinition, that does not create a new Klass
+    bool ok = ClassLoaderDataGraph::dictionary_classes_do_update_klass(name_h, k, old_klass);
     assert (ok, "must have found old class and updated!");
   }
   check_constraints(d_hash, k, class_loader_h, !is_redefining, CHECK);
@@ -1986,6 +1988,16 @@ bool SystemDictionary::is_well_known_klass(Symbol* class_name) {
 }
 #endif
 
+bool SystemDictionary::update_well_known_klass(InstanceKlass* old_klass, InstanceKlass* new_klass) {
+  for (int id = FIRST_WKID; id < WKID_LIMIT; id++) {
+    if (well_known_klass((WKID) id) == old_klass) {
+      *well_known_klass_addr((WKID)id) = new_klass;
+      return true;
+    }
+  }
+  return false;
+}
+
 bool SystemDictionary::resolve_wk_klass(WKID id, int init_opt, TRAPS) {
   assert(id >= (int)FIRST_WKID && id < (int)WKID_LIMIT, "oob");
   int  info = wk_init_info[id - FIRST_WKID];
diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp
index 1dbbffa197..4220978a02 100644
--- a/src/hotspot/share/classfile/systemDictionary.hpp
+++ b/src/hotspot/share/classfile/systemDictionary.hpp
@@ -467,6 +467,8 @@ public:
   static bool is_well_known_klass(Symbol* class_name);
 #endif
 
+  static bool update_well_known_klass(InstanceKlass* new_klass, InstanceKlass* old_klass);
+
   // Enhanced class redefinition
   static void remove_from_hierarchy(InstanceKlass* k);
   static void update_constraints_after_redefinition();
diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp
index 2409af9b06..daaa8d1237 100644
--- a/src/hotspot/share/classfile/vmSymbols.hpp
+++ b/src/hotspot/share/classfile/vmSymbols.hpp
@@ -355,6 +355,8 @@
   template(exit_method_name,                          "exit")                                     \
   template(add_method_name,                           "add")                                      \
   template(remove_method_name,                        "remove")                                   \
+  template(registerNatives_method_name,               "registerNatives")                          \
+  template(initIDs_method_name,                       "initIDs")                                  \
   template(parent_name,                               "parent")                                   \
   template(threads_name,                              "threads")                                  \
   template(groups_name,                               "groups")                                   \
diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp
index 60aa462604..bc39e147f2 100644
--- a/src/hotspot/share/compiler/compileBroker.cpp
+++ b/src/hotspot/share/compiler/compileBroker.cpp
@@ -1876,6 +1876,17 @@ void CompileBroker::compiler_thread_loop() {
       if (method()->number_of_breakpoints() == 0) {
         // Compile the method.
         if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) {
+
+          // TODO: review usage of CompileThread_lock (DCEVM)
+          if (ciObjectFactory::is_reinitialize_wk_klasses())
+          {
+            ASSERT_IN_VM;
+            MutexLocker only_one (CompileThread_lock, thread);
+            if (ciObjectFactory::is_reinitialize_wk_klasses()) {
+              ciObjectFactory::reinitialize_wk_classes();
+            }
+          }
+
           invoke_compiler_on_method(task);
           thread->start_idle_timer();
         } else {
diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp
index 3dc4cc1323..6b88271b5e 100644
--- a/src/hotspot/share/memory/universe.cpp
+++ b/src/hotspot/share/memory/universe.cpp
@@ -1030,6 +1030,14 @@ void Universe::initialize_known_methods(TRAPS) {
                           vmSymbols::doStackWalk_signature(), false, CHECK);
 }
 
+void Universe::reinitialize_loader_addClass_method(TRAPS) {
+  // Set up method for registering loaded classes in class loader vector
+  initialize_known_method(_loader_addClass_cache,
+                          SystemDictionary::ClassLoader_klass(),
+                          "addClass",
+                          vmSymbols::class_void_signature(), false, CHECK);
+}
+
 void universe2_init() {
   EXCEPTION_MARK;
   Universe::genesis(CATCH);
diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp
index b32db16b9c..d1af82b5fa 100644
--- a/src/hotspot/share/memory/universe.hpp
+++ b/src/hotspot/share/memory/universe.hpp
@@ -52,13 +52,8 @@ class LatestMethodCache : public CHeapObj<mtClass> {
   Klass*                _klass;
   int                   _method_idnum;
 
-  static bool _is_redefining_gc_run;
-
  public:
 
-   static bool is_redefining_gc_run()               { return _is_redefining_gc_run; }
-   static void set_redefining_gc_run(bool b)        { _is_redefining_gc_run = b;    }
-
   LatestMethodCache()   { _klass = NULL; _method_idnum = -1; }
   ~LatestMethodCache()  { _klass = NULL; _method_idnum = -1; }
 
@@ -354,6 +349,9 @@ class Universe: AllStatic {
   // Function to initialize these
   static void initialize_known_methods(TRAPS);
 
+  // Enhanced class redefinition
+  static void reinitialize_loader_addClass_method(TRAPS);
+
   static oop          null_ptr_exception_instance()   { return _null_ptr_exception_instance;   }
   static oop          arithmetic_exception_instance() { return _arithmetic_exception_instance; }
   static oop          virtual_machine_error_instance() { return _virtual_machine_error_instance; }
diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp
index 710e0ddc93..24eb3ed68a 100644
--- a/src/hotspot/share/oops/instanceKlass.cpp
+++ b/src/hotspot/share/oops/instanceKlass.cpp
@@ -327,11 +327,21 @@ bool InstanceKlass::has_nestmate_access_to(InstanceKlass* k, TRAPS) {
     return false;
   }
 
+  // (DCEVM) cur_host can be old, decide accessibility based on active version
+  if (AllowEnhancedClassRedefinition) {
+    cur_host = InstanceKlass::cast(cur_host->active_version());
+  }
+
   Klass* k_nest_host = k->nest_host(icce, CHECK_false);
   if (k_nest_host == NULL) {
     return false;
   }
 
+  // (DCEVM) k_nest_host can be old, decide accessibility based on active version
+  if (AllowEnhancedClassRedefinition) {
+    k_nest_host = InstanceKlass::cast(k_nest_host->active_version());
+  }
+
   bool access = (cur_host == k_nest_host);
 
   if (log_is_enabled(Trace, class, nestmates)) {
diff --git a/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.cpp
index 06424b3e6f..e56b74e365 100644
--- a/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.cpp
+++ b/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.cpp
@@ -84,6 +84,7 @@ Klass*      VM_EnhancedRedefineClasses::_the_class_oop = NULL;
 VM_EnhancedRedefineClasses::VM_EnhancedRedefineClasses(jint class_count, const jvmtiClassDefinition *class_defs, JvmtiClassLoadKind class_load_kind) :
         VM_GC_Operation(Universe::heap()->total_collections(), GCCause::_heap_inspection, Universe::heap()->total_full_collections(), true) {
   _affected_klasses = NULL;
+  _new_anonymous_classes = NULL;
   _class_count = class_count;
   _class_defs = class_defs;
   _class_load_kind = class_load_kind;
@@ -159,6 +160,8 @@ bool VM_EnhancedRedefineClasses::doit_prologue() {
         cld->add_to_deallocate_list(InstanceKlass::cast(_new_classes[i]));
       }
     }*/
+    delete _new_anonymous_classes;
+    _new_anonymous_classes = NULL;
     delete _new_classes;
     _new_classes = NULL;
     delete _affected_klasses;
@@ -497,6 +500,16 @@ void VM_EnhancedRedefineClasses::doit() {
     redefine_single_class(_new_classes->at(i), thread);
   }
 
+  // Update possible redefinition of well-known classes (like ClassLoader)
+  for (int i = 0; i < _new_classes->length(); i++) {
+    InstanceKlass* cur = _new_classes->at(i);
+    if (cur->old_version() != NULL && SystemDictionary::update_well_known_klass(InstanceKlass::cast(cur->old_version()), cur))
+    {
+      log_trace(redefine, class, obsolete, metadata)("Well known class updated %s", cur->external_name());
+      ciObjectFactory::set_reinitialize_wk_klasses();
+    }
+  }
+
   // Deoptimize all compiled code that depends on this class (do only once, because it clears whole cache)
   // if (_max_redefinition_flags > Klass::ModifyClass) {
     flush_dependent_code(NULL, thread);
@@ -669,16 +682,65 @@ void VM_EnhancedRedefineClasses::doit() {
   _timer_vm_op_doit.stop();
 }
 
+void VM_EnhancedRedefineClasses::reinitializeJDKClasses() {
+  if (!_new_classes->is_empty()) {
+    ResourceMark rm(Thread::current());
+
+    for (int i = 0; i < _new_classes->length(); i++) {
+      InstanceKlass* cur = _new_classes->at(i);
+
+      if ((cur->name()->starts_with("java/") || cur->name()->starts_with("jdk/") || cur->name()->starts_with("sun/"))
+          && cur->name()->index_of_at(0, "$$") == -1) { // skip dynamic proxies
+
+        if (cur == SystemDictionary::ClassLoader_klass()) {
+          // ClassLoader.addClass method is cached in Universe, we must redefine
+          Universe::reinitialize_loader_addClass_method(Thread::current());
+          log_trace(redefine, class, obsolete, metadata)("Reinitialize ClassLoade addClass method cache.");
+        }
+
+        // naive assumptions that only JDK classes has native static "registerNative" and "initIDs" methods
+        int end;
+        Symbol* signature = vmSymbols::registerNatives_method_name();
+        int midx = cur->find_method_by_name(signature, &end);
+        if (midx == -1) {
+          signature = vmSymbols::initIDs_method_name();
+          midx = cur->find_method_by_name(signature, &end);
+        }
+        Method* m = NULL;
+        if (midx != -1) {
+          m = cur->methods()->at(midx);
+        }
+        if (m != NULL && m->is_static() && m->is_native()) {
+          // call static registerNative if present
+          JavaValue result(T_VOID);
+          JavaCalls::call_static(&result,
+                                  cur,
+                                  signature,
+                                  vmSymbols::void_method_signature(),
+                                  Thread::current());
+          log_trace(redefine, class, obsolete, metadata)("Reregister natives of JDK class %s", cur->external_name());
+        }
+      }
+    }
+  }
+}
+
 // Cleanup - runs in JVM thread
 //  - free used memory
 //  - end GC
 void VM_EnhancedRedefineClasses::doit_epilogue() {
   VM_GC_Operation::doit_epilogue();
 
+  reinitializeJDKClasses();
+
   if (_new_classes != NULL) {
     delete _new_classes;
   }
   _new_classes = NULL;
+  if (_new_anonymous_classes != NULL) {
+    delete _new_anonymous_classes;
+  }
+  _new_anonymous_classes = NULL;
   if (_affected_klasses != NULL) {
     delete _affected_klasses;
   }
@@ -732,6 +794,7 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions(TRAPS) {
 
   _affected_klasses = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<Klass*>(_class_count, true);
   _new_classes = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<InstanceKlass*>(_class_count, true);
+  _new_anonymous_classes = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<InstanceKlass*>(0, true);
 
   ResourceMark rm(THREAD);
 
@@ -820,6 +883,7 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions(TRAPS) {
                                          THREAD);
       k->class_loader_data()->exchange_holders(the_class->class_loader_data());
       the_class->class_loader_data()->inc_keep_alive();
+      _new_anonymous_classes->append(k);
     } else {
       k = SystemDictionary::resolve_from_stream(the_class_sym,
                                                   the_class_loader,
@@ -1370,6 +1434,12 @@ void VM_EnhancedRedefineClasses::rollback() {
   log_info(redefine, class, load)("Rolling back redefinition, result=%d", _res);
   ClassLoaderDataGraph::rollback_redefinition();
 
+  for (int i = 0; i < _new_anonymous_classes->length(); i++) {
+    InstanceKlass* k = _new_anonymous_classes->at(i);
+    k->class_loader_data()->exchange_holders(k->old_version()->class_loader_data());
+  }
+  _new_anonymous_classes->clear();
+
   for (int i = 0; i < _new_classes->length(); i++) {
     SystemDictionary::remove_from_hierarchy(_new_classes->at(i));
   }
@@ -1564,7 +1634,12 @@ void VM_EnhancedRedefineClasses::check_methods_and_mark_as_obsolete() {
 
       // obsolete methods need a unique idnum so they become new entries in
       // the jmethodID cache in InstanceKlass
-      assert(old_method->method_idnum() == new_method->method_idnum(), "must match");
+      if (old_method->method_idnum() != new_method->method_idnum()) {
+        log_error(redefine, class, normalize)
+          ("Method not matched: %d != %d  old: %s = new: %s",  old_method->method_idnum(), new_method->method_idnum(),
+              old_method->name_and_sig_as_C_string(), new_method->name_and_sig_as_C_string());
+        // assert(old_method->method_idnum() == new_method->method_idnum(), "must match");
+      }
 //      u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum();
 //      if (num != ConstMethod::UNSET_IDNUM) {
 //        old_method->set_method_idnum(num);
@@ -2045,8 +2120,17 @@ jvmtiError VM_EnhancedRedefineClasses::find_sorted_affected_classes(TRAPS) {
   AffectedKlassClosure closure(_affected_klasses);
   // Updated in j10, from original SystemDictionary::classes_do
 
-  ClassLoaderDataGraph::classes_do(&closure);
-  //ClassLoaderDataGraph::dictionary_classes_do(&closure);
+  // 0. we can't use ClassLoaderDataGraph::classes_do since classes can be uninitialized in cld,
+  // fully initialized class is in system dictionary
+  // ClassLoaderDataGraph::classes_do(&closure);
+
+  // 1. Scan over dictionaries
+  ClassLoaderDataGraph::dictionary_classes_do(&closure);
+
+  // 2. Anonymous class is not in dictionary, we have to iterate anonymous cld directly, but there is race cond...
+  // TODO: review ... anonymous class is added to cld before InstanceKlass initialization,
+  //                  find out how to check if the InstanceKlass is initialized
+  ClassLoaderDataGraph::anonymous_classes_do(&closure);
 
   log_trace(redefine, class, load)("%d classes affected", _affected_klasses->length());
 
diff --git a/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.hpp b/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.hpp
index 535fa2114d..e23148c71a 100644
--- a/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.hpp
+++ b/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.hpp
@@ -70,6 +70,7 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
   JvmtiClassLoadKind          _class_load_kind;
 
   GrowableArray<InstanceKlass*>*      _new_classes;
+  GrowableArray<InstanceKlass*>*      _new_anonymous_classes;
   jvmtiError                  _res;
 
   // Set if any of the InstanceKlasses have entries in the ResolvedMethodTable
@@ -140,6 +141,8 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
 
   void flush_dependent_code(InstanceKlass* k_h, TRAPS);
 
+  void reinitializeJDKClasses();
+
   static void check_class(InstanceKlass* k_oop, TRAPS);
 
   static void dump_methods();

Reply to: