Skip to content

Commit

Permalink
8294980: test/jdk/java/lang/invoke 15 test classes use experimental b…
Browse files Browse the repository at this point in the history
…ytecode library

Reviewed-by: asotona
  • Loading branch information
Mourad Abbay authored and asotona committed Nov 8, 2023
1 parent e841897 commit 7bc8e4c
Show file tree
Hide file tree
Showing 38 changed files with 1,047 additions and 7,164 deletions.
Expand Up @@ -23,129 +23,116 @@

package test.java.lang.invoke.lib;

import jdk.experimental.bytecode.BasicClassBuilder;
import jdk.experimental.bytecode.BasicTypeHelper;
import jdk.experimental.bytecode.Flag;
import jdk.experimental.bytecode.PoolHelper;
import jdk.experimental.bytecode.TypedCodeBuilder;
import jdk.internal.classfile.ClassBuilder;
import jdk.internal.classfile.Classfile;
import jdk.internal.classfile.TypeKind;

import java.io.FileOutputStream;
import java.lang.constant.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;

import static java.lang.invoke.MethodType.fromMethodDescriptorString;
import static java.lang.invoke.MethodType.methodType;

public class InstructionHelper {

static final BasicTypeHelper BTH = new BasicTypeHelper();

static final AtomicInteger COUNT = new AtomicInteger();

static BasicClassBuilder classBuilder(MethodHandles.Lookup l) {
String className = l.lookupClass().getCanonicalName().replace('.', '/') + "$Code_" + COUNT.getAndIncrement();
return new BasicClassBuilder(className, 55, 0)
.withSuperclass("java/lang/Object")
.withMethod("<init>", "()V", M ->
M.withFlags(Flag.ACC_PUBLIC)
.withCode(TypedCodeBuilder::new, C ->
C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_()
));
private static void commonBuild(ClassBuilder classBuilder) {
classBuilder
.withVersion(55, 0)
.withSuperclass(ConstantDescs.CD_Object)
.withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, Classfile.ACC_PUBLIC,
methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.aload(0)
.invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME,
ConstantDescs.MTD_void, false)
.return_()));
}

public static MethodHandle invokedynamic(MethodHandles.Lookup l,
String name, MethodType type,
String bsmMethodName, MethodType bsmType,
Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception {
byte[] byteArray = classBuilder(l)
.withMethod("m", type.toMethodDescriptorString(), M ->
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
.withCode(TypedCodeBuilder::new,
C -> {
for (int i = 0; i < type.parameterCount(); i++) {
C.load(BTH.tag(cref(type.parameterType(i))), i);
}
C.invokedynamic(name, type.toMethodDescriptorString(),
csym(l.lookupClass()), bsmMethodName, bsmType.toMethodDescriptorString(),
staticArgs);
C.return_(BTH.tag(cref(type.returnType())));
}
))
.build();
public static MethodHandle invokedynamic(MethodHandles.Lookup l, String name, MethodType type, String bsmMethodName,
MethodType bsmType, ConstantDesc... boostrapArgs) throws Exception {
ClassDesc genClassDesc = classDesc(l.lookupClass(), "$Code_" + COUNT.getAndIncrement());
byte[] byteArray = Classfile.of().build(genClassDesc, classBuilder -> {
commonBuild(classBuilder);
classBuilder
.withMethod("m", MethodTypeDesc.ofDescriptor(type.toMethodDescriptorString()),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> {
for (int i = 0; i < type.parameterCount(); i++) {
codeBuilder.loadInstruction(TypeKind.from(type.parameterType(i)), i);
}
codeBuilder.invokedynamic(DynamicCallSiteDesc.of(
MethodHandleDesc.ofMethod(
DirectMethodHandleDesc.Kind.STATIC,
classDesc(l.lookupClass()),
bsmMethodName,
MethodTypeDesc.ofDescriptor(
bsmType.toMethodDescriptorString())),
name,
MethodTypeDesc.ofDescriptor(type.toMethodDescriptorString()),
boostrapArgs));
codeBuilder.returnInstruction(TypeKind.from(type.returnType()));
}));
});
Class<?> gc = l.defineClass(byteArray);
return l.findStatic(gc, "m", type);
}

public static MethodHandle ldcMethodHandle(MethodHandles.Lookup l,
int refKind, Class<?> owner, String name, MethodType type) throws Exception {
return ldc(l, MethodHandle.class,
P -> P.putHandle(refKind, csym(owner), name, type.toMethodDescriptorString()));
}

public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l,
String name, Class<?> type,
String bsmMethodName, MethodType bsmType,
Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception {
return ldcDynamicConstant(l, name, type, l.lookupClass(), bsmMethodName, bsmType, staticArgs);
}

public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l,
String name, Class<?> type,
Class<?> bsmClass, String bsmMethodName, MethodType bsmType,
Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception {
return ldcDynamicConstant(l, name, cref(type), csym(bsmClass), bsmMethodName, bsmType.toMethodDescriptorString(), staticArgs);
public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, Class<?> type, String bsmMethodName,
MethodType bsmType, ConstantDesc... bootstrapArgs) throws Exception {
return ldcDynamicConstant(l, name, type, l.lookupClass(), bsmMethodName, bsmType, bootstrapArgs);
}

public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l,
String name, String type,
String bsmMethodName, String bsmType,
Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception {
return ldcDynamicConstant(l, name, type, csym(l.lookupClass()), bsmMethodName, bsmType, staticArgs);
public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, Class<?> type, Class<?> bsmClass,
String bsmMethodName, MethodType bsmType, ConstantDesc... bootstrapArgs) throws Exception {
return ldcDynamicConstant(l, name, type.descriptorString(), bsmClass.descriptorString(), bsmMethodName,
bsmType.descriptorString(), bootstrapArgs);
}

public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l,
String name, String type,
String bsmClass, String bsmMethodName, String bsmType,
Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception {
return ldc(l, type,
P -> P.putDynamicConstant(name, type,
bsmClass, bsmMethodName, bsmType,
staticArgs));
public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, String type, String bsmMethodName,
String bsmType, ConstantDesc... bootstrapArgs) throws Exception {
return ldcDynamicConstant(l, name, type, l.lookupClass().descriptorString(), bsmMethodName, bsmType, bootstrapArgs);
}

public static MethodHandle ldc(MethodHandles.Lookup l,
Class<?> type,
Function<PoolHelper<String, String, byte[]>, Integer> poolFunc) throws Exception {
return ldc(l, cref(type), poolFunc);
}

public static MethodHandle ldc(MethodHandles.Lookup l,
String type,
Function<PoolHelper<String, String, byte[]>, Integer> poolFunc) throws Exception {
public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, String type, String bsmClass,
String bsmMethodName, String bsmType, ConstantDesc... bootstrapArgs)
throws IllegalAccessException, NoSuchMethodException {
String methodType = "()" + type;
byte[] byteArray = classBuilder(l)
.withMethod("m", "()" + type, M ->
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
.withCode(TypedCodeBuilder::new,
C -> {
C.ldc(null, (P, v) -> poolFunc.apply(P));
C.return_(BTH.tag(type));
}
))
.build();
Class<?> gc = l.defineClass(byteArray);
ClassDesc genClassDesc = classDesc(l.lookupClass(), "$Code_" + COUNT.getAndIncrement());
byte[] bytes = Classfile.of().build(genClassDesc, classBuilder -> {
commonBuild(classBuilder);
classBuilder.withMethod("m", MethodTypeDesc.of(ClassDesc.ofDescriptor(type)),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
MethodHandleDesc.ofMethod(
DirectMethodHandleDesc.Kind.STATIC,
ClassDesc.ofDescriptor(bsmClass),
bsmMethodName,
MethodTypeDesc.ofDescriptor(bsmType)),
name,
ClassDesc.ofDescriptor(type),
bootstrapArgs))
.returnInstruction(TypeKind.fromDescriptor(type))));
});
Class<?> gc = l.defineClass(bytes);
return l.findStatic(gc, "m", fromMethodDescriptorString(methodType, l.lookupClass().getClassLoader()));
}

public static String csym(Class<?> c) {
return c.getCanonicalName().replace('.', '/');
}

public static String cref(Class<?> c) {
return methodType(c).toMethodDescriptorString().substring(2);
public static ClassDesc classDesc(Class<?> c) {
return ClassDesc.ofDescriptor(c.descriptorString());
}

public static ClassDesc classDesc(Class<?> c, String suffix) {
StringBuilder sb = new StringBuilder(c.descriptorString());
String classDescStr = sb.insert(sb.length() - 1, suffix).toString();
return ClassDesc.ofDescriptor(classDescStr);
}
}
51 changes: 23 additions & 28 deletions test/jdk/java/lang/invoke/condy/BootstrapMethodJumboArgsTest.java
Expand Up @@ -25,13 +25,17 @@
* @test
* @bug 8186046
* @summary Test bootstrap methods throwing an exception
* @library /lib/testlibrary/bytecode /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper
* @library /java/lang/invoke/common
* @build test.java.lang.invoke.lib.InstructionHelper
* @modules java.base/jdk.internal.classfile
* java.base/jdk.internal.classfile.attribute
* java.base/jdk.internal.classfile.constantpool
* java.base/jdk.internal.classfile.instruction
* java.base/jdk.internal.classfile.components
* @run testng BootstrapMethodJumboArgsTest
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 BootstrapMethodJumboArgsTest
*/

import jdk.experimental.bytecode.PoolHelper;
import org.testng.Assert;
import org.testng.annotations.Test;
import test.java.lang.invoke.lib.InstructionHelper;
Expand All @@ -49,12 +53,11 @@ public class BootstrapMethodJumboArgsTest {


static Object bsmZero(MethodHandles.Lookup l, String name, Object type,
Object... args) {
Object... args) {
Object[] a = args.clone();
if (type instanceof MethodType) {
return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
}
else {
} else {
return a;
}
}
Expand All @@ -66,8 +69,7 @@ static Object bsmOne(MethodHandles.Lookup l, String name, Object type,
System.arraycopy(args, 0, a, 1, args.length);
if (type instanceof MethodType) {
return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
}
else {
} else {
return a;
}
}
Expand All @@ -80,27 +82,20 @@ static Object bsmTwo(MethodHandles.Lookup l, String name, Object type,
System.arraycopy(args, 0, a, 2, args.length);
if (type instanceof MethodType) {
return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
}
else {
} else {
return a;
}
}

static void manyStaticStrings(String[] args, PoolHelper.StaticArgListBuilder<String, String, byte[]> staticArgs) {
for (String s : args) {
staticArgs.add(s);
}
}

@Test
public void testCondyWithJumboArgs() throws Throwable {
String[] expected = IntStream.range(0, 1000).mapToObj(Integer::toString).toArray(String[]::new);

{
MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object[].class,
"bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object[].class),
S -> manyStaticStrings(expected, S));
"bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class,
Object.class, Object[].class), expected);

Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected);
Expand All @@ -109,8 +104,8 @@ public void testCondyWithJumboArgs() throws Throwable {
{
MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object[].class,
"bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object[].class),
S -> manyStaticStrings(expected, S));
"bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class,
Object.class, Object.class, Object[].class), expected);

Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected);
Expand All @@ -119,8 +114,8 @@ public void testCondyWithJumboArgs() throws Throwable {
{
MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object[].class,
"bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object.class, Object[].class),
S -> manyStaticStrings(expected, S));
"bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class,
Object.class, Object.class, Object.class, Object[].class), expected);

Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected);
Expand All @@ -134,8 +129,8 @@ public void testIndyWithJumboArgs() throws Throwable {
{
MethodHandle mh = InstructionHelper.invokedynamic(
L, "name", methodType(Object[].class),
"bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object[].class),
S -> manyStaticStrings(expected, S));
"bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class,
Object.class, Object[].class), expected);

Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected);
Expand All @@ -144,8 +139,8 @@ public void testIndyWithJumboArgs() throws Throwable {
{
MethodHandle mh = InstructionHelper.invokedynamic(
L, "name", methodType(Object[].class),
"bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object[].class),
S -> manyStaticStrings(expected, S));
"bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class,
Object.class, Object.class, Object[].class), expected);

Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected);
Expand All @@ -154,8 +149,8 @@ public void testIndyWithJumboArgs() throws Throwable {
{
MethodHandle mh = InstructionHelper.invokedynamic(
L, "name", methodType(Object[].class),
"bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object.class, Object[].class),
S -> manyStaticStrings(expected, S));
"bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class,
Object.class, Object.class, Object.class, Object[].class), expected);

Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected);
Expand Down

1 comment on commit 7bc8e4c

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.