8220512: Deoptimize redefinition functions that have dirty ICs
authorcoleenp
Fri, 15 Mar 2019 16:00:18 -0400
changeset 54150 5529640c5f67
parent 54149 c61f09122d3b
child 54151 d2f8b7b33013
8220512: Deoptimize redefinition functions that have dirty ICs Summary: Walk ICs to determine whether nmethods are dependent on redefined classes. Reviewed-by: sspitsyn, eosterlund
src/hotspot/share/aot/aotCodeHeap.cpp
src/hotspot/share/aot/aotCodeHeap.hpp
src/hotspot/share/aot/aotCompiledMethod.cpp
src/hotspot/share/aot/aotCompiledMethod.hpp
src/hotspot/share/aot/aotLoader.cpp
src/hotspot/share/aot/aotLoader.hpp
src/hotspot/share/ci/ciEnv.hpp
src/hotspot/share/ci/ciObjectFactory.cpp
src/hotspot/share/ci/ciObjectFactory.hpp
src/hotspot/share/classfile/metadataOnStackMark.cpp
src/hotspot/share/code/codeCache.cpp
src/hotspot/share/code/codeCache.hpp
src/hotspot/share/code/compiledMethod.cpp
src/hotspot/share/code/compiledMethod.hpp
src/hotspot/share/code/nmethod.cpp
src/hotspot/share/code/nmethod.hpp
src/hotspot/share/compiler/compileTask.cpp
src/hotspot/share/compiler/compileTask.hpp
src/hotspot/share/memory/iterator.hpp
src/hotspot/share/runtime/frame.cpp
src/hotspot/share/runtime/frame.hpp
src/hotspot/share/runtime/thread.cpp
src/hotspot/share/runtime/thread.hpp
--- a/src/hotspot/share/aot/aotCodeHeap.cpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/aot/aotCodeHeap.cpp	Fri Mar 15 16:00:18 2019 -0400
@@ -931,13 +931,13 @@
 // Scan only klasses_got cells which should have only Klass*,
 // metadata_got cells are scanned only for alive AOT methods
 // by AOTCompiledMethod::metadata_do().
-void AOTCodeHeap::got_metadata_do(void f(Metadata*)) {
+void AOTCodeHeap::got_metadata_do(MetadataClosure* f) {
   for (int i = 1; i < _klasses_got_size; i++) {
     Metadata** p = &_klasses_got[i];
     Metadata* md = *p;
     if (md == NULL)  continue;  // skip non-oops
     if (Metaspace::contains(md)) {
-      f(md);
+      f->do_metadata(md);
     } else {
       intptr_t meta = (intptr_t)md;
       fatal("Invalid value in _klasses_got[%d] = " INTPTR_FORMAT, i, meta);
@@ -969,7 +969,7 @@
 }
 #endif
 
-void AOTCodeHeap::metadata_do(void f(Metadata*)) {
+void AOTCodeHeap::metadata_do(MetadataClosure* f) {
   for (int index = 0; index < _method_count; index++) {
     if (_code_to_aot[index]._state != in_use) {
       continue; // Skip uninitialized entries.
--- a/src/hotspot/share/aot/aotCodeHeap.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/aot/aotCodeHeap.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -252,8 +252,8 @@
 
 
   void oops_do(OopClosure* f);
-  void metadata_do(void f(Metadata*));
-  void got_metadata_do(void f(Metadata*));
+  void metadata_do(MetadataClosure* f);
+  void got_metadata_do(MetadataClosure* f);
 
 #ifdef ASSERT
   bool got_contains(Metadata **p) {
--- a/src/hotspot/share/aot/aotCompiledMethod.cpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/aot/aotCompiledMethod.cpp	Fri Mar 15 16:00:18 2019 -0400
@@ -246,7 +246,7 @@
 
 // Iterate over metadata calling this function.   Used by RedefineClasses
 // Copied from nmethod::metadata_do
-void AOTCompiledMethod::metadata_do(void f(Metadata*)) {
+void AOTCompiledMethod::metadata_do(MetadataClosure* f) {
   address low_boundary = verified_entry_point();
   {
     // Visit all immediate references that are embedded in the instruction stream.
@@ -262,7 +262,7 @@
                "metadata must be found in exactly one place");
         if (r->metadata_is_immediate() && r->metadata_value() != NULL) {
           Metadata* md = r->metadata_value();
-          if (md != _method) f(md);
+          if (md != _method) f->do_metadata(md);
         }
       } else if (iter.type() == relocInfo::virtual_call_type) {
         ResourceMark rm;
@@ -270,13 +270,13 @@
         CompiledIC *ic = CompiledIC_at(&iter);
         if (ic->is_icholder_call()) {
           CompiledICHolder* cichk = ic->cached_icholder();
-          f(cichk->holder_metadata());
-          f(cichk->holder_klass());
+          f->do_metadata(cichk->holder_metadata());
+          f->do_metadata(cichk->holder_klass());
         } else {
           // Get Klass* or NULL (if value is -1) from GOT cell of virtual call PLT stub.
           Metadata* ic_oop = ic->cached_metadata();
           if (ic_oop != NULL) {
-            f(ic_oop);
+            f->do_metadata(ic_oop);
           }
         }
       } else if (iter.type() == relocInfo::static_call_type ||
@@ -284,7 +284,7 @@
         // Check Method* in AOT c2i stub for other calls.
         Metadata* meta = (Metadata*)nativeLoadGot_at(nativePltCall_at(iter.addr())->plt_c2i_stub())->data();
         if (meta != NULL) {
-          f(meta);
+          f->do_metadata(meta);
         }
       }
     }
@@ -302,11 +302,11 @@
       continue;
     }
     assert(Metaspace::contains(m), "");
-    f(m);
+    f->do_metadata(m);
   }
 
   // Visit metadata not embedded in the other places.
-  if (_method != NULL) f(_method);
+  if (_method != NULL) f->do_metadata(_method);
 }
 
 void AOTCompiledMethod::print() const {
--- a/src/hotspot/share/aot/aotCompiledMethod.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/aot/aotCompiledMethod.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -241,7 +241,7 @@
   address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); }
   void    set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; }
 
-  virtual void metadata_do(void f(Metadata*));
+  virtual void metadata_do(MetadataClosure* f);
 
   bool metadata_got_contains(Metadata **p) {
     return p >= &_metadata_got[0] && p < &_metadata_got[_metadata_size];
--- a/src/hotspot/share/aot/aotLoader.cpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/aot/aotLoader.cpp	Fri Mar 15 16:00:18 2019 -0400
@@ -78,7 +78,7 @@
   }
 }
 
-void AOTLoader::metadata_do(void f(Metadata*)) {
+void AOTLoader::metadata_do(MetadataClosure* f) {
   if (UseAOT) {
     FOR_ALL_AOT_HEAPS(heap) {
       (*heap)->metadata_do(f);
--- a/src/hotspot/share/aot/aotLoader.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/aot/aotLoader.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -62,7 +62,7 @@
   static void load_for_klass(InstanceKlass* ik, Thread* thread) NOT_AOT_RETURN;
   static uint64_t get_saved_fingerprint(InstanceKlass* ik) NOT_AOT({ return 0; });
   static void oops_do(OopClosure* f) NOT_AOT_RETURN;
-  static void metadata_do(void f(Metadata*)) NOT_AOT_RETURN;
+  static void metadata_do(MetadataClosure* f) NOT_AOT_RETURN;
   static void mark_evol_dependent_methods(InstanceKlass* dependee) NOT_AOT_RETURN;
 
   NOT_PRODUCT( static void print_statistics() NOT_AOT_RETURN; )
--- a/src/hotspot/share/ci/ciEnv.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/ci/ciEnv.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -465,7 +465,7 @@
   void record_out_of_memory_failure();
 
   // RedefineClasses support
-  void metadata_do(void f(Metadata*)) { _factory->metadata_do(f); }
+  void metadata_do(MetadataClosure* f) { _factory->metadata_do(f); }
 
   // Dump the compilation replay data for the ciEnv to the stream.
   void dump_replay_data(int compile_id);
--- a/src/hotspot/share/ci/ciObjectFactory.cpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/ci/ciObjectFactory.cpp	Fri Mar 15 16:00:18 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -689,11 +689,11 @@
 
 // ------------------------------------------------------------------
 // ciObjectFactory::metadata_do
-void ciObjectFactory::metadata_do(void f(Metadata*)) {
+void ciObjectFactory::metadata_do(MetadataClosure* f) {
   if (_ci_metadata == NULL) return;
   for (int j = 0; j< _ci_metadata->length(); j++) {
     Metadata* o = _ci_metadata->at(j)->constant_encoding();
-    f(o);
+    f->do_metadata(o);
   }
 }
 
--- a/src/hotspot/share/ci/ciObjectFactory.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/ci/ciObjectFactory.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -140,7 +140,7 @@
 
   GrowableArray<ciMetadata*>* get_ci_metadata() const { return _ci_metadata; }
   // RedefineClasses support
-  void metadata_do(void f(Metadata*));
+  void metadata_do(MetadataClosure* f);
 
   void print_contents();
   void print();
--- a/src/hotspot/share/classfile/metadataOnStackMark.cpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/classfile/metadataOnStackMark.cpp	Fri Mar 15 16:00:18 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,6 +42,10 @@
 MetadataOnStackBuffer* MetadataOnStackMark::_current_buffer = NULL;
 NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;)
 
+class MetadataOnStackClosure : public MetadataClosure {
+  void do_metadata(Metadata* m) { Metadata::mark_on_stack(m); }
+};
+
 // Walk metadata on the stack and mark it so that redefinition doesn't delete
 // it.  Class unloading only deletes in-error class files, methods created by
 // the relocator and dummy constant pools.  None of these appear anywhere except
@@ -55,8 +59,9 @@
   Threads::metadata_handles_do(Metadata::mark_on_stack);
 
   if (redefinition_walk) {
-    Threads::metadata_do(Metadata::mark_on_stack);
-    CodeCache::metadata_do(Metadata::mark_on_stack);
+    MetadataOnStackClosure md_on_stack;
+    Threads::metadata_do(&md_on_stack);
+    CodeCache::metadata_do(&md_on_stack);
     CompileBroker::mark_on_stack();
     JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack);
     ThreadService::metadata_do(Metadata::mark_on_stack);
--- a/src/hotspot/share/code/codeCache.cpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/code/codeCache.cpp	Fri Mar 15 16:00:18 2019 -0400
@@ -667,7 +667,7 @@
   }
 }
 
-void CodeCache::metadata_do(void f(Metadata* m)) {
+void CodeCache::metadata_do(MetadataClosure* f) {
   assert_locked_or_safepoint(CodeCache_lock);
   NMethodIterator iter(NMethodIterator::only_alive_and_not_unloading);
   while(iter.next()) {
@@ -1061,13 +1061,14 @@
       // ...Already marked in the previous pass; count it here.
       // Also counts AOT compiled methods, already marked.
       number_of_marked_CodeBlobs++;
-    } else if (nm->is_evol_dependent()) {
+    } else if (nm->has_evol_metadata()) {
       ResourceMark rm;
       nm->mark_for_deoptimization();
       number_of_marked_CodeBlobs++;
-    } else  {
-      // flush caches in case they refer to a redefined Method*
-      nm->clear_inline_caches();
+    } else {
+      // Inline caches that refer to an nmethod are deoptimized already, because
+      // the Method* is walked in the metadata section of the nmethod.
+      assert(!nm->is_evol_dependent(), "should no longer be necessary");
     }
   }
 
--- a/src/hotspot/share/code/codeCache.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/code/codeCache.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -147,7 +147,7 @@
   static void blobs_do(void f(CodeBlob* cb));              // iterates over all CodeBlobs
   static void blobs_do(CodeBlobClosure* f);                // iterates over all CodeBlobs
   static void nmethods_do(void f(nmethod* nm));            // iterates over all nmethods
-  static void metadata_do(void f(Metadata* m));            // iterates over metadata in alive nmethods
+  static void metadata_do(MetadataClosure* f);             // iterates over metadata in alive nmethods
 
   // Lookup
   static CodeBlob* find_blob(void* start);              // Returns the CodeBlob containing the given address
--- a/src/hotspot/share/code/compiledMethod.cpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/code/compiledMethod.cpp	Fri Mar 15 16:00:18 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -415,20 +415,22 @@
 
 #ifdef ASSERT
 // Check class_loader is alive for this bit of metadata.
-static void check_class(Metadata* md) {
-   Klass* klass = NULL;
-   if (md->is_klass()) {
-     klass = ((Klass*)md);
-   } else if (md->is_method()) {
-     klass = ((Method*)md)->method_holder();
-   } else if (md->is_methodData()) {
-     klass = ((MethodData*)md)->method()->method_holder();
-   } else {
-     md->print();
-     ShouldNotReachHere();
-   }
-   assert(klass->is_loader_alive(), "must be alive");
-}
+class CheckClass : public MetadataClosure {
+  void do_metadata(Metadata* md) {
+    Klass* klass = NULL;
+    if (md->is_klass()) {
+      klass = ((Klass*)md);
+    } else if (md->is_method()) {
+      klass = ((Method*)md)->method_holder();
+    } else if (md->is_methodData()) {
+      klass = ((MethodData*)md)->method()->method_holder();
+    } else {
+      md->print();
+      ShouldNotReachHere();
+    }
+    assert(klass->is_loader_alive(), "must be alive");
+  }
+};
 #endif // ASSERT
 
 
@@ -550,8 +552,11 @@
   // All static stubs need to be cleaned.
   clean_ic_stubs();
 
+#ifdef ASSERT
   // Check that the metadata embedded in the nmethod is alive
-  DEBUG_ONLY(metadata_do(check_class));
+  CheckClass check_class;
+  metadata_do(&check_class);
+#endif
   return true;
 }
 
@@ -628,3 +633,35 @@
          os::is_readable_pointer(method->constants()) &&
          os::is_readable_pointer(method->signature());
 }
+
+class HasEvolDependency : public MetadataClosure {
+  bool _has_evol_dependency;
+ public:
+  HasEvolDependency() : _has_evol_dependency(false) {}
+  void do_metadata(Metadata* md) {
+    if (md->is_method()) {
+      Method* method = (Method*)md;
+      if (method->is_old()) {
+        _has_evol_dependency = true;
+      }
+    }
+  }
+  bool has_evol_dependency() const { return _has_evol_dependency; }
+};
+
+bool CompiledMethod::has_evol_metadata() {
+  // Check the metadata in relocIter and CompiledIC and also deoptimize
+  // any nmethod that has reference to old methods.
+  HasEvolDependency check_evol;
+  metadata_do(&check_evol);
+  if (check_evol.has_evol_dependency() && log_is_enabled(Debug, redefine, class, nmethod)) {
+    ResourceMark rm;
+    log_debug(redefine, class, nmethod)
+            ("Found evol dependency of nmethod %s.%s(%s) compile_id=%d on in nmethod metadata",
+             _method->method_holder()->external_name(),
+             _method->name()->as_C_string(),
+             _method->signature()->as_C_string(),
+             compile_id());
+  }
+  return check_evol.has_evol_dependency();
+}
--- a/src/hotspot/share/code/compiledMethod.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/code/compiledMethod.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -38,6 +38,7 @@
 class NativeCallWrapper;
 class ScopeDesc;
 class CompiledIC;
+class MetadataClosure;
 
 // This class is used internally by nmethods, to cache
 // exception/pc/handler information.
@@ -368,6 +369,8 @@
   void verify_oop_relocations();
 
   virtual bool is_evol_dependent() = 0;
+  bool has_evol_metadata();
+
   // Fast breakpoint support. Tells if this compiled method is
   // dependent on the given method. Returns true if this nmethod
   // corresponds to the given method as well.
@@ -384,7 +387,7 @@
   Method* attached_method(address call_pc);
   Method* attached_method_before_pc(address pc);
 
-  virtual void metadata_do(void f(Metadata*)) = 0;
+  virtual void metadata_do(MetadataClosure* f) = 0;
 
   // GC support
  protected:
--- a/src/hotspot/share/code/nmethod.cpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/code/nmethod.cpp	Fri Mar 15 16:00:18 2019 -0400
@@ -1499,7 +1499,7 @@
 }
 
 // Iterate over metadata calling this function.   Used by RedefineClasses
-void nmethod::metadata_do(void f(Metadata*)) {
+void nmethod::metadata_do(MetadataClosure* f) {
   {
     // Visit all immediate references that are embedded in the instruction stream.
     RelocIterator iter(this, oops_reloc_begin());
@@ -1514,7 +1514,7 @@
                "metadata must be found in exactly one place");
         if (r->metadata_is_immediate() && r->metadata_value() != NULL) {
           Metadata* md = r->metadata_value();
-          if (md != _method) f(md);
+          if (md != _method) f->do_metadata(md);
         }
       } else if (iter.type() == relocInfo::virtual_call_type) {
         // Check compiledIC holders associated with this nmethod
@@ -1522,12 +1522,12 @@
         CompiledIC *ic = CompiledIC_at(&iter);
         if (ic->is_icholder_call()) {
           CompiledICHolder* cichk = ic->cached_icholder();
-          f(cichk->holder_metadata());
-          f(cichk->holder_klass());
+          f->do_metadata(cichk->holder_metadata());
+          f->do_metadata(cichk->holder_klass());
         } else {
           Metadata* ic_oop = ic->cached_metadata();
           if (ic_oop != NULL) {
-            f(ic_oop);
+            f->do_metadata(ic_oop);
           }
         }
       }
@@ -1538,11 +1538,11 @@
   for (Metadata** p = metadata_begin(); p < metadata_end(); p++) {
     if (*p == Universe::non_oop_word() || *p == NULL)  continue;  // skip non-oops
     Metadata* md = *p;
-    f(md);
+    f->do_metadata(md);
   }
 
   // Visit metadata not embedded in the other places.
-  if (_method != NULL) f(_method);
+  if (_method != NULL) f->do_metadata(_method);
 }
 
 // The _is_unloading_state encodes a tuple comprising the unloading cycle
--- a/src/hotspot/share/code/nmethod.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/code/nmethod.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -591,7 +591,7 @@
   static int osr_entry_point_offset()             { return offset_of(nmethod, _osr_entry_point); }
   static int state_offset()                       { return offset_of(nmethod, _state); }
 
-  virtual void metadata_do(void f(Metadata*));
+  virtual void metadata_do(MetadataClosure* f);
 
   NativeCallWrapper* call_wrapper_at(address call) const;
   NativeCallWrapper* call_wrapper_before(address return_pc) const;
--- a/src/hotspot/share/compiler/compileTask.cpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/compiler/compileTask.cpp	Fri Mar 15 16:00:18 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -197,13 +197,13 @@
 }
 
 // RedefineClasses support
-void CompileTask::metadata_do(void f(Metadata*)) {
+void CompileTask::metadata_do(MetadataClosure* f) {
   if (is_unloaded()) {
     return;
   }
-  f(method());
+  f->do_metadata(method());
   if (hot_method() != NULL && hot_method() != method()) {
-    f(hot_method());
+    f->do_metadata(hot_method());
   }
 }
 
--- a/src/hotspot/share/compiler/compileTask.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/compiler/compileTask.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -177,7 +177,7 @@
   bool         is_unloaded() const;
 
   // RedefineClasses support
-  void         metadata_do(void f(Metadata*));
+  void         metadata_do(MetadataClosure* f);
   void         mark_on_stack();
 
 private:
--- a/src/hotspot/share/memory/iterator.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/memory/iterator.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -36,6 +36,7 @@
 class KlassClosure;
 class ClassLoaderData;
 class Symbol;
+class Metadata;
 
 // The following classes are C++ `closures` for iterating over objects, roots and spaces
 
@@ -124,6 +125,11 @@
   virtual void do_cld(ClassLoaderData* cld) = 0;
 };
 
+class MetadataClosure : public Closure {
+ public:
+  virtual void do_metadata(Metadata* md) = 0;
+};
+
 
 class CLDToOopClosure : public CLDClosure {
   OopClosure*       _oop_closure;
--- a/src/hotspot/share/runtime/frame.cpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/runtime/frame.cpp	Fri Mar 15 16:00:18 2019 -0400
@@ -1115,13 +1115,13 @@
 }
 
 
-// call f() on the interpreted Method*s in the stack.
-// Have to walk the entire code cache for the compiled frames Yuck.
-void frame::metadata_do(void f(Metadata*)) {
+// Call f closure on the interpreted Method*s in the stack.
+void frame::metadata_do(MetadataClosure* f) {
+  ResourceMark rm;
   if (is_interpreted_frame()) {
     Method* m = this->interpreter_frame_method();
     assert(m != NULL, "expecting a method in this frame");
-    f(m);
+    f->do_metadata(m);
   }
 }
 
--- a/src/hotspot/share/runtime/frame.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/runtime/frame.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -378,7 +378,7 @@
   void nmethods_do(CodeBlobClosure* cf);
 
   // RedefineClasses support for finding live interpreted methods on the stack
-  void metadata_do(void f(Metadata*));
+  void metadata_do(MetadataClosure* f);
 
   // Verification
   void verify(const RegisterMap* map);
--- a/src/hotspot/share/runtime/thread.cpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/runtime/thread.cpp	Fri Mar 15 16:00:18 2019 -0400
@@ -2960,7 +2960,7 @@
   }
 }
 
-void JavaThread::metadata_do(void f(Metadata*)) {
+void JavaThread::metadata_do(MetadataClosure* f) {
   if (has_last_Java_frame()) {
     // Traverse the execution stack to call f() on the methods in the stack
     for (StackFrameStream fst(this); !fst.is_done(); fst.next()) {
@@ -4574,7 +4574,7 @@
   }
 }
 
-void Threads::metadata_do(void f(Metadata*)) {
+void Threads::metadata_do(MetadataClosure* f) {
   ALL_JAVA_THREADS(p) {
     p->metadata_do(f);
   }
--- a/src/hotspot/share/runtime/thread.hpp	Fri Mar 15 18:59:21 2019 +0100
+++ b/src/hotspot/share/runtime/thread.hpp	Fri Mar 15 16:00:18 2019 -0400
@@ -1866,7 +1866,7 @@
   virtual void nmethods_do(CodeBlobClosure* cf);
 
   // RedefineClasses Support
-  void metadata_do(void f(Metadata*));
+  void metadata_do(MetadataClosure* f);
 
   // Misc. operations
   char* name() const { return (char*)get_thread_name(); }
@@ -2281,7 +2281,7 @@
   static void nmethods_do(CodeBlobClosure* cf);
 
   // RedefineClasses support
-  static void metadata_do(void f(Metadata*));
+  static void metadata_do(MetadataClosure* f);
   static void metadata_handles_do(void f(Metadata*));
 
 #ifdef ASSERT