8338007: [JVMCI] ResolvedJavaMethod.reprofile can crash ciMethodData

Reviewed-by: dnsimon, kvn
This commit is contained in:
Tom Rodriguez 2024-11-12 15:52:30 +00:00
parent 81752c4bcc
commit c12b386d19
4 changed files with 43 additions and 6 deletions

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -114,7 +114,8 @@
template(GTestStopSafepoint) \
template(JFROldObject) \
template(JvmtiPostObjectFree) \
template(RendezvousGCThreads)
template(RendezvousGCThreads) \
template(ReinitializeMDO)
class Thread;
class outputStream;