-
Bug
-
Resolution: Not an Issue
-
P4
-
None
-
8, 11, 17, 21, 22
-
x86_64
-
linux
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
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