changeset 57264:31ec3e55fa3d

8230400: Missing constant pool entry for a method in stacktrace Reviewed-by: egahlin
author mgronlun
date Tue, 29 Oct 2019 11:33:25 +0100
parents b026a43e1809
children 6c255334120d
files src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java
diffstat 6 files changed, 106 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp	Tue Oct 29 09:34:23 2019 +0800
+++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp	Tue Oct 29 11:33:25 2019 +0100
@@ -1497,35 +1497,6 @@
   ik = new_ik;
 }
 
-// During retransform/redefine, copy the Method specific trace flags
-// from the previous ik ("the original klass") to the new ik ("the scratch_klass").
-// The open code for retransform/redefine does not know about these.
-// In doing this migration here, we ensure the new Methods (defined in scratch klass)
-// will carry over trace tags from the old Methods being replaced,
-// ensuring flag/tag continuity while being transparent to open code.
-static void copy_method_trace_flags(const InstanceKlass* the_original_klass, const InstanceKlass* the_scratch_klass) {
-  assert(the_original_klass != NULL, "invariant");
-  assert(the_scratch_klass != NULL, "invariant");
-  assert(the_original_klass->name() == the_scratch_klass->name(), "invariant");
-  const Array<Method*>* old_methods = the_original_klass->methods();
-  const Array<Method*>* new_methods = the_scratch_klass->methods();
-  const bool equal_array_length = old_methods->length() == new_methods->length();
-  // The Method array has the property of being sorted.
-  // If they are the same length, there is a one-to-one mapping.
-  // If they are unequal, there was a method added (currently only
-  // private static methods allowed to be added), use lookup.
-  for (int i = 0; i < old_methods->length(); ++i) {
-    const Method* const old_method = old_methods->at(i);
-    Method* const new_method = equal_array_length ? new_methods->at(i) :
-      the_scratch_klass->find_method(old_method->name(), old_method->signature());
-    assert(new_method != NULL, "invariant");
-    assert(new_method->name() == old_method->name(), "invariant");
-    assert(new_method->signature() == old_method->signature(), "invariant");
-    new_method->set_trace_flags(old_method->trace_flags());
-    assert(new_method->trace_flags() == old_method->trace_flags(), "invariant");
-  }
-}
-
 static bool is_retransforming(const InstanceKlass* ik, TRAPS) {
   assert(ik != NULL, "invariant");
   assert(JdkJfrEvent::is_a(ik), "invariant");
@@ -1533,16 +1504,7 @@
   assert(name != NULL, "invariant");
   Handle class_loader(THREAD, ik->class_loader());
   Handle protection_domain(THREAD, ik->protection_domain());
-  // nota bene: use lock-free dictionary lookup
-  const InstanceKlass* prev_ik = (const InstanceKlass*)SystemDictionary::find(name, class_loader, protection_domain, THREAD);
-  if (prev_ik == NULL) {
-    return false;
-  }
-  // an existing ik implies a retransform/redefine
-  assert(prev_ik != NULL, "invariant");
-  assert(JdkJfrEvent::is_a(prev_ik), "invariant");
-  copy_method_trace_flags(prev_ik, ik);
-  return true;
+  return SystemDictionary::find(name, class_loader, protection_domain, THREAD) != NULL;
 }
 
 // target for JFR_ON_KLASS_CREATION hook
@@ -1571,12 +1533,8 @@
     return;
   }
   assert(JdkJfrEvent::is_subklass(ik), "invariant");
-  if (is_retransforming(ik, THREAD)) {
-    // not the initial klass load
-    return;
-  }
-  if (ik->is_abstract()) {
-    // abstract classes are not instrumented
+  if (ik->is_abstract() || is_retransforming(ik, THREAD)) {
+    // abstract and scratch classes are not instrumented
     return;
   }
   ResourceMark rm(THREAD);
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp	Tue Oct 29 09:34:23 2019 +0800
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp	Tue Oct 29 11:33:25 2019 +0100
@@ -364,13 +364,13 @@
   if (!LeakProfiler::is_running()) {
     JfrCheckpointWriter writer(true, true, Thread::current());
     JfrTypeSet::serialize(&writer, NULL, false);
-    return;
+  } else {
+    Thread* const t = Thread::current();
+    JfrCheckpointWriter leakp_writer(false, true, t);
+    JfrCheckpointWriter writer(false, true, t);
+    JfrTypeSet::serialize(&writer, &leakp_writer, false);
+    ObjectSampleCheckpoint::on_type_set(leakp_writer);
   }
-  Thread* const t = Thread::current();
-  JfrCheckpointWriter leakp_writer(false, true, t);
-  JfrCheckpointWriter writer(false, true, t);
-  JfrTypeSet::serialize(&writer, &leakp_writer, false);
-  ObjectSampleCheckpoint::on_type_set(leakp_writer);
 }
 
 void JfrCheckpointManager::write_type_set_for_unloaded_classes() {
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp	Tue Oct 29 09:34:23 2019 +0800
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp	Tue Oct 29 11:33:25 2019 +0100
@@ -43,6 +43,7 @@
 #include "oops/objArrayKlass.hpp"
 #include "oops/oop.inline.hpp"
 #include "utilities/accessFlags.hpp"
+#include "utilities/bitMap.inline.hpp"
 
 typedef const Klass* KlassPtr;
 typedef const PackageEntry* PkgPtr;
@@ -117,7 +118,7 @@
 static traceid module_id(PkgPtr pkg, bool leakp) {
   assert(pkg != NULL, "invariant");
   ModPtr module_entry = pkg->module();
-  if (module_entry == NULL || !module_entry->is_named()) {
+  if (module_entry == NULL) {
     return 0;
   }
   if (leakp) {
@@ -136,9 +137,7 @@
 
 static traceid cld_id(CldPtr cld, bool leakp) {
   assert(cld != NULL, "invariant");
-  if (cld->is_unsafe_anonymous()) {
-    return 0;
-  }
+  assert(!cld->is_unsafe_anonymous(), "invariant");
   if (leakp) {
     SET_LEAKP(cld);
   } else {
@@ -153,6 +152,17 @@
   return ptr->access_flags().get_flags();
 }
 
+static bool is_unsafe_anonymous(const Klass* klass) {
+  assert(klass != NULL, "invariant");
+  return klass->is_instance_klass() && ((const InstanceKlass*)klass)->is_unsafe_anonymous();
+}
+
+static ClassLoaderData* get_cld(const Klass* klass) {
+  assert(klass != NULL, "invariant");
+  return is_unsafe_anonymous(klass) ?
+    InstanceKlass::cast(klass)->unsafe_anonymous_host()->class_loader_data() : klass->class_loader_data();
+}
+
 template <typename T>
 static void set_serialized(const T* ptr) {
   assert(ptr != NULL, "invariant");
@@ -184,7 +194,7 @@
     assert(theklass->is_typeArray_klass(), "invariant");
   }
   writer->write(artifact_id(klass));
-  writer->write(cld_id(klass->class_loader_data(), leakp));
+  writer->write(cld_id(get_cld(klass), leakp));
   writer->write(mark_symbol(klass, leakp));
   writer->write(pkg_id);
   writer->write(get_flags(klass));
@@ -538,13 +548,22 @@
   do_previous_epoch_artifact(_subsystem_callback, cld);
 }
 
-class CldFieldSelector {
+class KlassCldFieldSelector {
  public:
   typedef CldPtr TypePtr;
   static TypePtr select(KlassPtr klass) {
     assert(klass != NULL, "invariant");
-    CldPtr cld = klass->class_loader_data();
-    return cld->is_unsafe_anonymous() ? NULL : cld;
+    return get_cld(klass);
+  }
+};
+
+class ModuleCldFieldSelector {
+public:
+  typedef CldPtr TypePtr;
+  static TypePtr select(KlassPtr klass) {
+    assert(klass != NULL, "invariant");
+    ModPtr mod = ModuleFieldSelector::select(klass);
+    return mod != NULL ? mod->loader_data() : NULL;
   }
 };
 
@@ -570,14 +589,18 @@
 typedef JfrTypeWriterHost<CldWriterImpl, TYPE_CLASSLOADER> CldWriter;
 typedef CompositeFunctor<CldPtr, CldWriter, ClearArtifact<CldPtr> > CldWriterWithClear;
 typedef JfrArtifactCallbackHost<CldPtr, CldWriterWithClear> CldCallback;
-typedef KlassToFieldEnvelope<CldFieldSelector, CldWriter> KlassCldWriter;
+typedef KlassToFieldEnvelope<KlassCldFieldSelector, CldWriter> KlassCldWriter;
+typedef KlassToFieldEnvelope<ModuleCldFieldSelector, CldWriter> ModuleCldWriter;
+typedef CompositeFunctor<KlassPtr, KlassCldWriter, ModuleCldWriter> KlassAndModuleCldWriter;
 
 typedef LeakPredicate<CldPtr> LeakCldPredicate;
 typedef JfrPredicatedTypeWriterImplHost<CldPtr, LeakCldPredicate, write__classloader__leakp> LeakCldWriterImpl;
 typedef JfrTypeWriterHost<LeakCldWriterImpl, TYPE_CLASSLOADER> LeakCldWriter;
 
 typedef CompositeFunctor<CldPtr, LeakCldWriter, CldWriter> CompositeCldWriter;
-typedef KlassToFieldEnvelope<CldFieldSelector, CompositeCldWriter> KlassCompositeCldWriter;
+typedef KlassToFieldEnvelope<KlassCldFieldSelector, CompositeCldWriter> KlassCompositeCldWriter;
+typedef KlassToFieldEnvelope<ModuleCldFieldSelector, CompositeCldWriter> ModuleCompositeCldWriter;
+typedef CompositeFunctor<KlassPtr, KlassCompositeCldWriter, ModuleCompositeCldWriter> KlassAndModuleCompositeCldWriter;
 typedef CompositeFunctor<CldPtr, CompositeCldWriter, ClearArtifact<CldPtr> > CompositeCldWriterWithClear;
 typedef JfrArtifactCallbackHost<CldPtr, CompositeCldWriterWithClear> CompositeCldCallback;
 
@@ -585,14 +608,16 @@
   assert(_writer != NULL, "invariant");
   CldWriter cldw(_writer, _class_unload);
   KlassCldWriter kcw(&cldw);
+  ModuleCldWriter mcw(&cldw);
+  KlassAndModuleCldWriter kmcw(&kcw, &mcw);
   if (current_epoch()) {
-    _artifacts->iterate_klasses(kcw);
+    _artifacts->iterate_klasses(kmcw);
     _artifacts->tally(cldw);
     return;
   }
   assert(previous_epoch(), "invariant");
   if (_leakp_writer == NULL) {
-    _artifacts->iterate_klasses(kcw);
+    _artifacts->iterate_klasses(kmcw);
     ClearArtifact<CldPtr> clear;
     CldWriterWithClear cldwwc(&cldw, &clear);
     CldCallback callback(&cldwwc);
@@ -602,7 +627,9 @@
     LeakCldWriter lcldw(_leakp_writer, _class_unload);
     CompositeCldWriter ccldw(&lcldw, &cldw);
     KlassCompositeCldWriter kccldw(&ccldw);
-    _artifacts->iterate_klasses(kccldw);
+    ModuleCompositeCldWriter mccldw(&ccldw);
+    KlassAndModuleCompositeCldWriter kmccldw(&kccldw, &mccldw);
+    _artifacts->iterate_klasses(kmccldw);
     ClearArtifact<CldPtr> clear;
     CompositeCldWriterWithClear ccldwwc(&ccldw, &clear);
     CompositeCldCallback callback(&ccldwwc);
@@ -652,7 +679,31 @@
   return write_method(writer, method, true);
 }
 
-template <typename MethodCallback, typename KlassCallback, bool leakp>
+class BitMapFilter {
+  ResourceBitMap _bitmap;
+ public:
+  explicit BitMapFilter(int length = 0) : _bitmap((size_t)length) {}
+  bool operator()(size_t idx) {
+    if (_bitmap.size() == 0) {
+      return true;
+    }
+    if (_bitmap.at(idx)) {
+      return false;
+    }
+    _bitmap.set_bit(idx);
+    return true;
+  }
+};
+
+class AlwaysTrue {
+ public:
+  explicit AlwaysTrue(int length = 0) {}
+  bool operator()(size_t idx) {
+    return true;
+  }
+};
+
+template <typename MethodCallback, typename KlassCallback, class Filter, bool leakp>
 class MethodIteratorHost {
  private:
   MethodCallback _method_cb;
@@ -671,13 +722,19 @@
 
   bool operator()(KlassPtr klass) {
     if (_method_used_predicate(klass)) {
-      const InstanceKlass* const ik = InstanceKlass::cast(klass);
+      const InstanceKlass* ik = InstanceKlass::cast(klass);
       const int len = ik->methods()->length();
-      for (int i = 0; i < len; ++i) {
-        MethodPtr method = ik->methods()->at(i);
-        if (_method_flag_predicate(method)) {
-          _method_cb(method);
+      Filter filter(ik->previous_versions() != NULL ? len : 0);
+      while (ik != NULL) {
+        for (int i = 0; i < len; ++i) {
+          MethodPtr method = ik->methods()->at(i);
+          if (_method_flag_predicate(method) && filter(i)) {
+            _method_cb(method);
+          }
         }
+        // There can be multiple versions of the same method running
+        // due to redefinition. Need to inspect the complete set of methods.
+        ik = ik->previous_versions();
       }
     }
     return _klass_cb(klass);
@@ -697,16 +754,23 @@
   }
 };
 
+template <typename T>
+class EmptyStub {
+ public:
+  bool operator()(T const& value) { return true; }
+};
+
 typedef SerializePredicate<MethodPtr> MethodPredicate;
 typedef JfrPredicatedTypeWriterImplHost<MethodPtr, MethodPredicate, write__method> MethodWriterImplTarget;
-typedef Wrapper<KlassPtr, Stub> KlassCallbackStub;
+typedef Wrapper<KlassPtr, EmptyStub> KlassCallbackStub;
 typedef JfrTypeWriterHost<MethodWriterImplTarget, TYPE_METHOD> MethodWriterImpl;
-typedef MethodIteratorHost<MethodWriterImpl, KlassCallbackStub, false> MethodWriter;
+typedef MethodIteratorHost<MethodWriterImpl, KlassCallbackStub, BitMapFilter, false> MethodWriter;
 
 typedef LeakPredicate<MethodPtr> LeakMethodPredicate;
 typedef JfrPredicatedTypeWriterImplHost<MethodPtr, LeakMethodPredicate, write__method__leakp> LeakMethodWriterImplTarget;
 typedef JfrTypeWriterHost<LeakMethodWriterImplTarget, TYPE_METHOD> LeakMethodWriterImpl;
-typedef MethodIteratorHost<LeakMethodWriterImpl, KlassCallbackStub, true> LeakMethodWriter;
+typedef MethodIteratorHost<LeakMethodWriterImpl, KlassCallbackStub, BitMapFilter, true> LeakMethodWriter;
+typedef MethodIteratorHost<LeakMethodWriterImpl, KlassCallbackStub, BitMapFilter, true> LeakMethodWriter;
 typedef CompositeFunctor<KlassPtr, LeakMethodWriter, MethodWriter> CompositeMethodWriter;
 
 static void write_methods() {
@@ -832,7 +896,7 @@
 
 typedef Wrapper<KlassPtr, ClearArtifact> ClearKlassBits;
 typedef Wrapper<MethodPtr, ClearArtifact> ClearMethodFlag;
-typedef MethodIteratorHost<ClearMethodFlag, ClearKlassBits, false> ClearKlassAndMethods;
+typedef MethodIteratorHost<ClearMethodFlag, ClearKlassBits, AlwaysTrue, false> ClearKlassAndMethods;
 
 static size_t teardown() {
   assert(_artifacts != NULL, "invariant");
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp	Tue Oct 29 09:34:23 2019 +0800
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp	Tue Oct 29 11:33:25 2019 +0100
@@ -99,12 +99,6 @@
 };
 
 template <typename T>
-class Stub {
- public:
-  bool operator()(T const& value) { return true; }
-};
-
-template <typename T>
 class SerializePredicate {
   bool _class_unload;
  public:
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp	Tue Oct 29 09:34:23 2019 +0800
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp	Tue Oct 29 11:33:25 2019 +0100
@@ -38,7 +38,7 @@
 static const int meta_offset = low_offset - 1;
 #endif
 
-inline void set_bits(jbyte bits, jbyte* const dest) {
+inline void set_bits(jbyte bits, jbyte volatile* const dest) {
   assert(dest != NULL, "invariant");
   if (bits != (*dest & bits)) {
     *dest |= bits;
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java	Tue Oct 29 09:34:23 2019 +0800
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java	Tue Oct 29 11:33:25 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -255,20 +255,22 @@
         staleMetadata = true;
     }
 
-    // Lock around setOutput ensures that other threads dosn't
-    // emit event after setOutput and unregister the event class, before a call
+    // Lock around setOutput ensures that other threads don't
+    // emit events after setOutput and unregister the event class, before a call
     // to storeDescriptorInJVM
     synchronized void setOutput(String filename) {
+        if (staleMetadata) {
+            storeDescriptorInJVM();
+        }
         jvm.setOutput(filename);
 
         unregisterUnloaded();
         if (unregistered) {
-            staleMetadata = typeLibrary.clearUnregistered();
+            if (typeLibrary.clearUnregistered()) {
+                storeDescriptorInJVM();
+            }
             unregistered = false;
         }
-        if (staleMetadata) {
-            storeDescriptorInJVM();
-        }
     }
 
     private void unregisterUnloaded() {