Quantcast
Viewing latest article 10
Browse Latest Browse All 36

Can't load hidden class with VarHandle

I am trying to load a class as a hidden class in Java, but run into a VerifyError. The class uses a VarHandle, which has a PolymorphicSignature. I believe the error is implying that the polymorphic call is using the non-hidden class, but it's not obvious to me what to do to fix it. What is the correct way to define hidden classes that contain calls to MethodHandles or 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;    }  }}

The error:

Bad type on operand stackException 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 stackException 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)

Viewing latest article 10
Browse Latest Browse All 36

Trending Articles