Skip to content

Commit b81c9c8

Browse files
committedApr 26, 2023
8306951: [BACKOUT] JDK-8305252 make_method_handle_intrinsic may call java code under a lock
Reviewed-by: dcubed
1 parent 732179c commit b81c9c8

File tree

3 files changed

+30
-57
lines changed

3 files changed

+30
-57
lines changed
 

‎src/hotspot/share/classfile/systemDictionary.cpp

+26-50
Original file line numberDiff line numberDiff line change
@@ -1583,13 +1583,11 @@ void SystemDictionary::methods_do(void f(Method*)) {
15831583
}
15841584

15851585
auto doit = [&] (InvokeMethodKey key, Method* method) {
1586-
if (method != nullptr) {
1587-
f(method);
1588-
}
1586+
f(method);
15891587
};
15901588

15911589
{
1592-
MutexLocker ml(InvokeMethodIntrinsicTable_lock);
1590+
MutexLocker ml(InvokeMethodTable_lock);
15931591
_invoke_method_intrinsic_table.iterate_all(doit);
15941592
}
15951593

@@ -1941,62 +1939,40 @@ Method* SystemDictionary::find_method_handle_intrinsic(vmIntrinsicID iid,
19411939
iid != vmIntrinsics::_invokeGeneric,
19421940
"must be a known MH intrinsic iid=%d: %s", iid_as_int, vmIntrinsics::name_at(iid));
19431941

1944-
InvokeMethodKey key(signature, iid_as_int);
1945-
Method** met = nullptr;
1946-
1947-
// We only want one entry in the table for this (signature/id, method) pair but the code
1948-
// to create the intrinsic method needs to be outside the lock.
1949-
// The first thread claims the entry by adding the key and the other threads wait, until the
1950-
// Method has been added as the value.
19511942
{
1952-
MonitorLocker ml(THREAD, InvokeMethodIntrinsicTable_lock);
1953-
while (met == nullptr) {
1954-
bool created;
1955-
met = _invoke_method_intrinsic_table.put_if_absent(key, &created);
1956-
if (met != nullptr && *met != nullptr) {
1957-
return *met;
1958-
} else if (!created) {
1959-
// Second thread waits for first to actually create the entry and returns
1960-
// it after notify. Loop until method return is non-null.
1961-
ml.wait();
1962-
}
1943+
MutexLocker ml(THREAD, InvokeMethodTable_lock);
1944+
InvokeMethodKey key(signature, iid_as_int);
1945+
Method** met = _invoke_method_intrinsic_table.get(key);
1946+
if (met != nullptr) {
1947+
return *met;
19631948
}
1964-
}
19651949

1966-
methodHandle m = Method::make_method_handle_intrinsic(iid, signature, THREAD);
1967-
bool throw_error = HAS_PENDING_EXCEPTION;
1968-
if (!throw_error && (!Arguments::is_interpreter_only() || iid == vmIntrinsics::_linkToNative)) {
1969-
// Generate a compiled form of the MH intrinsic
1970-
// linkToNative doesn't have interpreter-specific implementation, so always has to go through compiled version.
1971-
AdapterHandlerLibrary::create_native_wrapper(m);
1972-
// Check if have the compiled code.
1973-
throw_error = (!m->has_compiled_code());
1974-
}
1950+
bool throw_error = false;
1951+
// This function could get an OOM but it is safe to call inside of a lock because
1952+
// throwing OutOfMemoryError doesn't call Java code.
1953+
methodHandle m = Method::make_method_handle_intrinsic(iid, signature, CHECK_NULL);
1954+
if (!Arguments::is_interpreter_only() || iid == vmIntrinsics::_linkToNative) {
1955+
// Generate a compiled form of the MH intrinsic
1956+
// linkToNative doesn't have interpreter-specific implementation, so always has to go through compiled version.
1957+
AdapterHandlerLibrary::create_native_wrapper(m);
1958+
// Check if have the compiled code.
1959+
throw_error = (!m->has_compiled_code());
1960+
}
19751961

1976-
{
1977-
MonitorLocker ml(THREAD, InvokeMethodIntrinsicTable_lock);
1978-
if (throw_error) {
1979-
// Remove the entry and let another thread try, or get the same exception.
1980-
bool removed = _invoke_method_intrinsic_table.remove(key);
1981-
assert(removed, "must be the owner");
1982-
ml.notify_all();
1983-
} else {
1962+
if (!throw_error) {
19841963
signature->make_permanent(); // The signature is never unloaded.
1964+
bool created = _invoke_method_intrinsic_table.put(key, m());
1965+
assert(created, "must be since we still hold the lock");
19851966
assert(Arguments::is_interpreter_only() || (m->has_compiled_code() &&
19861967
m->code()->entry_point() == m->from_compiled_entry()),
19871968
"MH intrinsic invariant");
1988-
*met = m(); // insert the element
1989-
ml.notify_all();
19901969
return m();
19911970
}
19921971
}
19931972

1994-
// Throw VirtualMachineError or the pending exception in the JavaThread
1995-
if (throw_error && !HAS_PENDING_EXCEPTION) {
1996-
THROW_MSG_NULL(vmSymbols::java_lang_VirtualMachineError(),
1997-
"Out of space in CodeCache for method handle intrinsic");
1998-
}
1999-
return nullptr;
1973+
// Throw error outside of the lock.
1974+
THROW_MSG_NULL(vmSymbols::java_lang_VirtualMachineError(),
1975+
"Out of space in CodeCache for method handle intrinsic");
20001976
}
20011977

20021978
// Helper for unpacking the return value from linkMethod and linkCallSite.
@@ -2139,7 +2115,7 @@ Handle SystemDictionary::find_method_handle_type(Symbol* signature,
21392115
Handle empty;
21402116
OopHandle* o;
21412117
{
2142-
MutexLocker ml(THREAD, InvokeMethodTypeTable_lock);
2118+
MutexLocker ml(THREAD, InvokeMethodTable_lock);
21432119
o = _invoke_method_type_table.get(signature);
21442120
}
21452121

@@ -2208,7 +2184,7 @@ Handle SystemDictionary::find_method_handle_type(Symbol* signature,
22082184

22092185
if (can_be_cached) {
22102186
// We can cache this MethodType inside the JVM.
2211-
MutexLocker ml(THREAD, InvokeMethodTypeTable_lock);
2187+
MutexLocker ml(THREAD, InvokeMethodTable_lock);
22122188
bool created = false;
22132189
assert(method_type != nullptr, "unexpected null");
22142190
OopHandle* h = _invoke_method_type_table.get(signature);

‎src/hotspot/share/runtime/mutexLocker.cpp

+3-5
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@
3939
Mutex* Patching_lock = nullptr;
4040
Mutex* CompiledMethod_lock = nullptr;
4141
Monitor* SystemDictionary_lock = nullptr;
42-
Mutex* InvokeMethodTypeTable_lock = nullptr;
43-
Monitor* InvokeMethodIntrinsicTable_lock = nullptr;
42+
Mutex* InvokeMethodTable_lock = nullptr;
4443
Mutex* SharedDictionary_lock = nullptr;
4544
Monitor* ClassInitError_lock = nullptr;
4645
Mutex* Module_lock = nullptr;
@@ -255,9 +254,7 @@ void mutex_init() {
255254
}
256255

257256
MUTEX_DEFN(JmethodIdCreation_lock , PaddedMutex , nosafepoint-2); // used for creating jmethodIDs.
258-
MUTEX_DEFN(InvokeMethodTypeTable_lock , PaddedMutex , safepoint);
259-
MUTEX_DEFN(InvokeMethodIntrinsicTable_lock , PaddedMonitor, safepoint);
260-
MUTEX_DEFN(AdapterHandlerLibrary_lock , PaddedMutex , safepoint);
257+
MUTEX_DEFN(InvokeMethodTable_lock , PaddedMutex , safepoint);
261258
MUTEX_DEFN(SharedDictionary_lock , PaddedMutex , safepoint);
262259
MUTEX_DEFN(VMStatistic_lock , PaddedMutex , safepoint);
263260
MUTEX_DEFN(SignatureHandlerLibrary_lock , PaddedMutex , safepoint);
@@ -347,6 +344,7 @@ void mutex_init() {
347344

348345
MUTEX_DEFL(Threads_lock , PaddedMonitor, CompileThread_lock, true);
349346
MUTEX_DEFL(Compile_lock , PaddedMutex , MethodCompileQueue_lock);
347+
MUTEX_DEFL(AdapterHandlerLibrary_lock , PaddedMutex , InvokeMethodTable_lock);
350348
MUTEX_DEFL(Heap_lock , PaddedMonitor, AdapterHandlerLibrary_lock);
351349

352350
MUTEX_DEFL(PerfDataMemAlloc_lock , PaddedMutex , Heap_lock);

‎src/hotspot/share/runtime/mutexLocker.hpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@
3434
extern Mutex* Patching_lock; // a lock used to guard code patching of compiled code
3535
extern Mutex* CompiledMethod_lock; // a lock used to guard a compiled method and OSR queues
3636
extern Monitor* SystemDictionary_lock; // a lock on the system dictionary
37-
extern Mutex* InvokeMethodTypeTable_lock;
38-
extern Monitor* InvokeMethodIntrinsicTable_lock;
37+
extern Mutex* InvokeMethodTable_lock;
3938
extern Mutex* SharedDictionary_lock; // a lock on the CDS shared dictionary
4039
extern Monitor* ClassInitError_lock; // a lock on the class initialization error table
4140
extern Mutex* Module_lock; // a lock on module and package related data structures

0 commit comments

Comments
 (0)
Please sign in to comment.