The implementation of java.lang.invoke uses SoftReferences so that unused MethodHandles, LambdaForms, etc, can be garbage collected.
However, if we want to store java.lang.invoke objects in the CDS archive (e.g., JDK-8293336), it's difficult to cache these SoftReferences. SoftReferences in turn point to ReferenceQueues, etc, which have dependencies on the current execution state (Threads, etc) which are difficult to cache.
The proposal is to add a new flag: MethodHandleStatics.NO_SOFT_CACHE. When this flag is true, we avoid using SoftReferences, and store a direct reference to the target object instead.
JDK-8293336 stores only java.lang.invoke objects that refer to classes loaded by the boot/platform/app loaders. These classes are never unloaded, so it's not necessary to point to them using SoftReferences.
This RFE modifies only the LambdaFormEditor and MethodTypeForm classes, as that's the minimal modification required by JDK-8293336.
(See comments below to alternatives)
Example: src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java
Before:
final SoftReference<MethodHandle>[] methodHandles;
public MethodHandle cachedMethodHandle(int which) {
SoftReference<MethodHandle> entry = methodHandles[which];
return (entry != null) ? entry.get() : null;
}
public synchronized MethodHandle setCachedMethodHandle(int which, MethodHandle mh) {
// Simulate a CAS, to avoid racy duplication of results.
SoftReference<MethodHandle> entry = methodHandles[which];
if (entry != null) {
MethodHandle prev = entry.get();
if (prev != null) {
return prev;
}
}
methodHandles[which] = new SoftReference<>(mh);
return mh;
}
After:
private final Object[] methodHandles;
@SuppressWarnings({"rawtypes", "unchecked"})
public MethodHandle cachedMethodHandle(int which) {
Object entry = methodHandles[which];
if (entry == null) {
return null;
} else if (entry instanceof MethodHandle) {
return (MethodHandle) entry;
} else {
return ((SoftReference<MethodHandle>)entry).get();
}
}
public synchronized MethodHandle setCachedMethodHandle(int which, MethodHandle mh) {
// Simulate a CAS, to avoid racy duplication of results.
MethodHandle prev = cachedMethodHandle(which);
if (prev != null) {
return prev;
}
if (NO_SOFT_CACHE) {
methodHandles[which] = mh;
} else {
methodHandles[which] = new SoftReference<>(mh);
}
return mh;
}
==============
NOTE: this is a short term solution so we can start archiving java.lang.invoke objects. At this point, we are willing to accept a few unwanted objects that might have otherwise been garbage collected during CDS dump time.
A more general solution is proposed in JDK-8311078