我试图在Java中将一个类作为隐藏类加载,但遇到了VerifyError.这个类使用一个VarHandle,它有一个PolymorphicSignature
.我认为这个错误暗示着多态调用正在使用非隐藏类,但我不清楚该如何修复它.定义包含对方法句柄或VarHandles调用的隐藏类的正确方式是什么?
package foo;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.IntUnaryOperator;
import org.junit.jupiter.api.Test;
public class HiddenClassTest {
@Test
public void loadHidden() throws Exception {
MethodHandles.Lookup lookup;
try (var is = IntThing.class.getResourceAsStream("HiddenClassTest$IntThing.class")) {
lookup =
MethodHandles.lookup().defineHiddenClass(is.readAllBytes(), true);
}
var instance =
lookup.lookupClass()
.asSubclass(IntUnaryOperator.class)
.getConstructor()
.newInstance();
System.out.println(instance.applyAsInt(12));
System.out.println(instance.applyAsInt(24));
}
static final class IntThing implements IntUnaryOperator {
static final VarHandle IDX;
static {
try {
IDX = MethodHandles.lookup().findVarHandle(IntThing.class, "idx", int.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private int idx;
@Override
public int applyAsInt(int newIdx) {
int oldIdx = (int) IDX.getOpaque(this);
IDX.setOpaque(this, newIdx);
return oldIdx;
}
}
}
错误:
Bad type on operand stack
Exception Details:
Location:
foo/HiddenClassTest$IntThing+0x0000000800d38c00.applyAsInt(I)I @4: invokevirtual
Reason:
Type 'foo/HiddenClassTest$IntThing+0x0000000800d38c00' (current frame, stack[1]) is not assignable to 'foo/HiddenClassTest$IntThing'
Current Frame:
bci: @4
flags: { }
locals: { 'foo/HiddenClassTest$IntThing+0x0000000800d38c00', integer }
stack: { 'java/lang/invoke/VarHandle', 'foo/HiddenClassTest$IntThing+0x0000000800d38c00' }
Bytecode:
0000000: b200 072a b600 0d3d b200 072a 1bb6 0013
0000010: 1cac
java.lang.VerifyError: Bad type on operand stack
Exception Details:
Location:
foo/HiddenClassTest$IntThing+0x0000000800d38c00.applyAsInt(I)I @4: invokevirtual
Reason:
Type 'foo/HiddenClassTest$IntThing+0x0000000800d38c00' (current frame, stack[1]) is not assignable to 'foo/HiddenClassTest$IntThing'
Current Frame:
bci: @4
flags: { }
locals: { 'foo/HiddenClassTest$IntThing+0x0000000800d38c00', integer }
stack: { 'java/lang/invoke/VarHandle', 'foo/HiddenClassTest$IntThing+0x0000000800d38c00' }
Bytecode:
0000000: b200 072a b600 0d3d b200 072a 1bb6 0013
0000010: 1cac
at java.base/java.lang.ClassLoader.defineClass0(Native Method)
at java.base/java.lang.System$2.defineClass(System.java:2307)
at java.base/java.lang.invoke.MethodHandles$Lookup$ClassDefiner.defineClass(MethodHandles.java:2439)
at java.base/java.lang.invoke.MethodHandles$Lookup$ClassDefiner.defineClassAsLookup(MethodHandles.java:2420)
at java.base/java.lang.invoke.MethodHandles$Lookup.defineHiddenClass(MethodHandles.java:2127)
at foo.HiddenClassTest.loadHidden(HiddenClassTest.java:16)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)