From c12b386d1916af9a04b4c6698838c2b40c6cdd86 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Tue, 12 Nov 2024 15:52:30 +0000 Subject: [PATCH] 8338007: [JVMCI] ResolvedJavaMethod.reprofile can crash ciMethodData Reviewed-by: dnsimon, kvn --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 3 +- src/hotspot/share/oops/methodData.cpp | 33 +++++++++++++++++-- src/hotspot/share/oops/methodData.hpp | 10 +++++- src/hotspot/share/runtime/vmOperation.hpp | 3 +- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 7922a681639..b85d2227fc7 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -1382,7 +1382,8 @@ C2V_VMENTRY(void, reprofile, (JNIEnv* env, jobject, ARGUMENT_PAIR(method))) if (method_data == nullptr) { method_data = get_profiling_method_data(method, CHECK); } else { - method_data->initialize(); + CompilerThreadCanCallJava canCallJava(THREAD, true); + method_data->reinitialize(); } C2V_END diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index af19d59f281..bc2649ba0ed 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -59,9 +59,14 @@ bool DataLayout::needs_array_len(u1 tag) { // Perform generic initialization of the data. More specific // initialization occurs in overrides of ProfileData::post_initialize. void DataLayout::initialize(u1 tag, u2 bci, int cell_count) { - _header._bits = (intptr_t)0; - _header._struct._tag = tag; - _header._struct._bci = bci; + DataLayout temp; + temp._header._bits = (intptr_t)0; + temp._header._struct._tag = tag; + temp._header._struct._bci = bci; + // Write the header using a single intptr_t write. This ensures that if the layout is + // reinitialized readers will never see the transient state where the header is 0. + _header = temp._header; + for (int i = 0; i < cell_count; i++) { set_cell_at(i, (intptr_t)0); } @@ -1224,6 +1229,28 @@ MethodData::MethodData(const methodHandle& method) initialize(); } +// Reinitialize the storage of an existing MDO at a safepoint. Doing it this way will ensure it's +// not being accessed while the contents are being rewritten. +class VM_ReinitializeMDO: public VM_Operation { + private: + MethodData* _mdo; + public: + VM_ReinitializeMDO(MethodData* mdo): _mdo(mdo) {} + VMOp_Type type() const { return VMOp_ReinitializeMDO; } + void doit() { + // The extra data is being zero'd, we'd like to acquire the extra_data_lock but it can't be held + // over a safepoint. This means that we don't actually need to acquire the lock. + _mdo->initialize(); + } + bool allow_nested_vm_operations() const { return true; } +}; + +void MethodData::reinitialize() { + VM_ReinitializeMDO op(this); + VMThread::execute(&op); +} + + void MethodData::initialize() { Thread* thread = Thread::current(); NoSafepointVerifier no_safepoint; // init function atomic wrt GC diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index 5071c29f1d7..36fcf8ce5fd 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -1949,6 +1949,7 @@ class MethodData : public Metadata { friend class ProfileData; friend class TypeEntriesAtCall; friend class ciMethodData; + friend class VM_ReinitializeMDO; // If you add a new field that points to any metaspace object, you // must add this field to MethodData::metaspace_pointers_do(). @@ -1965,11 +1966,18 @@ class MethodData : public Metadata { Mutex _extra_data_lock; MethodData(const methodHandle& method); + + void initialize(); + public: static MethodData* allocate(ClassLoaderData* loader_data, const methodHandle& method, TRAPS); virtual bool is_methodData() const { return true; } - void initialize(); + + // Safely reinitialize the data in the MDO. This is intended as a testing facility as the + // reinitialization is performed at a safepoint so it's isn't cheap and it doesn't ensure that all + // readers will see consistent profile data. + void reinitialize(); // Whole-method sticky bits and flags enum { diff --git a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp index eede52f00d5..50d85944485 100644 --- a/src/hotspot/share/runtime/vmOperation.hpp +++ b/src/hotspot/share/runtime/vmOperation.hpp @@ -114,7 +114,8 @@ template(GTestStopSafepoint) \ template(JFROldObject) \ template(JvmtiPostObjectFree) \ - template(RendezvousGCThreads) + template(RendezvousGCThreads) \ + template(ReinitializeMDO) class Thread; class outputStream;