Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8322510

ClassCastException when using extra boolean parameter in invokedynamic bootstrap

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P4 P4
    • None
    • 8, 11, 17, 21, 22
    • core-libs

      ADDITIONAL SYSTEM INFORMATION :
      Linux / Java 21.0.1

      A DESCRIPTION OF THE PROBLEM :
      When generating bytecode that uses the invokedynamic instruction, if an extra boolean parameter is passed to an invokedynamic bootstrap method, a ClassCastException will result:

      Caused by: java.lang.BootstrapMethodError: bootstrap method initialization exception
      at java.base/java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:188)
      at java.base/java.lang.invoke.CallSite.makeSite(CallSite.java:316)
      at java.base/java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:274)
      at java.base/java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:264)
      at HelloWorld.run(Unknown Source)
      at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
      ... 2 more
      Caused by: java.lang.ClassCastException: Cannot cast java.lang.Integer to java.lang.Boolean
      at java.base/java.lang.Class.cast(Class.java:4067)
      at java.base/sun.invoke.util.ValueConversions.primitiveConversion(ValueConversions.java:252)
      at java.base/sun.invoke.util.ValueConversions.unboxBoolean(ValueConversions.java:108)
      at java.base/java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:109)
      ... 7 more

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the attached source code.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      "Hello, World!" will be printed
      ACTUAL -
      Exception in thread "main" java.lang.reflect.InvocationTargetException
      at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:118)
      at java.base/java.lang.reflect.Method.invoke(Method.java:580)
      at org.robolectric.preinstrumented.InvokeDynamicTest.main(InvokeDynamicTest.java:59)
      Caused by: java.lang.BootstrapMethodError: bootstrap method initialization exception
      at java.base/java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:188)
      at java.base/java.lang.invoke.CallSite.makeSite(CallSite.java:316)
      at java.base/java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:274)
      at java.base/java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:264)
      at HelloWorld.run(Unknown Source)
      at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
      ... 2 more
      Caused by: java.lang.ClassCastException: Cannot cast java.lang.Integer to java.lang.Boolean
      at java.base/java.lang.Class.cast(Class.java:4067)
      at java.base/sun.invoke.util.ValueConversions.primitiveConversion(ValueConversions.java:252)
      at java.base/sun.invoke.util.ValueConversions.unboxBoolean(ValueConversions.java:108)
      at java.base/java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:109)
      ... 7 more

      ---------- BEGIN SOURCE ----------
      package some.package;

      import java.lang.invoke.CallSite;
      import java.lang.invoke.ConstantCallSite;
      import java.lang.invoke.MethodHandle;
      import java.lang.invoke.MethodHandles;
      import java.lang.invoke.MethodType;
      import java.lang.reflect.Method;
      import org.objectweb.asm.ClassWriter;
      import org.objectweb.asm.Handle;
      import org.objectweb.asm.Opcodes;
      import org.objectweb.asm.Type;
      import org.objectweb.asm.tree.ClassNode;
      import org.objectweb.asm.tree.InsnList;
      import org.objectweb.asm.tree.InsnNode;
      import org.objectweb.asm.tree.InvokeDynamicInsnNode;
      import org.objectweb.asm.tree.MethodNode;

      public class InvokeDynamicTest {
        public static void main(String[] args) throws Exception {
          System.err.println(System.getProperty("java.version"));

          ClassNode classNode = new ClassNode();
          classNode.version = Opcodes.V1_8;
          classNode.access = Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER;
          classNode.name = "HelloWorld";
          classNode.superName = "java/lang/Object";

          // Create the run method
          MethodNode runMethod = new MethodNode(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "run", "()V", null, null);
          InsnList instructions = runMethod.instructions;

              String bootstrapDescriptor = Type.getMethodDescriptor(Type.getType(CallSite.class),
                  Type.getType(MethodHandles.Lookup.class),
                  Type.getType(String.class),
                  Type.getType(MethodType.class),
                  Type.getType(boolean.class));

          Handle bootstrapMethod = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(
              InvokeDynamicTest.class), "bootstrap", bootstrapDescriptor, false);

          // Use invokedynamic to print "Hello, World!"
          instructions.add(new InvokeDynamicInsnNode("runMethod", "()V", bootstrapMethod, true));
          instructions.add(new InsnNode(Opcodes.RETURN));
          classNode.methods.add(runMethod);

          // Generate the bytecode
          ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
          classNode.accept(cw);
          byte[] bytecode = cw.toByteArray();

          // Define the generated class
          Class<?> helloWorldClass = new MyClassLoader().defineClass("HelloWorld", bytecode);

          // Invoke the run method of the generated class
          Method run = helloWorldClass.getMethod("run");
          run.invoke(null);
        }

        public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type, boolean extraBoolean) throws NoSuchMethodException, IllegalAccessException {
          MethodHandle mh = lookup.findStatic(InvokeDynamicTest.class, "dynamicMethod", type);
          return new ConstantCallSite(mh);
        }

        public static void dynamicMethod() {
          System.out.println("Hello, World!");
        }

        static class MyClassLoader extends ClassLoader {
          public Class<?> defineClass(String name, byte[] b) {
            return defineClass(name, b, 0, b.length);
          }
        }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      The workaround is to use 'int' instead of 'boolean' as the extra argument for the invokedynamic bootstrap method.

      FREQUENCY : always


            forax Rémi Forax
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: