8291065: Creating a VarHandle for a static field triggers class initialization

Reviewed-by: mchung, psandoz
This commit is contained in:
Chen Liang 2023-07-18 00:58:25 +00:00 committed by Mandy Chung
parent a53345ad03
commit 201e3bcf52
10 changed files with 744 additions and 160 deletions

View file

@ -472,7 +472,8 @@ import static java.lang.invoke.MethodHandleStatics.UNSAFE;
* @since 9
*/
public abstract sealed class VarHandle implements Constable
permits IndirectVarHandle, VarHandleSegmentViewBase,
permits IndirectVarHandle, LazyInitializingVarHandle,
VarHandleSegmentViewBase,
VarHandleByteArrayAsChars.ByteArrayViewVarHandle,
VarHandleByteArrayAsDoubles.ByteArrayViewVarHandle,
VarHandleByteArrayAsFloats.ByteArrayViewVarHandle,
@ -518,10 +519,23 @@ public abstract sealed class VarHandle implements Constable
this.exact = exact;
}
RuntimeException unsupported() {
return new UnsupportedOperationException();
/**
* Returns the target VarHandle. Subclasses may override this method to implement
* additional logic for example lazily initializing the declaring class of a static field var handle.
*/
@ForceInline
VarHandle target() {
return asDirect();
}
/**
* Returns the direct target VarHandle. Indirect VarHandle subclasses should implement
* this method.
*
* @see #getMethodHandle(int)
* @see #checkAccessModeThenIsDirect(AccessDescriptor)
*/
@ForceInline
VarHandle asDirect() {
return this;
}
@ -2062,13 +2076,19 @@ public abstract sealed class VarHandle implements Constable
/**
* Validates that the given access descriptors method type matches up with
* the access mode of this VarHandle, then returns if this is a direct
* method handle. These operations were grouped together to slightly
* the access mode of this VarHandle, then returns if this is direct.
* These operations were grouped together to slightly
* improve efficiency during startup/warmup.
*
* A direct VarHandle's VarForm has implementation MemberNames that can
* be linked directly. If a VarHandle is indirect, it must override
* {@link #isAccessModeSupported} and {@link #getMethodHandleUncached}
* which access MemberNames.
*
* @return true if this is a direct VarHandle, false if it's an indirect
* VarHandle.
* @throws WrongMethodTypeException if there's an access type mismatch
* @see #asDirect()
*/
@ForceInline
boolean checkAccessModeThenIsDirect(VarHandle.AccessDescriptor ad) {
@ -2144,7 +2164,7 @@ public abstract sealed class VarHandle implements Constable
public MethodHandle toMethodHandle(AccessMode accessMode) {
if (isAccessModeSupported(accessMode)) {
MethodHandle mh = getMethodHandle(accessMode.ordinal());
return mh.bindTo(this);
return mh.bindTo(asDirect());
}
else {
// Ensure an UnsupportedOperationException is thrown
@ -2186,6 +2206,14 @@ public abstract sealed class VarHandle implements Constable
return mh;
}
/**
* Computes a method handle that can be passed the {@linkplain #asDirect() direct}
* var handle of this var handle with the given access mode. Pre/postprocessing
* such as argument or return value filtering should be done by the returned
* method handle.
*
* @throws UnsupportedOperationException if the access mode is not supported
*/
MethodHandle getMethodHandleUncached(int mode) {
MethodType mt = accessModeType(AccessMode.values()[mode]).
insertParameterTypes(0, VarHandle.class);
@ -2401,13 +2429,13 @@ public abstract sealed class VarHandle implements Constable
public VarHandle resolveConstantDesc(MethodHandles.Lookup lookup)
throws ReflectiveOperationException {
return switch (kind) {
case FIELD -> lookup.findVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
case FIELD -> lookup.findVarHandle(declaringClass.resolveConstantDesc(lookup),
constantName(),
(Class<?>) varType.resolveConstantDesc(lookup));
case STATIC_FIELD -> lookup.findStaticVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
varType.resolveConstantDesc(lookup));
case STATIC_FIELD -> lookup.findStaticVarHandle(declaringClass.resolveConstantDesc(lookup),
constantName(),
(Class<?>) varType.resolveConstantDesc(lookup));
case ARRAY -> MethodHandles.arrayElementVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup));
varType.resolveConstantDesc(lookup));
case ARRAY -> MethodHandles.arrayElementVarHandle(declaringClass.resolveConstantDesc(lookup));
default -> throw new InternalError("Cannot reach here");
};
}