8294980: test/jdk/java/lang/invoke 15 test classes use experimental bytecode library

Reviewed-by: asotona
This commit is contained in:
Mourad Abbay 2023-11-08 13:26:58 +00:00 committed by Adam Sotona
parent e841897247
commit 7bc8e4c891
38 changed files with 1043 additions and 7160 deletions

View file

@ -23,121 +23,102 @@
package test.java.lang.invoke.lib; package test.java.lang.invoke.lib;
import jdk.experimental.bytecode.BasicClassBuilder; import jdk.internal.classfile.ClassBuilder;
import jdk.experimental.bytecode.BasicTypeHelper; import jdk.internal.classfile.Classfile;
import jdk.experimental.bytecode.Flag; import jdk.internal.classfile.TypeKind;
import jdk.experimental.bytecode.PoolHelper;
import jdk.experimental.bytecode.TypedCodeBuilder;
import java.io.FileOutputStream; import java.lang.constant.*;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.util.concurrent.atomic.AtomicInteger; 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.fromMethodDescriptorString;
import static java.lang.invoke.MethodType.methodType;
public class InstructionHelper { public class InstructionHelper {
static final BasicTypeHelper BTH = new BasicTypeHelper();
static final AtomicInteger COUNT = new AtomicInteger(); static final AtomicInteger COUNT = new AtomicInteger();
static BasicClassBuilder classBuilder(MethodHandles.Lookup l) { private static void commonBuild(ClassBuilder classBuilder) {
String className = l.lookupClass().getCanonicalName().replace('.', '/') + "$Code_" + COUNT.getAndIncrement(); classBuilder
return new BasicClassBuilder(className, 55, 0) .withVersion(55, 0)
.withSuperclass("java/lang/Object") .withSuperclass(ConstantDescs.CD_Object)
.withMethod("<init>", "()V", M -> .withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, Classfile.ACC_PUBLIC,
M.withFlags(Flag.ACC_PUBLIC) methodBuilder -> methodBuilder
.withCode(TypedCodeBuilder::new, C -> .withCode(codeBuilder -> codeBuilder
C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_() .aload(0)
)); .invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME,
ConstantDescs.MTD_void, false)
.return_()));
} }
public static MethodHandle invokedynamic(MethodHandles.Lookup l, public static MethodHandle invokedynamic(MethodHandles.Lookup l, String name, MethodType type, String bsmMethodName,
String name, MethodType type, MethodType bsmType, ConstantDesc... boostrapArgs) throws Exception {
String bsmMethodName, MethodType bsmType, ClassDesc genClassDesc = classDesc(l.lookupClass(), "$Code_" + COUNT.getAndIncrement());
Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception { byte[] byteArray = Classfile.of().build(genClassDesc, classBuilder -> {
byte[] byteArray = classBuilder(l) commonBuild(classBuilder);
.withMethod("m", type.toMethodDescriptorString(), M -> classBuilder
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .withMethod("m", MethodTypeDesc.ofDescriptor(type.toMethodDescriptorString()),
.withCode(TypedCodeBuilder::new, Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
C -> { .withCode(codeBuilder -> {
for (int i = 0; i < type.parameterCount(); i++) { for (int i = 0; i < type.parameterCount(); i++) {
C.load(BTH.tag(cref(type.parameterType(i))), i); codeBuilder.loadInstruction(TypeKind.from(type.parameterType(i)), i);
} }
C.invokedynamic(name, type.toMethodDescriptorString(), codeBuilder.invokedynamic(DynamicCallSiteDesc.of(
csym(l.lookupClass()), bsmMethodName, bsmType.toMethodDescriptorString(), MethodHandleDesc.ofMethod(
staticArgs); DirectMethodHandleDesc.Kind.STATIC,
C.return_(BTH.tag(cref(type.returnType()))); classDesc(l.lookupClass()),
} bsmMethodName,
)) MethodTypeDesc.ofDescriptor(
.build(); bsmType.toMethodDescriptorString())),
name,
MethodTypeDesc.ofDescriptor(type.toMethodDescriptorString()),
boostrapArgs));
codeBuilder.returnInstruction(TypeKind.from(type.returnType()));
}));
});
Class<?> gc = l.defineClass(byteArray); Class<?> gc = l.defineClass(byteArray);
return l.findStatic(gc, "m", type); return l.findStatic(gc, "m", type);
} }
public static MethodHandle ldcMethodHandle(MethodHandles.Lookup l, public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, Class<?> type, String bsmMethodName,
int refKind, Class<?> owner, String name, MethodType type) throws Exception { MethodType bsmType, ConstantDesc... bootstrapArgs) throws Exception {
return ldc(l, MethodHandle.class, return ldcDynamicConstant(l, name, type, l.lookupClass(), bsmMethodName, bsmType, bootstrapArgs);
P -> P.putHandle(refKind, csym(owner), name, type.toMethodDescriptorString()));
} }
public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, Class<?> type, Class<?> bsmClass,
String name, Class<?> type, String bsmMethodName, MethodType bsmType, ConstantDesc... bootstrapArgs) throws Exception {
String bsmMethodName, MethodType bsmType, return ldcDynamicConstant(l, name, type.descriptorString(), bsmClass.descriptorString(), bsmMethodName,
Consumer<PoolHelper.StaticArgListBuilder<String, String, byte[]>> staticArgs) throws Exception { bsmType.descriptorString(), bootstrapArgs);
return ldcDynamicConstant(l, name, type, l.lookupClass(), bsmMethodName, bsmType, staticArgs);
} }
public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, String type, String bsmMethodName,
String name, Class<?> type, String bsmType, ConstantDesc... bootstrapArgs) throws Exception {
Class<?> bsmClass, String bsmMethodName, MethodType bsmType, return ldcDynamicConstant(l, name, type, l.lookupClass().descriptorString(), bsmMethodName, bsmType, bootstrapArgs);
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, public static MethodHandle ldcDynamicConstant(MethodHandles.Lookup l, String name, String type, String bsmClass,
String name, String type, String bsmMethodName, String bsmType, ConstantDesc... bootstrapArgs)
String bsmMethodName, String bsmType, throws IllegalAccessException, NoSuchMethodException {
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, 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 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 {
String methodType = "()" + type; String methodType = "()" + type;
byte[] byteArray = classBuilder(l) ClassDesc genClassDesc = classDesc(l.lookupClass(), "$Code_" + COUNT.getAndIncrement());
.withMethod("m", "()" + type, M -> byte[] bytes = Classfile.of().build(genClassDesc, classBuilder -> {
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) commonBuild(classBuilder);
.withCode(TypedCodeBuilder::new, classBuilder.withMethod("m", MethodTypeDesc.of(ClassDesc.ofDescriptor(type)),
C -> { Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
C.ldc(null, (P, v) -> poolFunc.apply(P)); .withCode(codeBuilder -> codeBuilder
C.return_(BTH.tag(type)); .ldc(DynamicConstantDesc.ofNamed(
} MethodHandleDesc.ofMethod(
)) DirectMethodHandleDesc.Kind.STATIC,
.build(); ClassDesc.ofDescriptor(bsmClass),
Class<?> gc = l.defineClass(byteArray); 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())); return l.findStatic(gc, "m", fromMethodDescriptorString(methodType, l.lookupClass().getClassLoader()));
} }
@ -145,7 +126,13 @@ public class InstructionHelper {
return c.getCanonicalName().replace('.', '/'); return c.getCanonicalName().replace('.', '/');
} }
public static String cref(Class<?> c) { public static ClassDesc classDesc(Class<?> c) {
return methodType(c).toMethodDescriptorString().substring(2); 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);
} }
} }

View file

@ -25,13 +25,17 @@
* @test * @test
* @bug 8186046 * @bug 8186046
* @summary Test bootstrap methods throwing an exception * @summary Test bootstrap methods throwing an exception
* @library /lib/testlibrary/bytecode /java/lang/invoke/common * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper * @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 BootstrapMethodJumboArgsTest
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 BootstrapMethodJumboArgsTest * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 BootstrapMethodJumboArgsTest
*/ */
import jdk.experimental.bytecode.PoolHelper;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import test.java.lang.invoke.lib.InstructionHelper; import test.java.lang.invoke.lib.InstructionHelper;
@ -49,12 +53,11 @@ public class BootstrapMethodJumboArgsTest {
static Object bsmZero(MethodHandles.Lookup l, String name, Object type, static Object bsmZero(MethodHandles.Lookup l, String name, Object type,
Object... args) { Object... args) {
Object[] a = args.clone(); Object[] a = args.clone();
if (type instanceof MethodType) { if (type instanceof MethodType) {
return new ConstantCallSite(MethodHandles.constant(Object[].class, a)); return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
} } else {
else {
return a; return a;
} }
} }
@ -66,8 +69,7 @@ public class BootstrapMethodJumboArgsTest {
System.arraycopy(args, 0, a, 1, args.length); System.arraycopy(args, 0, a, 1, args.length);
if (type instanceof MethodType) { if (type instanceof MethodType) {
return new ConstantCallSite(MethodHandles.constant(Object[].class, a)); return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
} } else {
else {
return a; return a;
} }
} }
@ -80,18 +82,11 @@ public class BootstrapMethodJumboArgsTest {
System.arraycopy(args, 0, a, 2, args.length); System.arraycopy(args, 0, a, 2, args.length);
if (type instanceof MethodType) { if (type instanceof MethodType) {
return new ConstantCallSite(MethodHandles.constant(Object[].class, a)); return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
} } else {
else {
return a; return a;
} }
} }
static void manyStaticStrings(String[] args, PoolHelper.StaticArgListBuilder<String, String, byte[]> staticArgs) {
for (String s : args) {
staticArgs.add(s);
}
}
@Test @Test
public void testCondyWithJumboArgs() throws Throwable { public void testCondyWithJumboArgs() throws Throwable {
String[] expected = IntStream.range(0, 1000).mapToObj(Integer::toString).toArray(String[]::new); String[] expected = IntStream.range(0, 1000).mapToObj(Integer::toString).toArray(String[]::new);
@ -99,8 +94,8 @@ public class BootstrapMethodJumboArgsTest {
{ {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object[].class, L, "name", Object[].class,
"bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object[].class), "bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class,
S -> manyStaticStrings(expected, S)); Object.class, Object[].class), expected);
Object[] actual = (Object[]) mh.invoke(); Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected); Assert.assertEquals(actual, expected);
@ -109,8 +104,8 @@ public class BootstrapMethodJumboArgsTest {
{ {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object[].class, L, "name", Object[].class,
"bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object[].class), "bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class,
S -> manyStaticStrings(expected, S)); Object.class, Object.class, Object[].class), expected);
Object[] actual = (Object[]) mh.invoke(); Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected); Assert.assertEquals(actual, expected);
@ -119,8 +114,8 @@ public class BootstrapMethodJumboArgsTest {
{ {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object[].class, L, "name", Object[].class,
"bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object.class, Object[].class), "bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class,
S -> manyStaticStrings(expected, S)); Object.class, Object.class, Object.class, Object[].class), expected);
Object[] actual = (Object[]) mh.invoke(); Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected); Assert.assertEquals(actual, expected);
@ -134,8 +129,8 @@ public class BootstrapMethodJumboArgsTest {
{ {
MethodHandle mh = InstructionHelper.invokedynamic( MethodHandle mh = InstructionHelper.invokedynamic(
L, "name", methodType(Object[].class), L, "name", methodType(Object[].class),
"bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object[].class), "bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class,
S -> manyStaticStrings(expected, S)); Object.class, Object[].class), expected);
Object[] actual = (Object[]) mh.invoke(); Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected); Assert.assertEquals(actual, expected);
@ -144,8 +139,8 @@ public class BootstrapMethodJumboArgsTest {
{ {
MethodHandle mh = InstructionHelper.invokedynamic( MethodHandle mh = InstructionHelper.invokedynamic(
L, "name", methodType(Object[].class), L, "name", methodType(Object[].class),
"bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object[].class), "bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class,
S -> manyStaticStrings(expected, S)); Object.class, Object.class, Object[].class), expected);
Object[] actual = (Object[]) mh.invoke(); Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected); Assert.assertEquals(actual, expected);
@ -154,8 +149,8 @@ public class BootstrapMethodJumboArgsTest {
{ {
MethodHandle mh = InstructionHelper.invokedynamic( MethodHandle mh = InstructionHelper.invokedynamic(
L, "name", methodType(Object[].class), L, "name", methodType(Object[].class),
"bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object.class, Object[].class), "bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class,
S -> manyStaticStrings(expected, S)); Object.class, Object.class, Object.class, Object[].class), expected);
Object[] actual = (Object[]) mh.invoke(); Object[] actual = (Object[]) mh.invoke();
Assert.assertEquals(actual, expected); Assert.assertEquals(actual, expected);

View file

@ -25,8 +25,13 @@
* @test * @test
* @bug 8186046 * @bug 8186046
* @summary Test bootstrap methods throwing an exception * @summary Test bootstrap methods throwing an exception
* @library /lib/testlibrary/bytecode /java/lang/invoke/common * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper * @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 CondyBSMException * @run testng CondyBSMException
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMException * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMException
*/ */
@ -64,7 +69,7 @@ public class CondyBSMException {
} }
@Test @Test
public void testException() throws Throwable { public void testException() {
test("Exception", BootstrapMethodError.class, Exception.class); test("Exception", BootstrapMethodError.class, Exception.class);
} }
@ -73,8 +78,7 @@ public class CondyBSMException {
Throwable caught = null; Throwable caught = null;
try { try {
mh.invoke(); mh.invoke();
} } catch (Throwable t) {
catch (Throwable t) {
caught = t; caught = t;
} }
@ -98,8 +102,7 @@ public class CondyBSMException {
try { try {
Constructor<Throwable> c = type.getDeclaredConstructor(String.class); Constructor<Throwable> c = type.getDeclaredConstructor(String.class);
t = c.newInstance(name); t = c.newInstance(name);
} } catch (Exception e) {
catch (Exception e) {
throw new InternalError(); throw new InternalError();
} }
throw t; throw t;
@ -110,8 +113,9 @@ public class CondyBSMException {
return InstructionHelper.ldcDynamicConstant( return InstructionHelper.ldcDynamicConstant(
MethodHandles.lookup(), MethodHandles.lookup(),
message, t, message, t,
"throwingBsm", methodType(Throwable.class, MethodHandles.Lookup.class, String.class, Class.class), "throwingBsm",
S -> { }); methodType(Throwable.class, MethodHandles.Lookup.class, String.class, Class.class)
);
} catch (Exception e) { } catch (Exception e) {
throw new Error(e); throw new Error(e);
} }

View file

@ -25,8 +25,13 @@
* @test * @test
* @bug 8186046 8199875 * @bug 8186046 8199875
* @summary Test basic invocation of bootstrap methods * @summary Test basic invocation of bootstrap methods
* @library /lib/testlibrary/bytecode /java/lang/invoke/common * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper * @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 CondyBSMInvocation * @run testng CondyBSMInvocation
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMInvocation * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMInvocation
*/ */
@ -36,6 +41,7 @@ import org.testng.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import test.java.lang.invoke.lib.InstructionHelper; import test.java.lang.invoke.lib.InstructionHelper;
import java.lang.constant.ConstantDesc;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
@ -55,8 +61,8 @@ public class CondyBSMInvocation {
public void testNonexistent() throws Throwable { public void testNonexistent() throws Throwable {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object.class, L, "name", Object.class,
"bsm", methodType(Object.class), "bsm", methodType(Object.class)
S -> {}); );
try { try {
mh.invoke(); mh.invoke();
@ -110,8 +116,7 @@ public class CondyBSMInvocation {
for (MethodHandle bsm : bsms("shape_bsm")) { for (MethodHandle bsm : bsms("shape_bsm")) {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object.class, L, "name", Object.class,
"shape_bsm", bsm.type(), "shape_bsm", bsm.type()
S -> {}
); );
try { try {
@ -136,8 +141,7 @@ public class CondyBSMInvocation {
for (MethodHandle bsm : bsms("sig_bsm")) { for (MethodHandle bsm : bsms("sig_bsm")) {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object.class, L, "name", Object.class,
"sig_bsm", bsm.type(), "sig_bsm", bsm.type()
S -> {}
); );
try { try {
@ -216,8 +220,8 @@ public class CondyBSMInvocation {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object.class, L, "name", Object.class,
"bsm", mt, "bsm", mt,
S -> IntStream.range(0, n).forEach(S::add) IntStream.range(0, n).boxed().toArray(ConstantDesc[]::new)
); );
Object r = mh.invoke(); Object r = mh.invoke();
Assert.assertEquals(r, Integer.toString(n)); Assert.assertEquals(r, Integer.toString(n));
@ -228,7 +232,7 @@ public class CondyBSMInvocation {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object.class, L, "name", Object.class,
"bsm", mt, "bsm", mt,
S -> IntStream.range(0, 9).forEach(S::add) IntStream.range(0, 9).boxed().toArray(ConstantDesc[]::new)
); );
Object r = mh.invoke(); Object r = mh.invoke();
@ -246,7 +250,7 @@ public class CondyBSMInvocation {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", Object.class, L, "name", Object.class,
"bsm", mt, "bsm", mt,
S -> IntStream.range(0, n - 1).forEach(S::add) IntStream.range(0, n - 1).boxed().toArray(ConstantDesc[]::new)
); );
try { try {

View file

@ -25,12 +25,18 @@
* @test * @test
* @bug 8186046 * @bug 8186046
* @summary Test invalid name in name and type * @summary Test invalid name in name and type
* @library /lib/testlibrary/bytecode /java/lang/invoke/common * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper * @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 CondyBSMValidationTest * @run testng CondyBSMValidationTest
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMValidationTest * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMValidationTest
*/ */
import org.testng.Assert;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import test.java.lang.invoke.lib.InstructionHelper; import test.java.lang.invoke.lib.InstructionHelper;
@ -49,19 +55,22 @@ public class CondyBSMValidationTest {
@DataProvider @DataProvider
public Object[][] invalidSignaturesProvider() throws Exception { public Object[][] invalidSignaturesProvider() throws Exception {
return Stream.of(BSM_TYPE.replace("(", ""), return Stream.of(BSM_TYPE.replace("(", ""),
BSM_TYPE.replace(")", ""), BSM_TYPE.replace(")", ""),
BSM_TYPE.replace("(", "").replace(")", ""), BSM_TYPE.replace("(", "").replace(")", ""),
BSM_TYPE.replace(";)", ")"), BSM_TYPE.replace(";)", ")"),
BSM_TYPE.replace(";", "")) BSM_TYPE.replace(";", ""))
.map(e -> new Object[]{e}).toArray(Object[][]::new); .map(e -> new Object[]{e}).toArray(Object[][]::new);
} }
@Test(dataProvider = "invalidSignaturesProvider", expectedExceptions = ClassFormatError.class) @Test(dataProvider = "invalidSignaturesProvider")
public void testInvalidBSMSignature(String sig) throws Exception { public void testInvalidBSMSignature(String sig) throws Exception {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( try {
L, "name", "Ljava/lang/Object;", MethodHandle mh = InstructionHelper.ldcDynamicConstant(
"bsm", sig, L, "name", "Ljava/lang/Object;",
S -> { "bsm", sig
}); );
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage().contains("Bad method descriptor"));
}
} }
} }

View file

@ -25,18 +25,23 @@
* @test * @test
* @bug 8186046 * @bug 8186046
* @summary Test for an interface using condy with default overpass methods * @summary Test for an interface using condy with default overpass methods
* @library /lib/testlibrary/bytecode * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder * @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 CondyInterfaceWithOverpassMethods * @run testng CondyInterfaceWithOverpassMethods
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyInterfaceWithOverpassMethods * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyInterfaceWithOverpassMethods
*/ */
import jdk.experimental.bytecode.BasicClassBuilder; import jdk.internal.classfile.Classfile;
import jdk.experimental.bytecode.Flag;
import jdk.experimental.bytecode.TypedCodeBuilder;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import test.java.lang.invoke.lib.InstructionHelper;
import java.lang.constant.*;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
@ -70,24 +75,32 @@ public class CondyInterfaceWithOverpassMethods {
Class<?> thisClass = CondyInterfaceWithOverpassMethods.class; Class<?> thisClass = CondyInterfaceWithOverpassMethods.class;
String genClassName = thisClass.getSimpleName() + "$Code"; String genClassName = thisClass.getSimpleName() + "$Code";
String bsmClassName = thisClass.getCanonicalName().replace('.', '/'); String bsmClassName = thisClass.descriptorString();
String bsmMethodName = "bsm"; String bsmMethodName = "bsm";
String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class, String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class,
String.class, Class.class).toMethodDescriptorString(); String.class, Class.class).toMethodDescriptorString();
byte[] byteArray = new BasicClassBuilder(genClassName, 55, 0)
.withFlags(Flag.ACC_INTERFACE, Flag.ACC_ABSTRACT)
.withSuperclass("java/lang/Object")
.withSuperinterface(thisClass.getCanonicalName().replace('.', '/') + "$" + A.class.getSimpleName())
.withMethod("y", "()Ljava/lang/String;", M ->
M.withFlags(Flag.ACC_PUBLIC)
.withCode(TypedCodeBuilder::new, C ->
C.ldc("String", "Ljava/lang/String;", bsmClassName, bsmMethodName, bsmDescriptor,
S -> {})
.areturn()
))
.build();
byte[] byteArray = Classfile.of().build(ClassDesc.of(genClassName), classBuilder -> classBuilder
.withFlags(Classfile.ACC_INTERFACE + Classfile.ACC_ABSTRACT)
.withSuperclass(ConstantDescs.CD_Object)
.withInterfaceSymbols(InstructionHelper.classDesc(A.class))
.withMethod("y", MethodTypeDesc.of(ConstantDescs.CD_String), Classfile.ACC_PUBLIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
MethodHandleDesc.of(
DirectMethodHandleDesc.Kind.STATIC,
ClassDesc.ofDescriptor(bsmClassName),
bsmMethodName,
bsmDescriptor
),
"String",
ConstantDescs.CD_String
)
)
.areturn()
)
)
);
gc = MethodHandles.lookup().defineClass(byteArray); gc = MethodHandles.lookup().defineClass(byteArray);
} }

View file

@ -25,12 +25,18 @@
* @test * @test
* @bug 8186046 * @bug 8186046
* @summary Test invalid name in name and type * @summary Test invalid name in name and type
* @library /lib/testlibrary/bytecode /java/lang/invoke/common * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper * @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 CondyNameValidationTest * @run testng CondyNameValidationTest
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyNameValidationTest * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyNameValidationTest
*/ */
import org.testng.Assert;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import test.java.lang.invoke.lib.InstructionHelper; import test.java.lang.invoke.lib.InstructionHelper;
@ -47,29 +53,33 @@ public class CondyNameValidationTest {
static final MethodType BSM_TYPE = methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class); static final MethodType BSM_TYPE = methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class);
@DataProvider @DataProvider
public Object[][] invalidNamesProvider() throws Exception { public Object[][] invalidNamesProvider() {
return Stream.of("", return Stream.of(
".", new Object[]{"", "zero-length member name"},
";", new Object[]{".", "Invalid member name"},
"[", new Object[]{";", "Invalid member name"},
"/") new Object[]{"[", "Invalid member name"},
.map(e -> new Object[]{e}).toArray(Object[][]::new); new Object[]{"/", "Invalid member name"}
)
.toArray(Object[][]::new);
} }
@Test(dataProvider = "invalidNamesProvider", expectedExceptions = java.lang.ClassFormatError.class) @Test(dataProvider = "invalidNamesProvider")
public void testInvalidNames(String name) throws Exception { public void testInvalidNames(String name, String errMessContent) throws Exception {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( try {
L, name, Object.class, MethodHandle mh = InstructionHelper.ldcDynamicConstant(
"bsm", BSM_TYPE, L, name, Object.class,
S -> { "bsm", BSM_TYPE
}); );
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage().contains(errMessContent));
}
} }
@DataProvider @DataProvider
public Object[][] validNamesProvider() throws Exception { public Object[][] validNamesProvider() throws Exception {
return Stream.of("<clinit>", return Stream.of("<clinit>",
"<init>", "<init>")
"<foo>")
.map(e -> new Object[]{e}).toArray(Object[][]::new); .map(e -> new Object[]{e}).toArray(Object[][]::new);
} }
@ -77,8 +87,7 @@ public class CondyNameValidationTest {
public void testValidNames(String name) throws Exception { public void testValidNames(String name) throws Exception {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, name, Object.class, L, name, Object.class,
"bsm", BSM_TYPE, "bsm", BSM_TYPE
S -> { );
});
} }
} }

View file

@ -26,6 +26,11 @@
* @bug 8186046 * @bug 8186046
* @summary Test nested dynamic constant declarations that are recursive * @summary Test nested dynamic constant declarations that are recursive
* @compile CondyNestedTest_Code.jcod * @compile CondyNestedTest_Code.jcod
* @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 CondyNestedTest * @run testng CondyNestedTest
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyNestedTest * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyNestedTest
*/ */
@ -34,21 +39,17 @@ import org.testng.Assert;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
public class CondyNestedTest { public class CondyNestedTest {
static final Class[] THROWABLES = {InvocationTargetException.class, StackOverflowError.class}; static final Class[] THROWABLES = {InvocationTargetException.class, StackOverflowError.class};
private static final MethodHandles.Lookup L = MethodHandles.lookup();
Class<?> c; Class<?> c;
// Add the following annotations to the test description if uncommenting the
// following code
//
// * @library /lib/testlibrary/bytecode
// * @build jdk.experimental.bytecode.BasicClassBuilder
//
// static final MethodHandles.Lookup L = MethodHandles.lookup(); // static final MethodHandles.Lookup L = MethodHandles.lookup();
// //
// /** // /**
@ -65,97 +66,178 @@ public class CondyNestedTest {
// */ // */
// public static byte[] generator() throws Exception { // public static byte[] generator() throws Exception {
// String genClassName = L.lookupClass().getSimpleName() + "_Code"; // String genClassName = L.lookupClass().getSimpleName() + "_Code";
// String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class).toMethodDescriptorString(); // ClassDesc genClassDesc = ClassDesc.of(genClassName);
// String bsmIndyDescriptor = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class).toMethodDescriptorString(); // String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class,
// Object.class).toMethodDescriptorString();
// String bsmIndyDescriptor = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class,
// Object.class, Object.class).toMethodDescriptorString();
// DirectMethodHandleDesc bsmMhDesc = MethodHandleDesc.of(
// DirectMethodHandleDesc.Kind.STATIC,
// genClassDesc,
// "bsm",
// bsmDescriptor
// );
// DirectMethodHandleDesc bsmIndyMhDesc = MethodHandleDesc.of(
// DirectMethodHandleDesc.Kind.STATIC,
// genClassDesc,
// "bsmIndy",
// bsmIndyDescriptor
// );
// byte[] byteArray = Classfile.of().build(ClassDesc.of(genClassName), 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)
// .return_()
// )
// )
// .withMethod("main", MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_String.arrayType()),
// Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
// .withCode(codeBuilder -> {
// codeBuilder
// .aload(0)
// .iconst_0()
// .aaload()
// .invokevirtual(ConstantDescs.CD_String, "intern",
// MethodTypeDesc.of(ConstantDescs.CD_String))
// .astore(1);
// Label case1 = codeBuilder.newLabel();
// codeBuilder
// .aload(1)
// .ldc("condy_bsm_condy_bsm")
// .if_acmpne(case1)
// .invokestatic(genClassDesc, "condy_bsm_condy_bsm",
// MethodTypeDesc.of(ConstantDescs.CD_Object))
// .return_();
// Label case2 = codeBuilder.newLabel();
// codeBuilder
// .labelBinding(case1)
// .aload(1)
// .ldc("indy_bsmIndy_condy_bsm")
// .if_acmpne(case2)
// .invokestatic(genClassDesc, "indy_bsmIndy_condy_bsm",
// MethodTypeDesc.of(ConstantDescs.CD_Object))
// .return_();
// Label case3 = codeBuilder.newLabel();
// codeBuilder
// .labelBinding(case2)
// .aload(1)
// .ldc("indy_bsm_condy_bsm")
// .if_acmpne(case3)
// .invokestatic(genClassDesc, "indy_bsm_condy_bsm",
// MethodTypeDesc.of(ConstantDescs.CD_Object))
// .return_();
// codeBuilder
// .labelBinding(case3)
// .return_();
// }
// )
// )
// // bsm that when used with indy returns a call site whose target is MethodHandles.constant(String.class, name), and
// // when used with condy returns the name
// .withMethod("bsm", MethodTypeDesc.ofDescriptor(bsmDescriptor),
// Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
// .withCode(codeBuilder -> {
// codeBuilder
// .aload(2)
// .instanceof_(ConstantDescs.CD_MethodType)
// .iconst_0();
// Label condy = codeBuilder.newLabel();
// codeBuilder
// .if_acmpeq(condy)
// .new_(ClassDesc.ofDescriptor(ConstantCallSite.class.descriptorString()))
// .dup()
// .ldc(ConstantDescs.CD_String)
// .aload(1)
// .invokestatic(ConstantDescs.CD_MethodHandles, "constant",
// MethodTypeDesc.of(ConstantDescs.CD_MethodHandle, ConstantDescs.CD_Class,
// ConstantDescs.CD_Object))
// .invokespecial(ClassDesc.ofDescriptor(ConstantCallSite.class.descriptorString()),
// ConstantDescs.INIT_NAME,
// MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_MethodHandle))
// .areturn();
// codeBuilder
// .labelBinding(condy)
// .aload(1)
// .areturn();
// }
// //
// byte[] byteArray = new BasicClassBuilder(genClassName, 55, 0) // )
// .withSuperclass("java/lang/Object") // )
// .withMethod("<init>", "()V", M -> // // an indy bsm, that returns a call site whose target is MethodHandles.constant(String.class, methodName)
// M.withFlags(Flag.ACC_PUBLIC) // .withMethod("bsmIndy", MethodTypeDesc.ofDescriptor(bsmIndyDescriptor),
// .withCode(TypedCodeBuilder::new, C -> // Classfile.ACC_PUBLIC + Classfile.ACC_PUBLIC, methodBuilder -> methodBuilder
// C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_() // .withCode(codeBuilder -> codeBuilder
// )) // .new_(ClassDesc.ofDescriptor(ConstantCallSite.class.descriptorString()))
// .withMethod("main", "([Ljava/lang/String;)V", M -> // .dup()
// M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) // .ldc(ConstantDescs.CD_String)
// .withCode(TypedCodeBuilder::new, C -> { // .aload(1)
// C.aload_0().iconst_0().aaload(); // .invokestatic(ConstantDescs.CD_MethodHandles, "constant",
// C.invokevirtual("java/lang/String", "intern", "()Ljava/lang/String;", false); // MethodTypeDesc.of(ConstantDescs.CD_MethodHandle, ConstantDescs.CD_Class,
// C.astore_1(); // ConstantDescs.CD_Object))
// // .invokespecial(ClassDesc.ofDescriptor(ConstantCallSite.class.descriptorString()),
// C.aload_1(); // ConstantDescs.INIT_NAME,
// C.ldc("condy_bsm_condy_bsm"); // MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_MethodHandle))
// C.ifcmp(TypeTag.A, MacroCodeBuilder.CondKind.NE, "CASE1"); // .areturn()
// C.invokestatic(genClassName, "condy_bsm_condy_bsm", "()Ljava/lang/Object;", false).return_(); // )
// // )
// C.label("CASE1"); // .withMethod("condy_bsm_condy_bsm", MethodTypeDesc.of(ConstantDescs.CD_Object),
// C.aload_1(); // Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
// C.ldc("indy_bsmIndy_condy_bsm"); // .withCode(codeBuilder -> codeBuilder
// C.ifcmp(TypeTag.A, MacroCodeBuilder.CondKind.NE, "CASE2"); // .ldc(DynamicConstantDesc.ofNamed(
// C.invokestatic(genClassName, "indy_bsmIndy_condy_bsm", "()Ljava/lang/Object;", false).return_(); // bsmMhDesc,
// // "name",
// C.label("CASE2"); // ConstantDescs.CD_String,
// C.aload_1(); // DynamicConstantDesc.ofNamed(
// C.ldc("indy_bsm_condy_bsm"); // bsmMhDesc,
// C.ifcmp(TypeTag.A, MacroCodeBuilder.CondKind.NE, "CASE3"); // "name",
// C.invokestatic(genClassName, "indy_bsm_condy_bsm", "()Ljava/lang/Object;", false).return_(); // ConstantDescs.CD_String,
// // "DUMMY_ARG"
// C.label("CASE3"); // )
// C.return_(); // )
// })) // )
// .withMethod("bsm", bsmDescriptor, M -> // .areturn()
// M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) // )
// .withCode(TypedCodeBuilder::new, C -> { // )
// C.aload_2(); // .withMethod("indy_bsmIndy_condy_bsm", MethodTypeDesc.of(ConstantDescs.CD_Object),
// C.instanceof_("java/lang/invoke/MethodType"); // Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
// C.iconst_0(); // .withCode(codeBuilder -> codeBuilder
// C.ifcmp(TypeTag.I, MacroCodeBuilder.CondKind.EQ, "CONDY"); // .invokedynamic(DynamicCallSiteDesc.of(
// C.new_("java/lang/invoke/ConstantCallSite").dup(); // bsmIndyMhDesc,
// C.ldc("java/lang/String", PoolHelper::putClass); // "name",
// C.aload_1(); // MethodTypeDesc.of(ConstantDescs.CD_String),
// C.invokestatic("java/lang/invoke/MethodHandles", "constant", "(Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;", false); // DynamicConstantDesc.ofNamed(
// C.invokespecial("java/lang/invoke/ConstantCallSite", "<init>", "(Ljava/lang/invoke/MethodHandle;)V", false); // bsmMhDesc,
// C.areturn(); // "name",
// C.label("CONDY"); // ConstantDescs.CD_String,
// C.aload_1().areturn(); // "DUMMY_ARG"
// })) // )
// .withMethod("bsmIndy", bsmIndyDescriptor, M -> // )
// M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) // )
// .withCode(TypedCodeBuilder::new, C -> { // .areturn()
// C.new_("java/lang/invoke/ConstantCallSite").dup(); // )
// C.ldc("java/lang/String", PoolHelper::putClass); // )
// C.aload_1(); // .withMethod("indy_bsm_condy_bsm", MethodTypeDesc.of(ConstantDescs.CD_Object),
// C.invokestatic("java/lang/invoke/MethodHandles", "constant", "(Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;", false); // Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
// C.invokespecial("java/lang/invoke/ConstantCallSite", "<init>", "(Ljava/lang/invoke/MethodHandle;)V", false); // .withCode(codeBuilder -> codeBuilder
// C.areturn(); // .invokedynamic(DynamicCallSiteDesc.of(
// })) // bsmMhDesc,
// .withMethod("condy_bsm_condy_bsm", "()Ljava/lang/Object;", M -> // "name",
// M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) // MethodTypeDesc.of(ConstantDescs.CD_String),
// .withCode(TypedCodeBuilder::new, C -> // DynamicConstantDesc.ofNamed(
// C.ldc("name", "Ljava/lang/String;", genClassName, "bsm", bsmDescriptor, // bsmMhDesc,
// S -> S.add(null, (P, v) -> { // "name",
// return P.putDynamicConstant("name", "Ljava/lang/String;", genClassName, "bsm", bsmDescriptor, // ConstantDescs.CD_String,
// S2 -> S2.add("DUMMY_ARG", PoolHelper::putString)); // "DUMMY_ARG"
// })) // )
// .areturn())) // )
// .withMethod("indy_bsmIndy_condy_bsm", "()Ljava/lang/Object;", M -> // )
// M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) // .areturn()
// .withCode(TypedCodeBuilder::new, C -> // )
// C.invokedynamic("name", "()Ljava/lang/String;", genClassName, "bsmIndy", bsmIndyDescriptor, // )
// S -> S.add(null, (P, v) -> { // );
// return P.putDynamicConstant("name", "Ljava/lang/String;", genClassName, "bsm", bsmDescriptor,
// S2 -> S2.add("DUMMY_ARG", PoolHelper::putString));
// }))
// .areturn()))
// .withMethod("indy_bsm_condy_bsm", "()Ljava/lang/Object;", M ->
// M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
// .withCode(TypedCodeBuilder::new, C ->
// C.invokedynamic("name", "()Ljava/lang/String;", genClassName, "bsm", bsmDescriptor,
// S -> S.add(null, (P, v) -> {
// return P.putDynamicConstant("name", "Ljava/lang/String;", genClassName, "bsm", bsmDescriptor,
// S2 -> S2.add("DUMMY_ARG", PoolHelper::putString));
// }))
// .areturn()))
// .build();
// //
// File f = new File(genClassName + ".class"); // File f = new File(genClassName + ".class");
// if (f.getParentFile() != null) { // if (f.getParentFile() != null) {
@ -163,15 +245,13 @@ public class CondyNestedTest {
// } // }
// new FileOutputStream(f).write(byteArray); // new FileOutputStream(f).write(byteArray);
// return byteArray; // return byteArray;
//
// } // }
static void test(Method m, Class<? extends Throwable>... ts) { static void test(Method m, Class<? extends Throwable>... ts) {
Throwable caught = null; Throwable caught = null;
try { try {
m.invoke(null); m.invoke(null);
} } catch (Throwable t) {
catch (Throwable t) {
caught = t; caught = t;
} }

View file

@ -25,19 +25,22 @@
* @test * @test
* @bug 8186211 * @bug 8186211
* @summary Test basic invocation of multiple ldc's of the same dynamic constant that fail resolution * @summary Test basic invocation of multiple ldc's of the same dynamic constant that fail resolution
* @library /lib/testlibrary/bytecode /java/lang/invoke/common * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder * @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 CondyRepeatFailedResolution * @run testng CondyRepeatFailedResolution
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyRepeatFailedResolution * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyRepeatFailedResolution
*/ */
import jdk.experimental.bytecode.BasicClassBuilder; import jdk.internal.classfile.Classfile;
import jdk.experimental.bytecode.Flag;
import jdk.experimental.bytecode.TypedCodeBuilder;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.lang.constant.*;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -95,124 +98,194 @@ public class CondyRepeatFailedResolution {
@BeforeClass @BeforeClass
public void generateClass() throws Exception { public void generateClass() throws Exception {
String genClassName = CondyRepeatFailedResolution.class.getSimpleName() + "$Code"; String genClassName = CondyRepeatFailedResolution.class.getSimpleName() + "$Code";
String bsmClassName = CondyRepeatFailedResolution.class.getCanonicalName().replace('.', '/'); String bsmClassDesc = CondyRepeatFailedResolution.class.descriptorString();
String bsmMethodName = "intConversion"; String bsmMethodName = "intConversion";
String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class, String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class,
String.class, Class.class, int.class).toMethodDescriptorString(); String.class, Class.class, int.class).toMethodDescriptorString();
DirectMethodHandleDesc bsmMhDesc = MethodHandleDesc.of(
byte[] byteArray = new BasicClassBuilder(genClassName, 55, 0) DirectMethodHandleDesc.Kind.STATIC,
.withSuperclass("java/lang/Object") ClassDesc.ofDescriptor(bsmClassDesc),
.withMethod("<init>", "()V", M -> bsmMethodName,
M.withFlags(Flag.ACC_PUBLIC) bsmDescriptor
.withCode(TypedCodeBuilder::new, C -> );
C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_() byte[] byteArray = Classfile.of().build(ClassDesc.of(genClassName), classBuilder -> classBuilder
)) .withVersion(55, 0)
.withMethod("B", "()B", M -> .withSuperclass(ConstantDescs.CD_Object)
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, Classfile.ACC_PUBLIC,
.withCode(TypedCodeBuilder::new, C -> methodBuilder -> methodBuilder
C.ldc("B", "B", bsmClassName, bsmMethodName, bsmDescriptor, .withCode(codeBuilder -> codeBuilder
S -> S.add(Byte.MAX_VALUE)) .aload(0)
.ireturn() .invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME,
)) ConstantDescs.MTD_void, false)
.withMethod("C", "()C", M -> .return_()
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) )
.withCode(TypedCodeBuilder::new, C -> )
C.ldc("C", "C", bsmClassName, bsmMethodName, bsmDescriptor, .withMethod("B", MethodTypeDesc.of(ConstantDescs.CD_byte),
S -> S.add(Character.MAX_VALUE)) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.ireturn() .withCode(codeBuilder -> codeBuilder
)) .ldc(DynamicConstantDesc.ofNamed(
.withMethod("D", "()D", M -> bsmMhDesc,
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) "B",
.withCode(TypedCodeBuilder::new, C -> ConstantDescs.CD_byte,
C.ldc("D", "D", bsmClassName, bsmMethodName, bsmDescriptor, (int) Byte.MAX_VALUE))
S -> S.add(Integer.MAX_VALUE)) .ireturn()
.dreturn() )
)) )
.withMethod("D_AsType", "()D", M -> .withMethod("C", MethodTypeDesc.of(ConstantDescs.CD_char),
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(TypedCodeBuilder::new, C -> .withCode(codeBuilder -> codeBuilder
C.ldc("I", "D", bsmClassName, bsmMethodName, bsmDescriptor, .ldc(DynamicConstantDesc.ofNamed(
S -> S.add(Integer.MAX_VALUE)) bsmMhDesc,
.dreturn() "C",
)) ConstantDescs.CD_char,
.withMethod("F", "()F", M -> (int) Character.MAX_VALUE))
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .ireturn()
.withCode(TypedCodeBuilder::new, C -> )
C.ldc("F", "F", bsmClassName, bsmMethodName, bsmDescriptor, )
S -> S.add(Integer.MAX_VALUE)) .withMethod("D", MethodTypeDesc.of(ConstantDescs.CD_double),
.freturn() Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
)) .withCode(codeBuilder -> codeBuilder
.withMethod("F_AsType", "()F", M -> .ldc(DynamicConstantDesc.ofNamed(
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) bsmMhDesc,
.withCode(TypedCodeBuilder::new, C -> "D",
C.ldc("I", "F", bsmClassName, bsmMethodName, bsmDescriptor, ConstantDescs.CD_double,
S -> S.add(Integer.MAX_VALUE)) Integer.MAX_VALUE))
.freturn() .dreturn()
)) )
.withMethod("I", "()I", M -> )
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .withMethod("D_AsType", MethodTypeDesc.of(ConstantDescs.CD_double),
.withCode(TypedCodeBuilder::new, C -> Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
C.ldc("I", "I", bsmClassName, bsmMethodName, bsmDescriptor, .withCode(codeBuilder -> codeBuilder
S -> S.add(Integer.MAX_VALUE)) .ldc(DynamicConstantDesc.ofNamed(
.ireturn() bsmMhDesc,
)) "I",
.withMethod("J", "()J", M -> ConstantDescs.CD_double,
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) Integer.MAX_VALUE))
.withCode(TypedCodeBuilder::new, C -> .dreturn()
C.ldc("J", "J", bsmClassName, bsmMethodName, bsmDescriptor, )
S -> S.add(Integer.MAX_VALUE)) )
.lreturn() .withMethod("F", MethodTypeDesc.of(ConstantDescs.CD_float),
)) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withMethod("J_AsType", "()J", M -> .withCode(codeBuilder -> codeBuilder
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .ldc(DynamicConstantDesc.ofNamed(
.withCode(TypedCodeBuilder::new, C -> bsmMhDesc,
C.ldc("I", "J", bsmClassName, bsmMethodName, bsmDescriptor, "F",
S -> S.add(Integer.MAX_VALUE)) ConstantDescs.CD_float,
.lreturn() Integer.MAX_VALUE))
)) .freturn()
.withMethod("S", "()S", M -> )
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) )
.withCode(TypedCodeBuilder::new, C -> .withMethod("F_AsType", MethodTypeDesc.of(ConstantDescs.CD_float),
C.ldc("S", "S", bsmClassName, bsmMethodName, bsmDescriptor, Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
S -> S.add(Short.MAX_VALUE)) .withCode(codeBuilder -> codeBuilder
.ireturn() .ldc(DynamicConstantDesc.ofNamed(
)) bsmMhDesc,
.withMethod("Z_F", "()Z", M -> "I",
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) ConstantDescs.CD_float,
.withCode(TypedCodeBuilder::new, C -> Integer.MAX_VALUE))
C.ldc("Z", "Z", bsmClassName, bsmMethodName, bsmDescriptor, .freturn()
S -> S.add(0)) )
.ireturn() )
)) .withMethod("I", MethodTypeDesc.of(ConstantDescs.CD_int),
.withMethod("Z_T", "()Z", M -> Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .withCode(codeBuilder -> codeBuilder
.withCode(TypedCodeBuilder::new, C -> .ldc(DynamicConstantDesc.ofNamed(
C.ldc("Z", "Z", bsmClassName, bsmMethodName, bsmDescriptor, bsmMhDesc,
S -> S.add(1)) "I",
.ireturn() ConstantDescs.CD_int,
)) Integer.MAX_VALUE))
.withMethod("null", "()Ljava/lang/Object;", M -> .ireturn()
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) )
.withCode(TypedCodeBuilder::new, C -> )
C.ldc("nullRef", "Ljava/lang/Object;", bsmClassName, bsmMethodName, bsmDescriptor, .withMethod("J", MethodTypeDesc.of(ConstantDescs.CD_long),
S -> S.add(Integer.MAX_VALUE)) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.areturn() .withCode(codeBuilder -> codeBuilder
)) .ldc(DynamicConstantDesc.ofNamed(
.withMethod("string", "()Ljava/lang/String;", M -> bsmMhDesc,
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) "J",
.withCode(TypedCodeBuilder::new, C -> ConstantDescs.CD_long,
C.ldc("string", "Ljava/lang/String;", bsmClassName, bsmMethodName, bsmDescriptor, Integer.MAX_VALUE))
S -> S.add(Integer.MAX_VALUE)) .lreturn()
.areturn() )
)) )
.withMethod("stringArray", "()[Ljava/lang/String;", M -> .withMethod("J_AsType", MethodTypeDesc.of(ConstantDescs.CD_long),
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(TypedCodeBuilder::new, C -> .withCode(codeBuilder -> codeBuilder
C.ldc("stringArray", "[Ljava/lang/String;", bsmClassName, bsmMethodName, bsmDescriptor, .ldc(DynamicConstantDesc.ofNamed(
S -> S.add(Integer.MAX_VALUE)) bsmMhDesc,
.areturn() "I",
)) ConstantDescs.CD_long,
.build(); Integer.MAX_VALUE))
.lreturn()
)
)
.withMethod("S", MethodTypeDesc.of(ConstantDescs.CD_short),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"S",
ConstantDescs.CD_short,
((int) Short.MAX_VALUE)))
.ireturn()
)
)
.withMethod("Z_F", MethodTypeDesc.of(ConstantDescs.CD_boolean),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"Z",
ConstantDescs.CD_boolean,
0))
.ireturn()
)
)
.withMethod("Z_T", MethodTypeDesc.of(ConstantDescs.CD_boolean),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"Z",
ConstantDescs.CD_boolean,
1))
.ireturn()
)
)
.withMethod("null", MethodTypeDesc.of(ConstantDescs.CD_Object),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"nullRef",
ConstantDescs.CD_Object,
Integer.MAX_VALUE))
.areturn()
)
)
.withMethod("string", MethodTypeDesc.of(ConstantDescs.CD_String),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"string",
ConstantDescs.CD_String,
Integer.MAX_VALUE))
.areturn()
)
)
.withMethod("stringArray", MethodTypeDesc.of(ConstantDescs.CD_String.arrayType()),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"stringArray",
ConstantDescs.CD_String.arrayType(),
Integer.MAX_VALUE))
.areturn()
)
)
);
gc = MethodHandles.lookup().defineClass(byteArray); gc = MethodHandles.lookup().defineClass(byteArray);
} }

View file

@ -25,19 +25,21 @@
* @test * @test
* @bug 8186046 * @bug 8186046
* @summary Test for condy BSMs returning primitive values or null * @summary Test for condy BSMs returning primitive values or null
* @library /lib/testlibrary/bytecode * @modules java.base/jdk.internal.classfile
* @build jdk.experimental.bytecode.BasicClassBuilder * 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 CondyReturnPrimitiveTest * @run testng CondyReturnPrimitiveTest
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyReturnPrimitiveTest * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyReturnPrimitiveTest
*/ */
import jdk.experimental.bytecode.BasicClassBuilder; import jdk.internal.classfile.Classfile;
import jdk.experimental.bytecode.Flag;
import jdk.experimental.bytecode.TypedCodeBuilder;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.lang.constant.*;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -96,124 +98,194 @@ public class CondyReturnPrimitiveTest {
@BeforeClass @BeforeClass
public void generateClass() throws Exception { public void generateClass() throws Exception {
String genClassName = CondyReturnPrimitiveTest.class.getSimpleName() + "$Code"; String genClassName = CondyReturnPrimitiveTest.class.getSimpleName() + "$Code";
String bsmClassName = CondyReturnPrimitiveTest.class.getCanonicalName().replace('.', '/'); String bsmClassDesc = CondyReturnPrimitiveTest.class.descriptorString();
String bsmMethodName = "intConversion"; String bsmMethodName = "intConversion";
String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class, String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class,
String.class, Class.class, int.class).toMethodDescriptorString(); String.class, Class.class, int.class).toMethodDescriptorString();
DirectMethodHandleDesc bsmMhDesc = MethodHandleDesc.of(
byte[] byteArray = new BasicClassBuilder(genClassName, 55, 0) DirectMethodHandleDesc.Kind.STATIC,
.withSuperclass("java/lang/Object") ClassDesc.ofDescriptor(bsmClassDesc),
.withMethod("<init>", "()V", M -> bsmMethodName,
M.withFlags(Flag.ACC_PUBLIC) bsmDescriptor
.withCode(TypedCodeBuilder::new, C -> );
C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_() byte[] byteArray = Classfile.of().build(ClassDesc.of(genClassName), classBuilder -> classBuilder
)) .withVersion(55, 0)
.withMethod("B", "()B", M -> .withSuperclass(ConstantDescs.CD_Object)
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, Classfile.ACC_PUBLIC,
.withCode(TypedCodeBuilder::new, C -> methodBuilder -> methodBuilder
C.ldc("B", "B", bsmClassName, bsmMethodName, bsmDescriptor, .withCode(codeBuilder -> codeBuilder
S -> S.add(Byte.MAX_VALUE)) .aload(0)
.ireturn() .invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME,
)) ConstantDescs.MTD_void, false)
.withMethod("C", "()C", M -> .return_()
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) )
.withCode(TypedCodeBuilder::new, C -> )
C.ldc("C", "C", bsmClassName, bsmMethodName, bsmDescriptor, .withMethod("B", MethodTypeDesc.of(ConstantDescs.CD_byte),
S -> S.add(Character.MAX_VALUE)) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.ireturn() .withCode(codeBuilder -> codeBuilder
)) .ldc(DynamicConstantDesc.ofNamed(
.withMethod("D", "()D", M -> bsmMhDesc,
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) "B",
.withCode(TypedCodeBuilder::new, C -> ConstantDescs.CD_byte,
C.ldc("D", "D", bsmClassName, bsmMethodName, bsmDescriptor, (int) Byte.MAX_VALUE))
S -> S.add(Integer.MAX_VALUE)) .ireturn()
.dreturn() )
)) )
.withMethod("D_AsType", "()D", M -> .withMethod("C", MethodTypeDesc.of(ConstantDescs.CD_char),
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(TypedCodeBuilder::new, C -> .withCode(codeBuilder -> codeBuilder
C.ldc("I", "D", bsmClassName, bsmMethodName, bsmDescriptor, .ldc(DynamicConstantDesc.ofNamed(
S -> S.add(Integer.MAX_VALUE)) bsmMhDesc,
.dreturn() "C",
)) ConstantDescs.CD_char,
.withMethod("F", "()F", M -> (int) Character.MAX_VALUE))
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .ireturn()
.withCode(TypedCodeBuilder::new, C -> )
C.ldc("F", "F", bsmClassName, bsmMethodName, bsmDescriptor, )
S -> S.add(Integer.MAX_VALUE)) .withMethod("D", MethodTypeDesc.of(ConstantDescs.CD_double),
.freturn() Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
)) .withCode(codeBuilder -> codeBuilder
.withMethod("F_AsType", "()F", M -> .ldc(DynamicConstantDesc.ofNamed(
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) bsmMhDesc,
.withCode(TypedCodeBuilder::new, C -> "D",
C.ldc("I", "F", bsmClassName, bsmMethodName, bsmDescriptor, ConstantDescs.CD_double,
S -> S.add(Integer.MAX_VALUE)) Integer.MAX_VALUE))
.freturn() .dreturn()
)) )
.withMethod("I", "()I", M -> )
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .withMethod("D_AsType", MethodTypeDesc.of(ConstantDescs.CD_double),
.withCode(TypedCodeBuilder::new, C -> Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
C.ldc("I", "I", bsmClassName, bsmMethodName, bsmDescriptor, .withCode(codeBuilder -> codeBuilder
S -> S.add(Integer.MAX_VALUE)) .ldc(DynamicConstantDesc.ofNamed(
.ireturn() bsmMhDesc,
)) "I",
.withMethod("J", "()J", M -> ConstantDescs.CD_double,
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) Integer.MAX_VALUE))
.withCode(TypedCodeBuilder::new, C -> .dreturn()
C.ldc("J", "J", bsmClassName, bsmMethodName, bsmDescriptor, )
S -> S.add(Integer.MAX_VALUE)) )
.lreturn() .withMethod("F", MethodTypeDesc.of(ConstantDescs.CD_float),
)) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withMethod("J_AsType", "()J", M -> .withCode(codeBuilder -> codeBuilder
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .ldc(DynamicConstantDesc.ofNamed(
.withCode(TypedCodeBuilder::new, C -> bsmMhDesc,
C.ldc("I", "J", bsmClassName, bsmMethodName, bsmDescriptor, "F",
S -> S.add(Integer.MAX_VALUE)) ConstantDescs.CD_float,
.lreturn() Integer.MAX_VALUE))
)) .freturn()
.withMethod("S", "()S", M -> )
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) )
.withCode(TypedCodeBuilder::new, C -> .withMethod("F_AsType", MethodTypeDesc.of(ConstantDescs.CD_float),
C.ldc("S", "S", bsmClassName, bsmMethodName, bsmDescriptor, Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
S -> S.add(Short.MAX_VALUE)) .withCode(codeBuilder -> codeBuilder
.ireturn() .ldc(DynamicConstantDesc.ofNamed(
)) bsmMhDesc,
.withMethod("Z_F", "()Z", M -> "I",
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) ConstantDescs.CD_float,
.withCode(TypedCodeBuilder::new, C -> Integer.MAX_VALUE))
C.ldc("Z", "Z", bsmClassName, bsmMethodName, bsmDescriptor, .freturn()
S -> S.add(0)) )
.ireturn() )
)) .withMethod("I", MethodTypeDesc.of(ConstantDescs.CD_int),
.withMethod("Z_T", "()Z", M -> Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .withCode(codeBuilder -> codeBuilder
.withCode(TypedCodeBuilder::new, C -> .ldc(DynamicConstantDesc.ofNamed(
C.ldc("Z", "Z", bsmClassName, bsmMethodName, bsmDescriptor, bsmMhDesc,
S -> S.add(1)) "I",
.ireturn() ConstantDescs.CD_int,
)) Integer.MAX_VALUE))
.withMethod("null", "()Ljava/lang/Object;", M -> .ireturn()
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) )
.withCode(TypedCodeBuilder::new, C -> )
C.ldc("nullRef", "Ljava/lang/Object;", bsmClassName, bsmMethodName, bsmDescriptor, .withMethod("J", MethodTypeDesc.of(ConstantDescs.CD_long),
S -> S.add(Integer.MAX_VALUE)) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.areturn() .withCode(codeBuilder -> codeBuilder
)) .ldc(DynamicConstantDesc.ofNamed(
.withMethod("string", "()Ljava/lang/String;", M -> bsmMhDesc,
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) "J",
.withCode(TypedCodeBuilder::new, C -> ConstantDescs.CD_long,
C.ldc("string", "Ljava/lang/String;", bsmClassName, bsmMethodName, bsmDescriptor, Integer.MAX_VALUE))
S -> S.add(Integer.MAX_VALUE)) .lreturn()
.areturn() )
)) )
.withMethod("stringArray", "()[Ljava/lang/String;", M -> .withMethod("J_AsType", MethodTypeDesc.of(ConstantDescs.CD_long),
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(TypedCodeBuilder::new, C -> .withCode(codeBuilder -> codeBuilder
C.ldc("stringArray", "[Ljava/lang/String;", bsmClassName, bsmMethodName, bsmDescriptor, .ldc(DynamicConstantDesc.ofNamed(
S -> S.add(Integer.MAX_VALUE)) bsmMhDesc,
.areturn() "I",
)) ConstantDescs.CD_long,
.build(); Integer.MAX_VALUE))
.lreturn()
)
)
.withMethod("S", MethodTypeDesc.of(ConstantDescs.CD_short),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"S",
ConstantDescs.CD_short,
((int) Short.MAX_VALUE)))
.ireturn()
)
)
.withMethod("Z_F", MethodTypeDesc.of(ConstantDescs.CD_boolean),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"Z",
ConstantDescs.CD_boolean,
0))
.ireturn()
)
)
.withMethod("Z_T", MethodTypeDesc.of(ConstantDescs.CD_boolean),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"Z",
ConstantDescs.CD_boolean,
1))
.ireturn()
)
)
.withMethod("null", MethodTypeDesc.of(ConstantDescs.CD_Object),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"nullRef",
ConstantDescs.CD_Object,
Integer.MAX_VALUE))
.areturn()
)
)
.withMethod("string", MethodTypeDesc.of(ConstantDescs.CD_String),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"string",
ConstantDescs.CD_String,
Integer.MAX_VALUE))
.areturn()
)
)
.withMethod("stringArray", MethodTypeDesc.of(ConstantDescs.CD_String.arrayType()),
Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.withCode(codeBuilder -> codeBuilder
.ldc(DynamicConstantDesc.ofNamed(
bsmMhDesc,
"stringArray",
ConstantDescs.CD_String.arrayType(),
Integer.MAX_VALUE))
.areturn()
)
)
);
gc = MethodHandles.lookup().defineClass(byteArray); gc = MethodHandles.lookup().defineClass(byteArray);
} }

View file

@ -25,22 +25,23 @@
* @test * @test
* @bug 8186046 * @bug 8186046
* @summary Test bootstrap arguments for condy * @summary Test bootstrap arguments for condy
* @library /lib/testlibrary/bytecode /java/lang/invoke/common * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper * @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 CondyStaticArgumentsTest * @run testng CondyStaticArgumentsTest
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyStaticArgumentsTest * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyStaticArgumentsTest
*/ */
import jdk.experimental.bytecode.PoolHelper;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import test.java.lang.invoke.lib.InstructionHelper; import test.java.lang.invoke.lib.InstructionHelper;
import java.lang.invoke.ConstantCallSite; import java.lang.constant.*;
import java.lang.invoke.MethodHandle; import java.lang.invoke.*;
import java.lang.invoke.MethodHandleInfo;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.MathContext; import java.math.MathContext;
@ -51,6 +52,8 @@ import static java.lang.invoke.MethodType.methodType;
public class CondyStaticArgumentsTest { public class CondyStaticArgumentsTest {
static final MethodHandles.Lookup L = MethodHandles.lookup(); static final MethodHandles.Lookup L = MethodHandles.lookup();
private static final DirectMethodHandleDesc bigDecimalMhDesc = directMhDesc("bigDecimal");
private static final DirectMethodHandleDesc mathContextMhDesc = directMhDesc("mathContext");
static class BSMInfo { static class BSMInfo {
final String methodName; final String methodName;
@ -65,8 +68,7 @@ public class CondyStaticArgumentsTest {
.get(); .get();
try { try {
handle = MethodHandles.lookup().unreflect(m); handle = MethodHandles.lookup().unreflect(m);
} } catch (Exception e) {
catch (Exception e) {
throw new Error(e); throw new Error(e);
} }
descriptor = handle.type().toMethodDescriptorString(); descriptor = handle.type().toMethodDescriptorString();
@ -103,18 +105,18 @@ public class CondyStaticArgumentsTest {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "constant-name", String.class, L, "constant-name", String.class,
bi.methodName, bi.handle.type(), bi.methodName, bi.handle.type(),
S -> S.add(1).add(2L).add(3.0f).add(4.0d) 1, 2L, 3.0f, 4.0d,
.add("java/lang/Number", PoolHelper::putClass) ClassDesc.ofDescriptor(Number.class.descriptorString()),
.add("something", PoolHelper::putString) "something",
.add("(IJFD)V", PoolHelper::putMethodType) MethodTypeDesc.ofDescriptor("(IJFD)V"),
.add(mhi, (P, Z) -> { MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.valueOf(mhi.getReferenceKind()),
return P.putHandle(mhi.getReferenceKind(), "CondyStaticArgumentsTest", mhi.getName(), bi.descriptor); ClassDesc.ofDescriptor(mhi.getDeclaringClass().descriptorString()),
})); mhi.getName(), MethodTypeDesc.ofDescriptor(mhi.getMethodType().descriptorString()))
);
Assert.assertEquals(mh.invoke(), "constant-name-String-1-2-3.0-4.0-Number-something-(int,long,float,double)void-11"); Assert.assertEquals(mh.invoke(), "constant-name-String-1-2-3.0-4.0-Number-something-(int,long,float,double)void-11");
} }
static MathContext mathContext(MethodHandles.Lookup l, String value, Class<?> type) { static MathContext mathContext(MethodHandles.Lookup l, String value, Class<?> type) {
switch (value) { switch (value) {
case "UNLIMITED": case "UNLIMITED":
@ -145,22 +147,6 @@ public class CondyStaticArgumentsTest {
.toString(); .toString();
} }
static <E> int bigDecimalPoolHelper(String value, String mc, PoolHelper<String, String, E> P) {
BSMInfo bi = BSMInfo.of("bigDecimal");
return P.putDynamicConstant("big-decimal", "Ljava/math/BigDecimal;", InstructionHelper.csym(L.lookupClass()), bi.methodName, bi.descriptor,
S -> S.add(value, PoolHelper::putString)
.add(mc, (P2, s) -> {
return mathContextPoolHelper(s, P2);
}));
}
static <E> int mathContextPoolHelper(String mc, PoolHelper<String, String, E> P) {
BSMInfo bi = BSMInfo.of("mathContext");
return P.putDynamicConstant(mc, "Ljava/math/MathContext;", InstructionHelper.csym(L.lookupClass()), bi.methodName, bi.descriptor,
S -> {
});
}
@Test @Test
public void testCondyWithCondy() throws Throwable { public void testCondyWithCondy() throws Throwable {
BSMInfo bi = BSMInfo.of("condyWithCondy"); BSMInfo bi = BSMInfo.of("condyWithCondy");
@ -168,9 +154,18 @@ public class CondyStaticArgumentsTest {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "big-decimal-math-context", String.class, L, "big-decimal-math-context", String.class,
bi.methodName, bi.handle.type(), bi.methodName, bi.handle.type(),
S -> S.add(null, (P, v) -> { DynamicConstantDesc.ofNamed(
return bigDecimalPoolHelper("3.14159265358979323846", "DECIMAL32", P); bigDecimalMhDesc,
})); "big-decimal",
InstructionHelper.classDesc(BigDecimal.class),
"3.14159265358979323846",
DynamicConstantDesc.ofNamed(
mathContextMhDesc,
"DECIMAL32",
InstructionHelper.classDesc(MathContext.class)
)
)
);
Assert.assertEquals(mh.invoke(), "big-decimal-math-context-String-3.141593-7"); Assert.assertEquals(mh.invoke(), "big-decimal-math-context-String-3.141593-7");
} }
@ -193,9 +188,27 @@ public class CondyStaticArgumentsTest {
MethodHandle mh = InstructionHelper.invokedynamic( MethodHandle mh = InstructionHelper.invokedynamic(
L, "big-decimal-math-context", methodType(String.class), L, "big-decimal-math-context", methodType(String.class),
bi.methodName, bi.handle.type(), bi.methodName, bi.handle.type(),
S -> S.add(null, (P, v) -> { DynamicConstantDesc.ofNamed(
return bigDecimalPoolHelper("3.14159265358979323846", "DECIMAL32", P); bigDecimalMhDesc,
})); "big-decimal",
InstructionHelper.classDesc(BigDecimal.class),
"3.14159265358979323846",
DynamicConstantDesc.ofNamed(
mathContextMhDesc,
"DECIMAL32",
InstructionHelper.classDesc(MathContext.class)
)
));
Assert.assertEquals(mh.invoke(), "big-decimal-math-context-()Ljava/lang/String;-3.141593-7"); Assert.assertEquals(mh.invoke(), "big-decimal-math-context-()Ljava/lang/String;-3.141593-7");
} }
private static DirectMethodHandleDesc directMhDesc(String methodName) {
MethodHandleInfo mhi = MethodHandles.lookup().revealDirect(BSMInfo.of(methodName).handle);
return MethodHandleDesc.of(
DirectMethodHandleDesc.Kind.valueOf(mhi.getReferenceKind()),
ClassDesc.ofDescriptor(mhi.getDeclaringClass().descriptorString()),
mhi.getName(),
mhi.getMethodType().descriptorString()
);
}
} }

View file

@ -25,11 +25,17 @@
* @test * @test
* @bug 8186046 * @bug 8186046
* @summary Test invalid name in name and type * @summary Test invalid name in name and type
* @library /lib/testlibrary/bytecode /java/lang/invoke/common * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper * @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/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyTypeValidationTest * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyTypeValidationTest
*/ */
import org.testng.Assert;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import test.java.lang.invoke.lib.InstructionHelper; import test.java.lang.invoke.lib.InstructionHelper;
@ -49,29 +55,36 @@ public class CondyTypeValidationTest {
.toMethodDescriptorString(); .toMethodDescriptorString();
@DataProvider @DataProvider
public Object[][] invalidTypesProvider() throws Exception { public Object[][] invalidTypesProvider() {
return Stream.of( return Stream.of(
// ByteCode API checks for the following invalid types // ByteCode API checks for the following invalid types
// "", // "",
// "[", // "[",
// "A", // "A",
// "a", // "a",
"L/java/lang/Object", new Object[]{"L/java/lang/Object", "not a valid reference type descriptor"},
Stream.generate(() -> "[").limit(256).collect(Collectors.joining("", "", "I"))) new Object[]{
.map(e -> new Object[]{e}).toArray(Object[][]::new); Stream.generate(() -> "[").limit(256)
.collect(Collectors.joining("", "", "I")),
"Cannot create an array type descriptor with more than 255 dimensions"
}
).toArray(Object[][]::new);
} }
@Test(dataProvider = "invalidTypesProvider", expectedExceptions = ClassFormatError.class) @Test(dataProvider = "invalidTypesProvider")
public void testInvalidTypes(String type) throws Exception { public void testInvalidTypes(String type, String errMessContent) throws Exception {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( try {
L, "name", type, MethodHandle mh = InstructionHelper.ldcDynamicConstant(
"bsm", BSM_TYPE, L, "name", type,
S -> { "bsm", BSM_TYPE
}); );
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage().contains(errMessContent));
}
} }
@DataProvider @DataProvider
public Object[][] validTypesProvider() throws Exception { public Object[][] validTypesProvider() {
List<String> t = new ArrayList<>(List.of("B", "C", "D", "F", "I", "J", "Ljava/lang/Object;", "S", "Z")); List<String> t = new ArrayList<>(List.of("B", "C", "D", "F", "I", "J", "Ljava/lang/Object;", "S", "Z"));
int l = t.size(); int l = t.size();
for (int i = 0; i < l; i++) { for (int i = 0; i < l; i++) {
@ -86,8 +99,7 @@ public class CondyTypeValidationTest {
public void testValidTypes(String type) throws Exception { public void testValidTypes(String type) throws Exception {
MethodHandle mh = InstructionHelper.ldcDynamicConstant( MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", type, L, "name", type,
"bsm", BSM_TYPE, "bsm", BSM_TYPE
S -> { );
});
} }
} }

View file

@ -25,25 +25,29 @@
* @test * @test
* @bug 8186046 * @bug 8186046
* @summary Stress test ldc to ensure HotSpot correctly manages oop maps * @summary Stress test ldc to ensure HotSpot correctly manages oop maps
* @library /lib/testlibrary/bytecode /java/lang/invoke/common * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper * @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 CondyWithGarbageTest * @run testng CondyWithGarbageTest
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyWithGarbageTest * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyWithGarbageTest
*/ */
import jdk.experimental.bytecode.BasicClassBuilder; import jdk.internal.classfile.Classfile;
import jdk.experimental.bytecode.Flag; import jdk.internal.classfile.CodeBuilder;
import jdk.experimental.bytecode.TypedCodeBuilder;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.lang.constant.*;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import static java.lang.invoke.MethodType.methodType; import static java.lang.invoke.MethodType.methodType;
import static test.java.lang.invoke.lib.InstructionHelper.cref; import static test.java.lang.invoke.lib.InstructionHelper.classDesc;
import static test.java.lang.invoke.lib.InstructionHelper.csym;
public class CondyWithGarbageTest { public class CondyWithGarbageTest {
static final MethodHandles.Lookup L = MethodHandles.lookup(); static final MethodHandles.Lookup L = MethodHandles.lookup();
@ -65,46 +69,65 @@ public class CondyWithGarbageTest {
} }
static MethodHandle lcdStringBasher() throws Exception { static MethodHandle lcdStringBasher() throws Exception {
byte[] byteArray = new BasicClassBuilder(csym(L.lookupClass()) + "$Code$String", 55, 0) ClassDesc cd = classDesc(L.lookupClass(), "$Code$String");
.withSuperclass("java/lang/Object") byte[] bytes = Classfile.of().build(cd, classBuilder -> classBuilder
.withMethod("<init>", "()V", M -> .withVersion(55, 0)
M.withFlags(Flag.ACC_PUBLIC) .withSuperclass(ConstantDescs.CD_Object)
.withCode(TypedCodeBuilder::new, C -> .withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, Classfile.ACC_PUBLIC,
C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_() methodBuilder -> methodBuilder
)) .withCode(codeBuilder -> codeBuilder
.withMethod("m", "()" + cref(String.class), M -> .aload(0)
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME,
.withCode(TypedCodeBuilder::new, C -> { ConstantDescs.MTD_void, false)
C.new_(csym(StringBuilder.class)) .return_()))
.dup() .withMethod("m", MethodTypeDesc.of(ConstantDescs.CD_String),
.invokespecial(csym(StringBuilder.class), "<init>", "()V", false) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.astore_0(); .withCode(codeBuilder -> {
codeBuilder
.new_(classDesc(StringBuilder.class))
.dup()
.invokespecial(classDesc(StringBuilder.class), ConstantDescs.INIT_NAME,
ConstantDescs.MTD_void, false)
.astore(0);
for (int i = 10; i < 100; i++) { for (int i = 10; i < 100; i++) {
ldcString(C, Integer.toString(i)); ldcString(codeBuilder, Integer.toString(i));
C.astore_1().aload_0().aload_1(); codeBuilder
C.invokevirtual(csym(StringBuilder.class), "append", methodType(StringBuilder.class, String.class).toMethodDescriptorString(), false); .astore(1)
C.pop(); .aload(0)
} .aload(1)
.invokevirtual(
classDesc(StringBuilder.class),
"append",
MethodTypeDesc.of(
classDesc(StringBuilder.class),
classDesc(String.class)))
.pop();
}
C.aload_0(); codeBuilder
C.invokevirtual(csym(StringBuilder.class), "toString", methodType(String.class).toMethodDescriptorString(), false); .aload(0)
C.areturn(); .invokevirtual(
} classDesc(StringBuilder.class),
)) "toString",
.build(); MethodTypeDesc.of(classDesc(String.class)))
.areturn();
Class<?> gc = L.defineClass(byteArray); }
)));
Class<?> gc = L.defineClass(bytes);
return L.findStatic(gc, "m", methodType(String.class)); return L.findStatic(gc, "m", methodType(String.class));
} }
static void ldcString(TypedCodeBuilder<String, String, byte[], ?> C, String name) { private static void ldcString(CodeBuilder codeBuilder, String name) {
C.ldc(name, cref(String.class), codeBuilder.ldc(DynamicConstantDesc.ofNamed(
csym(L.lookupClass()), MethodHandleDesc.of(
"bsmString", DirectMethodHandleDesc.Kind.STATIC,
methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class).toMethodDescriptorString(), classDesc(L.lookupClass()),
S -> { "bsmString",
}); methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class).toMethodDescriptorString()),
name,
classDesc(String.class)
));
} }
@ -125,46 +148,67 @@ public class CondyWithGarbageTest {
} }
static MethodHandle lcdStringArrayBasher() throws Exception { static MethodHandle lcdStringArrayBasher() throws Exception {
byte[] byteArray = new BasicClassBuilder(csym(L.lookupClass()) + "$Code$StringArray", 55, 0) ClassDesc cd = classDesc(L.lookupClass(), "$Code$StringArray");
.withSuperclass("java/lang/Object") byte[] bytes = Classfile.of().build(cd, classBuilder -> classBuilder
.withMethod("<init>", "()V", M -> .withVersion(55, 0)
M.withFlags(Flag.ACC_PUBLIC) .withSuperclass(ConstantDescs.CD_Object)
.withCode(TypedCodeBuilder::new, C -> .withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, Classfile.ACC_PUBLIC,
C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_() methodBuilder -> methodBuilder
)) .withCode(codeBuilder -> codeBuilder
.withMethod("m", "()" + cref(String.class), M -> .aload(0)
M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) .invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME,
.withCode(TypedCodeBuilder::new, C -> { ConstantDescs.MTD_void, false)
C.new_(csym(StringBuilder.class)) .return_()))
.dup() .withMethod("m", MethodTypeDesc.of(classDesc(String.class)),
.invokespecial(csym(StringBuilder.class), "<init>", "()V", false) Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
.astore_0(); .withCode(codeBuilder -> {
codeBuilder
.new_(classDesc(StringBuilder.class))
.dup()
.invokespecial(classDesc(StringBuilder.class),
ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, false)
.astore(0);
for (int i = 10; i < 100; i++) { for (int i = 10; i < 100; i++) {
ldcStringArray(C, Integer.toString(i)); ldcStringArray(codeBuilder, Integer.toString(i));
C.bipush(0).aaload().astore_1(); codeBuilder
C.aload_0().aload_1(); .bipush(0)
C.invokevirtual(csym(StringBuilder.class), "append", methodType(StringBuilder.class, String.class).toMethodDescriptorString(), false); .aaload()
C.pop(); .astore(1)
} .aload(0)
.aload(1)
.invokevirtual(
classDesc(StringBuilder.class),
"append",
MethodTypeDesc.of(
classDesc(StringBuilder.class),
classDesc(String.class)))
.pop();
}
C.aload_0(); codeBuilder
C.invokevirtual(csym(StringBuilder.class), "toString", methodType(String.class).toMethodDescriptorString(), false); .aload(0)
C.areturn(); .invokevirtual(
} classDesc(StringBuilder.class),
)) "toString",
.build(); MethodTypeDesc.of(classDesc(String.class)))
.areturn();
Class<?> gc = L.defineClass(byteArray); }
)));
Class<?> gc = L.defineClass(bytes);
return L.findStatic(gc, "m", methodType(String.class)); return L.findStatic(gc, "m", methodType(String.class));
} }
static void ldcStringArray(TypedCodeBuilder<String, String, byte[], ?> C, String name) { static void ldcStringArray(CodeBuilder codeBuilder, String name) {
C.ldc(name, cref(String[].class), codeBuilder.ldc(DynamicConstantDesc.ofNamed(
csym(L.lookupClass()), MethodHandleDesc.of(
"bsmStringArray", DirectMethodHandleDesc.Kind.STATIC,
methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class).toMethodDescriptorString(), classDesc(L.lookupClass()),
S -> { "bsmStringArray",
}); methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class).toMethodDescriptorString()
),
name,
classDesc(String[].class)
));
} }
} }

View file

@ -25,8 +25,13 @@
* @test * @test
* @bug 8186046 * @bug 8186046
* @summary Test bootstrap methods returning the wrong type * @summary Test bootstrap methods returning the wrong type
* @library /lib/testlibrary/bytecode /java/lang/invoke/common * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper * @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 CondyWrongType * @run testng CondyWrongType
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyWrongType * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyWrongType
*/ */
@ -60,7 +65,7 @@ public class CondyWrongType {
"J", long.class, "J", long.class,
"S", short.class, "S", short.class,
"Z", boolean.class "Z", boolean.class
); );
List<Object[]> cases = new ArrayList<>(); List<Object[]> cases = new ArrayList<>();
for (String name : typeMap.keySet()) { for (String name : typeMap.keySet()) {
@ -71,11 +76,10 @@ public class CondyWrongType {
boolean pass = true; boolean pass = true;
try { try {
zero.asType(MethodType.methodType(typeMap.get(type))); zero.asType(MethodType.methodType(typeMap.get(type)));
} } catch (WrongMethodTypeException e) {
catch (WrongMethodTypeException e) {
pass = false; pass = false;
} }
cases.add(new Object[] { name, type, pass}); cases.add(new Object[]{name, type, pass});
} }
} }
@ -110,20 +114,17 @@ public class CondyWrongType {
Throwable caught = null; Throwable caught = null;
try { try {
mh.invoke(); mh.invoke();
} } catch (Throwable t) {
catch (Throwable t) {
caught = t; caught = t;
} }
if (caught == null) { if (caught == null) {
if (pass) { if (pass) {
return; return;
} } else {
else {
Assert.fail("Throwable expected"); Assert.fail("Throwable expected");
} }
} } else if (pass) {
else if (pass) {
Assert.fail("Throwable not expected"); Assert.fail("Throwable not expected");
} }
@ -165,8 +166,8 @@ public class CondyWrongType {
return InstructionHelper.ldcDynamicConstant( return InstructionHelper.ldcDynamicConstant(
MethodHandles.lookup(), MethodHandles.lookup(),
name, type, name, type,
"bsm", methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class).toMethodDescriptorString(), "bsm",
S -> { }); methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class).descriptorString());
} catch (Exception e) { } catch (Exception e) {
throw new Error(e); throw new Error(e);
} }

View file

@ -25,23 +25,24 @@
* @test * @test
* @bug 8186046 8195694 * @bug 8186046 8195694
* @summary Test dynamic constant bootstraps * @summary Test dynamic constant bootstraps
* @library /lib/testlibrary/bytecode /java/lang/invoke/common * @library /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper * @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 ConstantBootstrapsTest * @run testng ConstantBootstrapsTest
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 ConstantBootstrapsTest * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 ConstantBootstrapsTest
*/ */
import jdk.experimental.bytecode.PoolHelper;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import test.java.lang.invoke.lib.InstructionHelper; import test.java.lang.invoke.lib.InstructionHelper;
import java.lang.invoke.ConstantBootstraps; import java.lang.constant.ConstantDescs;
import java.lang.invoke.MethodHandle; import java.lang.constant.DirectMethodHandleDesc;
import java.lang.invoke.MethodHandleInfo; import java.lang.constant.MethodHandleDesc;
import java.lang.invoke.MethodHandles; import java.lang.invoke.*;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.lang.invoke.WrongMethodTypeException;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -61,13 +62,11 @@ public class ConstantBootstrapsTest {
public void testNullConstant() throws Throwable { public void testNullConstant() throws Throwable {
var handle = InstructionHelper.ldcDynamicConstant(L, "_", Object.class, var handle = InstructionHelper.ldcDynamicConstant(L, "_", Object.class,
ConstantBootstraps.class, "nullConstant", lookupMT(Object.class), ConstantBootstraps.class, "nullConstant", lookupMT(Object.class));
S -> {});
assertNull(handle.invoke()); assertNull(handle.invoke());
handle = InstructionHelper.ldcDynamicConstant(L, "_", MethodType.class, handle = InstructionHelper.ldcDynamicConstant(L, "_", MethodType.class,
ConstantBootstraps.class, "nullConstant", lookupMT(Object.class), ConstantBootstraps.class, "nullConstant", lookupMT(Object.class));
S -> {});
assertNull(handle.invoke()); assertNull(handle.invoke());
} }
@ -92,8 +91,7 @@ public class ConstantBootstrapsTest {
for (var desc : pm.keySet()) { for (var desc : pm.keySet()) {
var handle = InstructionHelper.ldcDynamicConstant(L, desc, Class.class, var handle = InstructionHelper.ldcDynamicConstant(L, desc, Class.class,
ConstantBootstraps.class, "primitiveClass", lookupMT(Class.class), ConstantBootstraps.class, "primitiveClass", lookupMT(Class.class));
S -> {});
assertEquals(handle.invoke(), pm.get(desc)); assertEquals(handle.invoke(), pm.get(desc));
} }
} }
@ -127,8 +125,7 @@ public class ConstantBootstrapsTest {
public void testEnumConstant() throws Throwable { public void testEnumConstant() throws Throwable {
for (var v : StackWalker.Option.values()) { for (var v : StackWalker.Option.values()) {
var handle = InstructionHelper.ldcDynamicConstant(L, v.name(), StackWalker.Option.class, var handle = InstructionHelper.ldcDynamicConstant(L, v.name(), StackWalker.Option.class,
ConstantBootstraps.class, "enumConstant", lookupMT(Enum.class), ConstantBootstraps.class, "enumConstant", lookupMT(Enum.class));
S -> { });
assertEquals(handle.invoke(), v); assertEquals(handle.invoke(), v);
} }
} }
@ -141,21 +138,19 @@ public class ConstantBootstrapsTest {
public void testGetStaticDecl() throws Throwable { public void testGetStaticDecl() throws Throwable {
var handle = InstructionHelper.ldcDynamicConstant(L, "TYPE", Class.class, var handle = InstructionHelper.ldcDynamicConstant(L, "TYPE", Class.class,
ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class, Class.class), ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class, Class.class),
S -> { S.add("java/lang/Integer", PoolHelper::putClass); }); InstructionHelper.classDesc(Integer.class));
assertEquals(handle.invoke(), int.class); assertEquals(handle.invoke(), int.class);
} }
public void testGetStaticSelf() throws Throwable { public void testGetStaticSelf() throws Throwable {
var handle = InstructionHelper.ldcDynamicConstant(L, "MAX_VALUE", int.class, var handle = InstructionHelper.ldcDynamicConstant(L, "MAX_VALUE", int.class,
ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class), ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class));
S -> { });
assertEquals(handle.invoke(), Integer.MAX_VALUE); assertEquals(handle.invoke(), Integer.MAX_VALUE);
handle = InstructionHelper.ldcDynamicConstant(L, "ZERO", BigInteger.class, handle = InstructionHelper.ldcDynamicConstant(L, "ZERO", BigInteger.class,
ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class), ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class));
S -> { });
assertEquals(handle.invoke(), BigInteger.ZERO); assertEquals(handle.invoke(), BigInteger.ZERO);
} }
@ -164,14 +159,10 @@ public class ConstantBootstrapsTest {
var handle = InstructionHelper.ldcDynamicConstant( var handle = InstructionHelper.ldcDynamicConstant(
L, "_", List.class, L, "_", List.class,
ConstantBootstraps.class, "invoke", lookupMT(Object.class, MethodHandle.class, Object[].class), ConstantBootstraps.class, "invoke", lookupMT(Object.class, MethodHandle.class, Object[].class),
S -> { MethodHandleDesc.of(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, ConstantDescs.CD_List, "of",
S.add("", (P, Z) -> { MethodType.methodType(List.class, Object[].class).toMethodDescriptorString()),
return P.putHandle(MethodHandleInfo.REF_invokeStatic, "java/util/List", "of", 1, 2, 3, 4
MethodType.methodType(List.class, Object[].class).toMethodDescriptorString(), );
true);
});
S.add(1).add(2).add(3).add(4);
});
assertEquals(handle.invoke(), List.of(1, 2, 3, 4)); assertEquals(handle.invoke(), List.of(1, 2, 3, 4));
} }
@ -179,14 +170,10 @@ public class ConstantBootstrapsTest {
var handle = InstructionHelper.ldcDynamicConstant( var handle = InstructionHelper.ldcDynamicConstant(
L, "_", int.class, L, "_", int.class,
ConstantBootstraps.class, "invoke", lookupMT(Object.class, MethodHandle.class, Object[].class), ConstantBootstraps.class, "invoke", lookupMT(Object.class, MethodHandle.class, Object[].class),
S -> { MethodHandleDesc.of(DirectMethodHandleDesc.Kind.STATIC, ConstantDescs.CD_Integer, "valueOf",
S.add("", (P, Z) -> { MethodType.methodType(Integer.class, String.class).toMethodDescriptorString()),
return P.putHandle(MethodHandleInfo.REF_invokeStatic, "java/lang/Integer", "valueOf", "42"
MethodType.methodType(Integer.class, String.class).toMethodDescriptorString(), );
false);
});
S.add("42");
});
assertEquals(handle.invoke(), 42); assertEquals(handle.invoke(), 42);
} }
@ -195,29 +182,25 @@ public class ConstantBootstrapsTest {
var handle = InstructionHelper.ldcDynamicConstant( var handle = InstructionHelper.ldcDynamicConstant(
L, "_", Collection.class, L, "_", Collection.class,
ConstantBootstraps.class, "invoke", lookupMT(Object.class, MethodHandle.class, Object[].class), ConstantBootstraps.class, "invoke", lookupMT(Object.class, MethodHandle.class, Object[].class),
S -> { MethodHandleDesc.of(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, ConstantDescs.CD_List, "of",
S.add("", (P, Z) -> { MethodType.methodType(List.class, Object[].class).toMethodDescriptorString()),
return P.putHandle(MethodHandleInfo.REF_invokeStatic, "java/util/List", "of", 1, 2, 3, 4
MethodType.methodType(List.class, Object[].class).toMethodDescriptorString(), );
true);
});
S.add(1).add(2).add(3).add(4);
});
assertEquals(handle.invoke(), List.of(1, 2, 3, 4)); assertEquals(handle.invoke(), List.of(1, 2, 3, 4));
} }
@Test(expectedExceptions = ClassCastException.class) @Test(expectedExceptions = ClassCastException.class)
public void testInvokeAsTypeClassCast() throws Throwable { public void testInvokeAsTypeClassCast() throws Throwable {
ConstantBootstraps.invoke(MethodHandles.lookup(), "_", String.class, ConstantBootstraps.invoke(MethodHandles.lookup(), "_", String.class,
MethodHandles.lookup().findStatic(Integer.class, "valueOf", MethodType.methodType(Integer.class, String.class)), MethodHandles.lookup().findStatic(Integer.class, "valueOf", MethodType.methodType(Integer.class, String.class)),
"42"); "42");
} }
@Test(expectedExceptions = WrongMethodTypeException.class) @Test(expectedExceptions = WrongMethodTypeException.class)
public void testInvokeAsTypeWrongReturnType() throws Throwable { public void testInvokeAsTypeWrongReturnType() throws Throwable {
ConstantBootstraps.invoke(MethodHandles.lookup(), "_", short.class, ConstantBootstraps.invoke(MethodHandles.lookup(), "_", short.class,
MethodHandles.lookup().findStatic(Integer.class, "parseInt", MethodType.methodType(int.class, String.class)), MethodHandles.lookup().findStatic(Integer.class, "parseInt", MethodType.methodType(int.class, String.class)),
"42"); "42");
} }
@ -230,10 +213,9 @@ public class ConstantBootstrapsTest {
var handle = InstructionHelper.ldcDynamicConstant( var handle = InstructionHelper.ldcDynamicConstant(
L, "f", VarHandle.class, L, "f", VarHandle.class,
ConstantBootstraps.class, "fieldVarHandle", lookupMT(VarHandle.class, Class.class, Class.class), ConstantBootstraps.class, "fieldVarHandle", lookupMT(VarHandle.class, Class.class, Class.class),
S -> { InstructionHelper.classDesc(X.class),
S.add(X.class.getName().replace('.', '/'), PoolHelper::putClass). InstructionHelper.classDesc(String.class)
add("java/lang/String", PoolHelper::putClass); );
});
var vhandle = (VarHandle) handle.invoke(); var vhandle = (VarHandle) handle.invoke();
assertEquals(vhandle.varType(), String.class); assertEquals(vhandle.varType(), String.class);
@ -244,10 +226,9 @@ public class ConstantBootstrapsTest {
var handle = InstructionHelper.ldcDynamicConstant( var handle = InstructionHelper.ldcDynamicConstant(
L, "sf", VarHandle.class, L, "sf", VarHandle.class,
ConstantBootstraps.class, "staticFieldVarHandle", lookupMT(VarHandle.class, Class.class, Class.class), ConstantBootstraps.class, "staticFieldVarHandle", lookupMT(VarHandle.class, Class.class, Class.class),
S -> { InstructionHelper.classDesc(X.class),
S.add(X.class.getName().replace('.', '/'), PoolHelper::putClass). InstructionHelper.classDesc(String.class)
add("java/lang/String", PoolHelper::putClass); );
});
var vhandle = (VarHandle) handle.invoke(); var vhandle = (VarHandle) handle.invoke();
assertEquals(vhandle.varType(), String.class); assertEquals(vhandle.varType(), String.class);
@ -258,9 +239,8 @@ public class ConstantBootstrapsTest {
var handle = InstructionHelper.ldcDynamicConstant( var handle = InstructionHelper.ldcDynamicConstant(
L, "_", VarHandle.class, L, "_", VarHandle.class,
ConstantBootstraps.class, "arrayVarHandle", lookupMT(VarHandle.class, Class.class), ConstantBootstraps.class, "arrayVarHandle", lookupMT(VarHandle.class, Class.class),
S -> { InstructionHelper.classDesc(String[].class)
S.add(String[].class.getName().replace('.', '/'), PoolHelper::putClass); );
});
var vhandle = (VarHandle) handle.invoke(); var vhandle = (VarHandle) handle.invoke();
assertEquals(vhandle.varType(), String.class); assertEquals(vhandle.varType(), String.class);

View file

@ -1,60 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
/**
* Base builder.
*
* @param <S> the type of the symbol representation
* @param <T> the type of type descriptors representation
* @param <E> the type of pool entries
* @param <D> the type of this builder
*/
public class AbstractBuilder<S, T, E, D extends AbstractBuilder<S, T, E, D>> {
/**
* The helper to build the constant pool.
*/
protected final PoolHelper<S, T, E> poolHelper;
/**
* The helper to use to manipulate type descriptors.
*/
protected final TypeHelper<S, T> typeHelper;
/**
* Create a builder.
*
* @param poolHelper the helper to build the constant pool
* @param typeHelper the helper to use to manipulate type descriptors
*/
AbstractBuilder(PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
this.poolHelper = poolHelper;
this.typeHelper = typeHelper;
}
@SuppressWarnings("unchecked")
D thisBuilder() {
return (D) this;
}
}

View file

@ -1,338 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import java.util.function.Consumer;
import java.util.function.ToIntBiFunction;
public class AnnotationsBuilder<S, T, E> extends AbstractBuilder<S, T, E, AnnotationsBuilder<S, T, E>> {
GrowableByteBuffer annoAttribute;
int nannos;
AnnotationsBuilder(PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
super(poolHelper, typeHelper);
this.annoAttribute = new GrowableByteBuffer();
annoAttribute.writeChar(0);
}
public enum Kind {
RUNTIME_VISIBLE,
RUNTIME_INVISIBLE;
}
enum Tag {
B('B'),
C('C'),
D('D'),
F('F'),
I('I'),
J('J'),
S('S'),
Z('Z'),
STRING('s'),
ENUM('e'),
CLASS('c'),
ANNO('@'),
ARRAY('[');
char tagChar;
Tag(char tagChar) {
this.tagChar = tagChar;
}
}
AnnotationsBuilder<S, T, E> withAnnotation(T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
annoAttribute.writeChar(poolHelper.putType(annoType));
int offset = annoAttribute.offset;
annoAttribute.writeChar(0);
if (annotationBuilder != null) {
AnnotationElementBuilder _builder = new AnnotationElementBuilder();
int nelems = _builder.withElements(annotationBuilder);
patchCharAt(offset, nelems);
}
nannos++;
return this;
}
byte[] build() {
patchCharAt(0, nannos);
return annoAttribute.bytes();
}
private void patchCharAt(int offset, int newChar) {
int prevOffset = annoAttribute.offset;
try {
annoAttribute.offset = offset;
annoAttribute.writeChar(newChar);
} finally {
annoAttribute.offset = prevOffset;
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
static Consumer NO_BUILDER =
new Consumer() {
@Override
public void accept(Object o) {
//do nothing
}
};
public class AnnotationElementBuilder {
int nelems;
public AnnotationElementBuilder withString(String name, String s) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writeStringValue(s);
return this;
}
private void writeStringValue(String s) {
annoAttribute.writeByte(Tag.STRING.tagChar);
annoAttribute.writeChar(poolHelper.putUtf8(s));
nelems++;
}
public AnnotationElementBuilder withClass(String name, T s) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writeClassValue(s);
return this;
}
private void writeClassValue(T s) {
annoAttribute.writeByte(Tag.CLASS.tagChar);
annoAttribute.writeChar(poolHelper.putType(s));
nelems++;
}
public AnnotationElementBuilder withEnum(String name, T enumType, int constant) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writeEnumValue(enumType, constant);
return this;
}
private void writeEnumValue(T enumType, int constant) {
annoAttribute.writeByte(Tag.ENUM.tagChar);
annoAttribute.writeChar(poolHelper.putType(enumType));
annoAttribute.writeChar(constant);
nelems++;
}
public AnnotationElementBuilder withAnnotation(String name, T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writeAnnotationValue(annoType, annotationBuilder);
return this;
}
private void writeAnnotationValue(T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
annoAttribute.writeByte(Tag.ANNO.tagChar);
annoAttribute.writeChar(poolHelper.putType(annoType));
int offset = annoAttribute.offset;
annoAttribute.writeChar(0);
int nelems = withNestedElements(annotationBuilder);
patchCharAt(offset, nelems);
this.nelems++;
}
public AnnotationElementBuilder withPrimitive(String name, char c) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writePrimitiveValue(Tag.C, (int)c, PoolHelper::putInt);
return this;
}
public AnnotationElementBuilder withPrimitive(String name, short s) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writePrimitiveValue(Tag.S, (int)s, PoolHelper::putInt);
return this;
}
public AnnotationElementBuilder withPrimitive(String name, byte b) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writePrimitiveValue(Tag.B, (int)b, PoolHelper::putInt);
return this;
}
public AnnotationElementBuilder withPrimitive(String name, int i) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writePrimitiveValue(Tag.I, i, PoolHelper::putInt);
return this;
}
public AnnotationElementBuilder withPrimitive(String name, float f) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writePrimitiveValue(Tag.F, f, PoolHelper::putFloat);
return this;
}
public AnnotationElementBuilder withPrimitive(String name, long l) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writePrimitiveValue(Tag.J, l, PoolHelper::putLong);
return this;
}
public AnnotationElementBuilder withPrimitive(String name, double d) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writePrimitiveValue(Tag.D, d, PoolHelper::putDouble);
return this;
}
public AnnotationElementBuilder withPrimitive(String name, boolean b) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
writePrimitiveValue(Tag.Z, b ? 1 : 0, PoolHelper::putInt);
return this;
}
private <Z> void writePrimitiveValue(Tag tag, Z value, ToIntBiFunction<PoolHelper<S, T, E>, Z> poolFunc) {
annoAttribute.writeByte(tag.tagChar);
annoAttribute.writeChar(poolFunc.applyAsInt(poolHelper, value));
nelems++;
}
AnnotationElementBuilder withStrings(String name, String... ss) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(ss.length);
for (String s : ss) {
writeStringValue(s);
}
return this;
}
@SuppressWarnings("unchecked")
AnnotationElementBuilder withClasses(String name, T... cc) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(cc.length);
for (T c : cc) {
writeClassValue(c);
}
return this;
}
AnnotationElementBuilder withEnums(String name, T enumType, int... constants) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(constants.length);
for (int c : constants) {
writeEnumValue(enumType, c);
}
return this;
}
@SuppressWarnings("unchecked")
public AnnotationElementBuilder withAnnotations(String name, T annoType, Consumer<? super AnnotationElementBuilder>... annotationBuilders) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(annotationBuilders.length);
for (Consumer<? super AnnotationElementBuilder> annotationBuilder : annotationBuilders) {
writeAnnotationValue(annoType, annotationBuilder);
}
return this;
}
public AnnotationElementBuilder withPrimitives(String name, char... cc) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(cc.length);
for (char c : cc) {
writePrimitiveValue(Tag.C, (int)c, PoolHelper::putInt);
}
return this;
}
public AnnotationElementBuilder withPrimitives(String name, short... ss) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(ss.length);
for (short s : ss) {
writePrimitiveValue(Tag.S, (int)s, PoolHelper::putInt);
}
return this;
}
public AnnotationElementBuilder withPrimitives(String name, byte... bb) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(bb.length);
for (byte b : bb) {
writePrimitiveValue(Tag.B, (int)b, PoolHelper::putInt);
}
return this;
}
public AnnotationElementBuilder withPrimitives(String name, int... ii) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(ii.length);
for (int i : ii) {
writePrimitiveValue(Tag.I, i, PoolHelper::putInt);
}
return this;
}
public AnnotationElementBuilder withPrimitives(String name, float... ff) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(ff.length);
for (float f : ff) {
writePrimitiveValue(Tag.F, f, PoolHelper::putFloat);
}
return this;
}
public AnnotationElementBuilder withPrimitives(String name, long... ll) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(ll.length);
for (long l : ll) {
writePrimitiveValue(Tag.J, l, PoolHelper::putLong);
}
return this;
}
public AnnotationElementBuilder withPrimitives(String name, double... dd) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(dd.length);
for (double d : dd) {
writePrimitiveValue(Tag.D, d, PoolHelper::putDouble);
}
return this;
}
public AnnotationElementBuilder withPrimitives(String name, boolean... bb) {
annoAttribute.writeChar(poolHelper.putUtf8(name));
annoAttribute.writeChar(bb.length);
for (boolean b : bb) {
writePrimitiveValue(Tag.Z, b ? 1 : 0, PoolHelper::putInt);
}
return this;
}
int withNestedElements(Consumer<? super AnnotationElementBuilder> annotationBuilder) {
return withElements(new AnnotationElementBuilder(), annotationBuilder);
}
int withElements(Consumer<? super AnnotationElementBuilder> annotationBuilder) {
return withElements(this, annotationBuilder);
}
private int withElements(AnnotationElementBuilder builder, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
annotationBuilder.accept(builder);
return builder.nelems;
}
}
}

View file

@ -1,125 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
/**
* Base builder for attribute containing class file entities.
*
* @param <S> the type of the symbol representation
* @param <T> the type of type descriptors representation
* @param <E> the type of pool entries
* @param <D> the type of this builder
*/
public class AttributeBuilder<S, T, E, D extends AttributeBuilder<S, T, E, D>>
extends AbstractBuilder<S, T, E, D> {
/**
* The number of attributes.
*/
protected int nattrs;
/**
* The attributes represented as bytes.
*/
protected GrowableByteBuffer attributes = new GrowableByteBuffer();
/**
* Create an attribute builder.
*
* @param poolHelper the helper to build the constant pool
* @param typeHelper the helper to use to manipulate type descriptors
*/
public AttributeBuilder(PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
super(poolHelper, typeHelper);
}
/**
* Add a class file Attribute. Defined as:
* <pre>
* {@code attribute_info {
* u2 attribute_name_index;
* u4 attribute_length;
* u1 info[attribute_length];
* }}
* </pre>
*
* @param name the attribute name
* @param bytes the bytes of the attribute info
* @return this builder, for chained calls
*/
public D withAttribute(CharSequence name, byte[] bytes) {
attributes.writeChar(poolHelper.putUtf8(name));
attributes.writeInt(bytes.length);
attributes.writeBytes(bytes);
nattrs++;
return thisBuilder();
}
/**
* Add a class file Attribute, using a writer. Defined as:
* <pre>
* {@code attribute_info {
* u2 attribute_name_index;
* u4 attribute_length;
* u1 info[attribute_length];
* }}
* </pre>
*
* @param <Z> the type of the object representing the attribute
* @param name the attribute name
* @param attr the representation of the attribute
* @param attrWriter the writer which transform the attribute representation into bytes
* @return this builder, for chained calls
*/
public <Z> D withAttribute(CharSequence name, Z attr, AttributeWriter<S, T, E, Z> attrWriter) {
attributes.writeChar(poolHelper.putUtf8(name));
int offset = attributes.offset;
attributes.writeInt(0);
attrWriter.write(attr, poolHelper, attributes);
int len = attributes.offset - offset - 4;
attributes.withOffset(offset, buf -> buf.writeInt(len));
nattrs++;
return thisBuilder();
}
/**
* Writer for transforming attribute representations to bytes
*
* @param <S> the type of symbol representation
* @param <T> the type of type descriptors representation
* @param <E> the type of pool entries
* @param <A> the type of the object representing the attribute
*/
public interface AttributeWriter<S, T, E, A> {
/**
* Write an attribute representation into a byte buffer.
*
* @param attr the representation of the attribute
* @param poolHelper the constant pool helper
* @param buf the buffer to collect the bytes
*/
void write(A attr, PoolHelper<S, T, E> poolHelper, GrowableByteBuffer buf);
}
}

View file

@ -1,38 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
public class BasicClassBuilder extends ClassBuilder<String, String, BasicClassBuilder> {
public BasicClassBuilder(String thisClass, int majorVersion, int minorVersion) {
this();
withMinorVersion(minorVersion);
withMajorVersion(majorVersion);
withThisClass(thisClass);
}
public BasicClassBuilder() {
super(new BytePoolHelper<>(s->s, s->s), new BasicTypeHelper());
}
}

View file

@ -1,181 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import java.util.Iterator;
/**
* Helper to create and manipulate type descriptors, where type descriptors
* are represented as JVM type descriptor strings and symbols are represented
* as name strings
*/
public class BasicTypeHelper implements TypeHelper<String, String> {
@Override
public String elemtype(String s) {
if (!s.startsWith("[")) {
throw new IllegalStateException();
}
return s.substring(1);
}
@Override
public String arrayOf(String s) {
return "[" + s;
}
@Override
public String type(String s) {
return "L" + s + ";";
}
@Override
public TypeTag tag(String s) {
switch (s.charAt(0)) {
case '[':
case 'L':
return TypeTag.A;
case 'B':
case 'C':
case 'Z':
case 'S':
case 'I':
return TypeTag.I;
case 'F':
return TypeTag.F;
case 'J':
return TypeTag.J;
case 'D':
return TypeTag.D;
case 'V':
return TypeTag.V;
case 'Q':
return TypeTag.Q;
default:
throw new IllegalStateException("Bad type: " + s);
}
}
@Override
public String nullType() {
// Needed in TypedCodeBuilder; ACONST_NULL pushes a 'null' onto the stack,
// and stack maps handle null differently
return "<null>";
}
@Override
public String commonSupertype(String t1, String t2) {
if (t1.equals(t2)) {
return t1;
} else {
try {
Class<?> c1 = from(t1);
Class<?> c2 = from(t2);
if (c1.isAssignableFrom(c2)) {
return t1;
} else if (c2.isAssignableFrom(c1)) {
return t2;
} else {
return "Ljava/lang/Object;";
}
} catch (Exception e) {
return null;
}
}
}
public Class<?> from(String desc) throws ReflectiveOperationException {
if (desc.startsWith("[")) {
return Class.forName(desc.replaceAll("/", "."));
} else {
return Class.forName(symbol(desc).replaceAll("/", "."));
}
}
@Override
public Iterator<String> parameterTypes(String s) {
//TODO: gracefully non-method types
return new Iterator<String>() {
int ch = 1;
@Override
public boolean hasNext() {
return s.charAt(ch) != ')';
}
@Override
public String next() {
char curr = s.charAt(ch);
switch (curr) {
case 'C':
case 'B':
case 'S':
case 'I':
case 'J':
case 'F':
case 'D':
case 'Z':
ch++;
return String.valueOf(curr);
case '[':
ch++;
return "[" + next();
case 'L':
case 'Q':
StringBuilder builder = new StringBuilder();
while (curr != ';') {
builder.append(curr);
curr = s.charAt(++ch);
}
builder.append(';');
ch++;
return builder.toString();
default:
throw new AssertionError("cannot parse string: " + s);
}
}
};
}
@Override
public String symbolFrom(String s) {
return s;
}
@Override
public String fromTag(TypeTag tag) {
return tag.name();
}
@Override
public String symbol(String type) {
return (type.startsWith("L") || type.startsWith("Q")) ? type.substring(1, type.length() - 1) : type;
}
@Override
public String returnType(String s) {
return s.substring(s.indexOf(')') + 1, s.length());
}
}

View file

@ -1,752 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import java.lang.invoke.MethodHandleInfo;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.ToIntBiFunction;
/**
* A helper for building and tracking constant pools whose entries are
* represented as byte arrays.
*
* @param <S> the type of the symbol representation
* @param <T> the type of type descriptors representation
*/
public class BytePoolHelper<S, T> implements PoolHelper<S, T, byte[]> {
GrowableByteBuffer pool = new GrowableByteBuffer();
GrowableByteBuffer bsm_attr = new GrowableByteBuffer();
//Map<PoolKey, PoolKey> indicesMap = new HashMap<>();
int currentIndex = 1;
int currentBsmIndex = 0;
KeyMap<PoolKey> entries = new KeyMap<>();
KeyMap<BsmKey> bootstraps = new KeyMap<>();
PoolKey key = new PoolKey();
BsmKey bsmKey = new BsmKey();
Function<S, String> symbolToString;
Function<T, String> typeToString;
public BytePoolHelper(Function<S, String> symbolToString, Function<T, String> typeToString) {
this.symbolToString = symbolToString;
this.typeToString = typeToString;
}
static class KeyMap<K extends AbstractKey<K>> {
@SuppressWarnings("unchecked")
K[] table = (K[])new AbstractKey<?>[0x10];
int nelems;
public void enter(K e) {
if (nelems * 3 >= (table.length - 1) * 2)
dble();
int hash = getIndex(e);
K old = table[hash];
if (old == null) {
nelems++;
}
e.next = old;
table[hash] = e;
}
protected K lookup(K other) {
K e = table[getIndex(other)];
while (e != null && !e.equals(other))
e = e.next;
return e;
}
/**
* Look for slot in the table.
* We use open addressing with double hashing.
*/
int getIndex(K e) {
int hashMask = table.length - 1;
int h = e.hashCode();
int i = h & hashMask;
// The expression below is always odd, so it is guaranteed
// to be mutually prime with table.length, a power of 2.
int x = hashMask - ((h + (h >> 16)) << 1);
for (; ; ) {
K e2 = table[i];
if (e2 == null)
return i;
else if (e.hash == e2.hash)
return i;
i = (i + x) & hashMask;
}
}
@SuppressWarnings("unchecked")
private void dble() {
K[] oldtable = table;
table = (K[])new AbstractKey<?>[oldtable.length * 2];
int n = 0;
for (int i = oldtable.length; --i >= 0; ) {
K e = oldtable[i];
if (e != null) {
table[getIndex(e)] = e;
n++;
}
}
// We don't need to update nelems for shared inherited scopes,
// since that gets handled by leave().
nelems = n;
}
}
public static abstract class AbstractKey<K extends AbstractKey<K>> {
int hash;
int index = -1;
K next;
abstract K dup();
public abstract boolean equals(Object o);
@Override
public int hashCode() {
return hash;
}
void at(int index) {
this.index = index;
}
}
public static class PoolKey extends AbstractKey<PoolKey> {
PoolTag tag;
Object o1;
Object o2;
Object o3;
Object o4;
int size = -1;
void setUtf8(CharSequence s) {
tag = PoolTag.CONSTANT_UTF8;
o1 = s;
size = 1;
hash = tag.tag | (s.hashCode() << 1);
}
void setClass(String clazz) {
tag = PoolTag.CONSTANT_CLASS;
o1 = clazz;
size = 1;
hash = tag.tag | (clazz.hashCode() << 1);
}
void setNameAndType(CharSequence name, String type) {
tag = PoolTag.CONSTANT_NAMEANDTYPE;
o1 = name;
o2 = type;
size = 2;
hash = tag.tag | ((name.hashCode() | type.hashCode()) << 1);
}
void setMemberRef(PoolTag poolTag, String owner, CharSequence name, String type) {
tag = poolTag;
o1 = owner;
o2 = name;
o3 = type;
size = 3;
hash = tag.tag | ((owner.hashCode() | name.hashCode() | type.hashCode()) << 1);
}
void setInvokeDynamic(int bsmIndex, CharSequence name, String type) {
tag = PoolTag.CONSTANT_INVOKEDYNAMIC;
o1 = bsmIndex;
o2 = name;
o3 = type;
size = 3;
hash = tag.tag | ((bsmIndex | name.hashCode() | type.hashCode()) << 1);
}
void setDynamicConstant(int bsmIndex, CharSequence name, String type) {
tag = PoolTag.CONSTANT_DYNAMIC;
o1 = bsmIndex;
o2 = name;
o3 = type;
size = 3;
hash = tag.tag | ((bsmIndex | name.hashCode() | type.hashCode()) << 1);
}
void setString(String s) {
tag = PoolTag.CONSTANT_STRING;
o1 = s;
size = 1;
hash = tag.tag | (s.hashCode() << 1);
}
void setInteger(Integer i) {
tag = PoolTag.CONSTANT_INTEGER;
o1 = i;
size = 1;
hash = tag.tag | (i.hashCode() << 1);
}
void setFloat(Float f) {
tag = PoolTag.CONSTANT_FLOAT;
o1 = f;
size = 1;
hash = tag.tag | (f.hashCode() << 1);
}
void setLong(Long l) {
tag = PoolTag.CONSTANT_LONG;
o1 = l;
size = 1;
hash = tag.tag | (l.hashCode() << 1);
}
void setDouble(Double d) {
tag = PoolTag.CONSTANT_DOUBLE;
o1 = d;
size = 1;
hash = tag.tag | (d.hashCode() << 1);
}
void setMethodType(String type) {
tag = PoolTag.CONSTANT_METHODTYPE;
o1 = type;
size = 1;
hash = tag.tag | (type.hashCode() << 1);
}
void setMethodHandle(int bsmKind, String owner, CharSequence name, String type) {
tag = PoolTag.CONSTANT_METHODHANDLE;
o1 = bsmKind;
o2 = owner;
o3 = name;
o4 = type;
size = 4;
hash = tag.tag | (bsmKind | owner.hashCode() | name.hashCode() | type.hashCode() << 1);
}
@Override
public boolean equals(Object obj) {
PoolKey that = (PoolKey) obj;
if (tag != that.tag) return false;
switch (size) {
case 1:
if (!o1.equals(that.o1)) {
return false;
}
break;
case 2:
if (!o2.equals(that.o2) || !o1.equals(that.o1)) {
return false;
}
break;
case 3:
if (!o3.equals(that.o3) || !o2.equals(that.o2) || !o1.equals(that.o1)) {
return false;
}
break;
case 4:
if (!o4.equals(that.o4) || !o3.equals(that.o3) || !o2.equals(that.o2) || !o1.equals(that.o1)) {
return false;
}
break;
}
return true;
}
PoolKey dup() {
PoolKey poolKey = new PoolKey();
poolKey.tag = tag;
poolKey.size = size;
poolKey.hash = hash;
poolKey.o1 = o1;
poolKey.o2 = o2;
poolKey.o3 = o3;
poolKey.o4 = o4;
return poolKey;
}
}
static class BsmKey extends AbstractKey<BsmKey> {
String bsmClass;
CharSequence bsmName;
String bsmType;
List<Integer> bsmArgs;
void set(String bsmClass, CharSequence bsmName, String bsmType, List<Integer> bsmArgs) {
this.bsmClass = bsmClass;
this.bsmName = bsmName;
this.bsmType = bsmType;
this.bsmArgs = bsmArgs;
hash = bsmClass.hashCode() | bsmName.hashCode() | bsmType.hashCode() | Objects.hash(bsmArgs);
}
BsmKey dup() {
BsmKey bsmKey = new BsmKey();
bsmKey.bsmClass = bsmClass;
bsmKey.bsmName = bsmName;
bsmKey.bsmType = bsmType;
bsmKey.bsmArgs = bsmArgs;
bsmKey.hash = hash;
return bsmKey;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof BsmKey) {
BsmKey that = (BsmKey)obj;
return Objects.equals(bsmClass, that.bsmClass) &&
Objects.equals(bsmName, that.bsmName) &&
Objects.equals(bsmType, that.bsmType) &&
Objects.deepEquals(bsmArgs, that.bsmArgs);
} else {
return false;
}
}
}
@Override
public int putClass(S symbol) {
return putClassInternal(symbolToString.apply(symbol));
}
private int putClassInternal(String symbol) {
key.setClass(symbol);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
int utf8_idx = putUtf8(symbol);
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_CLASS.tag);
pool.writeChar(utf8_idx);
}
return poolKey.index;
}
@Override
public int putFieldRef(S owner, CharSequence name, T type) {
return putMemberRef(PoolTag.CONSTANT_FIELDREF, owner, name, type);
}
@Override
public int putMethodRef(S owner, CharSequence name, T type, boolean isInterface) {
return putMemberRef(isInterface ? PoolTag.CONSTANT_INTERFACEMETHODREF : PoolTag.CONSTANT_METHODREF,
owner, name, type);
}
int putMemberRef(PoolTag poolTag, S owner, CharSequence name, T type) {
return putMemberRefInternal(poolTag, symbolToString.apply(owner), name, typeToString.apply(type));
}
int putMemberRefInternal(PoolTag poolTag, String owner, CharSequence name, String type) {
key.setMemberRef(poolTag, owner, name, type);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
int owner_idx = putClassInternal(owner);
int nameAndType_idx = putNameAndType(name, type);
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(poolTag.tag);
pool.writeChar(owner_idx);
pool.writeChar(nameAndType_idx);
}
return poolKey.index;
}
@Override
public int putInt(int i) {
key.setInteger(i);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_INTEGER.tag);
pool.writeInt(i);
}
return poolKey.index;
}
@Override
public int putFloat(float f) {
key.setFloat(f);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_FLOAT.tag);
pool.writeFloat(f);
}
return poolKey.index;
}
@Override
public int putLong(long l) {
key.setLong(l);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_LONG.tag);
pool.writeLong(l);
currentIndex++;
}
return poolKey.index;
}
@Override
public int putDouble(double d) {
key.setDouble(d);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_DOUBLE.tag);
pool.writeDouble(d);
currentIndex++;
}
return poolKey.index;
}
@Override
public int putInvokeDynamic(CharSequence invokedName, T invokedType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
return putInvokeDynamicInternal(invokedName, typeToString.apply(invokedType), symbolToString.apply(bsmClass), bsmName, typeToString.apply(bsmType), staticArgs);
}
@Override
public int putDynamicConstant(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
return putDynamicConstantInternal(constName, typeToString.apply(constType), symbolToString.apply(bsmClass), bsmName, typeToString.apply(bsmType), staticArgs);
}
private int putInvokeDynamicInternal(CharSequence invokedName, String invokedType, String bsmClass, CharSequence bsmName, String bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
int bsmIndex = putBsmInternal(bsmClass, bsmName, bsmType, staticArgs);
key.setInvokeDynamic(bsmIndex, invokedName, invokedType);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
int nameAndType_idx = putNameAndType(invokedName, invokedType);
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_INVOKEDYNAMIC.tag);
pool.writeChar(bsmIndex);
pool.writeChar(nameAndType_idx);
}
return poolKey.index;
}
private int putDynamicConstantInternal(CharSequence constName, String constType, String bsmClass, CharSequence bsmName, String bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
int bsmIndex = putBsmInternal(bsmClass, bsmName, bsmType, staticArgs);
key.setDynamicConstant(bsmIndex, constName, constType);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
int nameAndType_idx = putNameAndType(constName, constType);
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_DYNAMIC.tag);
pool.writeChar(bsmIndex);
pool.writeChar(nameAndType_idx);
}
return poolKey.index;
}
private int putBsmInternal(String bsmClass, CharSequence bsmName, String bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
ByteStaticArgListBuilder staticArgsBuilder = new ByteStaticArgListBuilder();
staticArgs.accept(staticArgsBuilder);
List<Integer> static_idxs = staticArgsBuilder.indexes;
bsmKey.set(bsmClass, bsmName, bsmType, static_idxs);
BsmKey poolKey = bootstraps.lookup(bsmKey);
if (poolKey == null) {
poolKey = bsmKey.dup();
// TODO the BSM could be a static method on an interface
int bsm_ref = putHandleInternal(MethodHandleInfo.REF_invokeStatic, bsmClass, bsmName, bsmType, false);
poolKey.at(currentBsmIndex++);
bootstraps.enter(poolKey);
bsm_attr.writeChar(bsm_ref);
bsm_attr.writeChar(static_idxs.size());
for (int i : static_idxs) {
bsm_attr.writeChar(i);
}
}
return poolKey.index;
}
//where
class ByteStaticArgListBuilder implements StaticArgListBuilder<S, T, byte[]> {
List<Integer> indexes = new ArrayList<>();
public ByteStaticArgListBuilder add(int i) {
indexes.add(putInt(i));
return this;
}
public ByteStaticArgListBuilder add(float f) {
indexes.add(putFloat(f));
return this;
}
public ByteStaticArgListBuilder add(long l) {
indexes.add(putLong(l));
return this;
}
public ByteStaticArgListBuilder add(double d) {
indexes.add(putDouble(d));
return this;
}
public ByteStaticArgListBuilder add(String s) {
indexes.add(putString(s));
return this;
}
@Override
public StaticArgListBuilder<S, T, byte[]> add(int refKind, S owner, CharSequence name, T type) {
indexes.add(putHandle(refKind, owner, name, type));
return this;
}
public <Z> ByteStaticArgListBuilder add(Z z, ToIntBiFunction<PoolHelper<S, T, byte[]>, Z> poolFunc) {
indexes.add(poolFunc.applyAsInt(BytePoolHelper.this, z));
return this;
}
public ByteStaticArgListBuilder add(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) {
indexes.add(putDynamicConstant(constName, constType, bsmClass, bsmName, bsmType, staticArgs));
return this;
}
}
@Override
public int putMethodType(T s) {
return putMethodTypeInternal(typeToString.apply(s));
}
private int putMethodTypeInternal(String s) {
key.setMethodType(s);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
int desc_idx = putUtf8(s);
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_METHODTYPE.tag);
pool.writeChar(desc_idx);
}
return poolKey.index;
}
@Override
public int putHandle(int refKind, S owner, CharSequence name, T type) {
return putHandleInternal(refKind, symbolToString.apply(owner), name, typeToString.apply(type), false);
}
@Override
public int putHandle(int refKind, S owner, CharSequence name, T type, boolean isInterface) {
return putHandleInternal(refKind, symbolToString.apply(owner), name, typeToString.apply(type), isInterface);
}
private int putHandleInternal(int refKind, String owner, CharSequence name, String type, boolean isInterface) {
key.setMethodHandle(refKind, owner, name, type);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
int ref_idx = putMemberRefInternal(fromKind(refKind, isInterface), owner, name, type);
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_METHODHANDLE.tag);
pool.writeByte(refKind);
pool.writeChar(ref_idx);
}
return poolKey.index;
}
PoolTag fromKind(int bsmKind, boolean isInterface) {
switch (bsmKind) {
case 1: // REF_getField
case 2: // REF_getStatic
case 3: // REF_putField
case 4: // REF_putStatic
return PoolTag.CONSTANT_FIELDREF;
case 5: // REF_invokeVirtual
case 6: // REF_invokeStatic
case 7: // REF_invokeSpecial
case 8: // REF_newInvokeSpecial
case 9: // REF_invokeInterface
return isInterface ? PoolTag.CONSTANT_INTERFACEMETHODREF : PoolTag.CONSTANT_METHODREF;
default:
throw new IllegalStateException();
}
}
@Override
public int putType(T s) {
return putUtf8(typeToString.apply(s));
}
public int putUtf8(CharSequence s) {
key.setUtf8(s);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_UTF8.tag);
putUTF8Internal(s);
}
return poolKey.index;
}
/**
* Puts an UTF8 string into this byte vector. The byte vector is
* automatically enlarged if necessary.
*
* @param s a String whose UTF8 encoded length must be less than 65536.
* @return this byte vector.
*/
void putUTF8Internal(final CharSequence s) {
int charLength = s.length();
if (charLength > 65535) {
throw new IllegalArgumentException();
}
// optimistic algorithm: instead of computing the byte length and then
// serializing the string (which requires two loops), we assume the byte
// length is equal to char length (which is the most frequent case), and
// we start serializing the string right away. During the serialization,
// if we find that this assumption is wrong, we continue with the
// general method.
pool.writeChar(charLength);
for (int i = 0; i < charLength; ++i) {
char c = s.charAt(i);
if (c >= '\001' && c <= '\177') {
pool.writeByte((byte) c);
} else {
encodeUTF8(s, i, 65535);
break;
}
}
}
/**
* Puts an UTF8 string into this byte vector. The byte vector is
* automatically enlarged if necessary. The string length is encoded in two
* bytes before the encoded characters, if there is space for that (i.e. if
* this.length - i - 2 >= 0).
*
* @param s the String to encode.
* @param i the index of the first character to encode. The previous
* characters are supposed to have already been encoded, using
* only one byte per character.
* @param maxByteLength the maximum byte length of the encoded string, including the
* already encoded characters.
* @return this byte vector.
*/
void encodeUTF8(final CharSequence s, int i, int maxByteLength) {
int charLength = s.length();
int byteLength = i;
char c;
for (int j = i; j < charLength; ++j) {
c = s.charAt(j);
if (c >= '\001' && c <= '\177') {
byteLength++;
} else if (c > '\u07FF') {
byteLength += 3;
} else {
byteLength += 2;
}
}
if (byteLength > maxByteLength) {
throw new IllegalArgumentException();
}
int byteLengthFinal = byteLength;
pool.withOffset(pool.offset - i - 2, buf -> buf.writeChar(byteLengthFinal));
for (int j = i; j < charLength; ++j) {
c = s.charAt(j);
if (c >= '\001' && c <= '\177') {
pool.writeChar((byte) c);
} else if (c > '\u07FF') {
pool.writeChar((byte) (0xE0 | c >> 12 & 0xF));
pool.writeChar((byte) (0x80 | c >> 6 & 0x3F));
pool.writeChar((byte) (0x80 | c & 0x3F));
} else {
pool.writeChar((byte) (0xC0 | c >> 6 & 0x1F));
pool.writeChar((byte) (0x80 | c & 0x3F));
}
}
}
@Override
public int putString(String s) {
key.setString(s);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
int utf8_index = putUtf8(s);
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_STRING.tag);
pool.writeChar(utf8_index);
}
return poolKey.index;
}
int putNameAndType(CharSequence name, String type) {
key.setNameAndType(name, type);
PoolKey poolKey = entries.lookup(key);
if (poolKey == null) {
poolKey = key.dup();
int name_idx = putUtf8(name);
int type_idx = putUtf8(type);
poolKey.at(currentIndex++);
entries.enter(poolKey);
pool.writeByte(PoolTag.CONSTANT_NAMEANDTYPE.tag);
pool.writeChar(name_idx);
pool.writeChar(type_idx);
}
return poolKey.index;
}
@Override
public int size() {
return currentIndex - 1;
}
@Override
public byte[] entries() {
return pool.bytes();
}
<Z extends ClassBuilder<S, T, Z>> void addAttributes(ClassBuilder<S , T, Z> cb) {
if (currentBsmIndex > 0) {
GrowableByteBuffer bsmAttrBuf = new GrowableByteBuffer();
bsmAttrBuf.writeChar(currentBsmIndex);
bsmAttrBuf.writeBytes(bsm_attr);
cb.withAttribute("BootstrapMethods", bsmAttrBuf.bytes());
}
}
}

View file

@ -1,240 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import java.util.function.Consumer;
/**
* Base class builder. The base of higher level class builders.
*
* @param <S> the type of symbol representation
* @param <T> the type of type descriptors representation
* @param <C> the type of this builder
*/
public class ClassBuilder<S, T, C extends ClassBuilder<S, T, C>>
extends DeclBuilder<S, T, byte[], C> {
/**
* The helper to use to manipulate type descriptors.
*/
protected TypeHelper<S, T> typeHelper;
/**
* The symbol for the class being built.
*/
protected S thisClass;
/**
* The super-interfaces of the class being built..
*/
protected GrowableByteBuffer interfaces = new GrowableByteBuffer();
/**
* The fields of the class being built.
*/
protected GrowableByteBuffer fields = new GrowableByteBuffer();
/**
* The methods of the class being built.
*/
protected GrowableByteBuffer methods = new GrowableByteBuffer();
int majorVersion;
int minorVersion;
int flags;
int superclass;
int nmethods, nfields, ninterfaces;
/**
* Create a class builder.
*
* @param poolHelper the helper to build the constant pool
* @param typeHelper the helper to use to manipulate type descriptors
*/
public ClassBuilder(BytePoolHelper<S, T> poolHelper, TypeHelper<S, T> typeHelper) {
super(poolHelper, typeHelper);
this.typeHelper = typeHelper;
}
/**
* Set the minor class file version.
*
* @param minorVersion the minor version number
* @return this builder, for chained calls
*/
public C withMinorVersion(int minorVersion) {
this.minorVersion = minorVersion;
return thisBuilder();
}
/**
* Set the major class file version.
*
* @param majorVersion the major version number
* @return this builder, for chained calls
*/
public C withMajorVersion(int majorVersion) {
this.majorVersion = majorVersion;
return thisBuilder();
}
/**
* Set the class symbol
*
* @param thisClass the class symbol
* @return this builder, for chained calls
*/
public C withThisClass(S thisClass) {
this.thisClass = thisClass;
return thisBuilder();
}
/**
* Set the class access flags
*
* @param flags an array of {@code Flag}
* @return this builder, for chained calls
*/
@Override
public C withFlags(Flag... flags) {
for (Flag f : flags) {
this.flags |= f.flag;
}
return thisBuilder();
}
/**
* Set the superclass
*
* @param sup the superclass symbol
* @return this builder, for chained calls
*/
public C withSuperclass(S sup) {
this.superclass = poolHelper.putClass(sup);
return thisBuilder();
}
/**
* Add a super interface.
*
* @param sup an interface symbol
* @return this builder, for chained calls
*/
public C withSuperinterface(S sup) {
this.interfaces.writeChar(poolHelper.putClass(sup));
ninterfaces++;
return thisBuilder();
}
/**
* Add a field.
*
* @param name the name of the field
* @param type the type descriptor of the field
* @return this builder, for chained calls
*/
public final C withField(CharSequence name, T type) {
return withField(name, type, FB -> {
});
}
/**
* Add a field.
*
* @param name the name of the field
* @param type the type descriptor of the field
* @param fieldConfig access to the {@code FieldBuilder} to allow clients to
* adjust flags, annotations and bytecode attributes on the field declaration
* @return this builder, for chained calls
*/
public C withField(CharSequence name, T type, Consumer<? super FieldBuilder<S, T, byte[]>> fieldConfig) {
FieldBuilder<S, T, byte[]> F = new FieldBuilder<>(name, type, poolHelper, typeHelper);
fieldConfig.accept(F);
F.build(fields);
nfields++;
return thisBuilder();
}
/**
* Add a method
*
* @param name the name of the method
* @param type the type descriptor of the method
* @return this builder, for chained calls
*/
public final C withMethod(CharSequence name, T type) {
return withMethod(name, type, MB -> {
});
}
/**
* Add a method
*
* @param name the name of the method
* @param type the type descriptor of the method
* @param methodConfig access to the {@code MethodBuilder} to allow clients to
* adjust flags, annotations and bytecode attributes on the method declaration
* @return this builder, for chained calls
*/
public C withMethod(CharSequence name, T type, Consumer<? super MethodBuilder<S, T, byte[]>> methodConfig) {
MethodBuilder<S, T, byte[]> M = new MethodBuilder<>(thisClass, name, type, poolHelper, typeHelper);
methodConfig.accept(M);
M.build(methods);
nmethods++;
return thisBuilder();
}
/**
* Build the constant pool into a byte array.
*
* @return a representation of this constant pool as a byte array
*/
@SuppressWarnings("unchecked")
public byte[] build() {
((BytePoolHelper<S, T>)poolHelper).addAttributes(this);
addAnnotations();
int thisClassIdx = poolHelper.putClass(thisClass);
byte[] poolBytes = poolHelper.entries();
GrowableByteBuffer buf = new GrowableByteBuffer();
buf.writeInt(0xCAFEBABE);
buf.writeChar(minorVersion);
buf.writeChar(majorVersion);
buf.writeChar(poolHelper.size() + 1);
buf.writeBytes(poolBytes);
buf.writeChar(flags);
buf.writeChar(thisClassIdx);
buf.writeChar(superclass);
buf.writeChar(ninterfaces);
if (ninterfaces > 0) {
buf.writeBytes(interfaces);
}
buf.writeChar(nfields);
buf.writeBytes(fields);
buf.writeChar(nmethods);
buf.writeBytes(methods);
buf.writeChar(nattrs);
buf.writeBytes(attributes);
return buf.bytes();
}
}

View file

@ -1,115 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import java.util.function.Consumer;
/**
* Declaration (class, class member, ...) builder.
*
* @param <S> the type of symbol representation
* @param <T> the type of type descriptors representation
* @param <E> the type of pool entries
* @param <D> the type of this builder
*/
public class DeclBuilder<S, T, E, D extends DeclBuilder<S, T, E, D>>
extends AttributeBuilder<S, T, E, D> {
/**
* The access flags of the declaration, as bit flags.
*/
protected int flags;
AnnotationsBuilder<S, T, E> runtimeInvisibleAnnotations;
AnnotationsBuilder<S, T, E> runtimeVisibleAnnotations;
/**
* Create a declaration builder,
*
* @param poolHelper the helper to build the constant pool
* @param typeHelper the helper to use to manipulate type descriptors
*/
DeclBuilder(PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
super(poolHelper, typeHelper);
}
/**
* Specify the class file flags for this declaration.
*
* @param flags the flags as {@code Flag} objects
* @return this builder, for chained calls
*/
public D withFlags(Flag... flags) {
for (Flag f : flags) {
this.flags |= f.flag;
}
return thisBuilder();
}
/**
* Specify, via bits, the class file flags for this declaration.
*
* @param flags the flags as bit settings
* @return this builder, for chained calls
*/
public D withFlags(int flags) {
withFlags(Flag.parse(flags));
return thisBuilder();
}
public D withAnnotation(AnnotationsBuilder.Kind kind, T annoType) {
getAnnotations(kind).withAnnotation(annoType, null);
return thisBuilder();
}
public D withAnnotation(AnnotationsBuilder.Kind kind, T annoType, Consumer<? super AnnotationsBuilder<S, T, E>.AnnotationElementBuilder> annotations) {
getAnnotations(kind).withAnnotation(annoType, annotations);
return thisBuilder();
}
private AnnotationsBuilder<S, T, E> getAnnotations(AnnotationsBuilder.Kind kind) {
switch (kind) {
case RUNTIME_INVISIBLE:
if (runtimeInvisibleAnnotations == null) {
runtimeInvisibleAnnotations = new AnnotationsBuilder<>(poolHelper, typeHelper);
}
return runtimeInvisibleAnnotations;
case RUNTIME_VISIBLE:
if (runtimeVisibleAnnotations == null) {
runtimeVisibleAnnotations = new AnnotationsBuilder<>(poolHelper, typeHelper);
}
return runtimeVisibleAnnotations;
}
throw new IllegalStateException();
}
void addAnnotations() {
if (runtimeVisibleAnnotations != null) {
withAttribute("RuntimeVisibleAnnotations", runtimeVisibleAnnotations.build());
}
if (runtimeInvisibleAnnotations != null) {
withAttribute("RuntimeInvisibleAnnotations", runtimeVisibleAnnotations.build());
}
}
}

View file

@ -1,37 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
/**
* Field builder.
*
* @param <S> the type of symbol representation
* @param <T> the type of type descriptor representation
* @param <E> the type of pool entries
*/
public class FieldBuilder<S, T, E> extends MemberBuilder<S, T, E, FieldBuilder<S, T, E>> {
public FieldBuilder(CharSequence name, T type, PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
super(name, type, poolHelper, typeHelper);
}
}

View file

@ -1,63 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import java.util.EnumSet;
public enum Flag {
ACC_PUBLIC(0x0001),
ACC_PROTECTED(0x0004),
ACC_PRIVATE(0x0002),
ACC_INTERFACE(0x0200),
ACC_ENUM(0x4000),
ACC_ANNOTATION(0x2000),
ACC_SUPER(0x0020),
ACC_ABSTRACT(0x0400),
ACC_VOLATILE(0x0040),
ACC_TRANSIENT(0x0080),
ACC_SYNTHETIC(0x1000),
ACC_STATIC(0x0008),
ACC_FINAL(0x0010),
ACC_SYNCHRONIZED(0x0020),
ACC_BRIDGE(0x0040),
ACC_VARARGS(0x0080),
ACC_NATIVE(0x0100),
ACC_STRICT(0x0800);
public int flag;
Flag(int flag) {
this.flag = flag;
}
static Flag[] parse(int flagsMask) {
EnumSet<Flag> flags = EnumSet.noneOf(Flag.class);
for (Flag f : Flag.values()) {
if ((f.flag & flagsMask) != 0) {
flags.add(f);
}
}
return flags.stream().toArray(Flag[]::new);
}
}

View file

@ -1,108 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import java.util.function.Consumer;
public class GrowableByteBuffer {
public GrowableByteBuffer() {
}
byte[] elems = new byte[64];
int offset = 0;
public GrowableByteBuffer writeByte(int b) {
return writeBytes(1, b);
}
public GrowableByteBuffer writeChar(int x) {
return writeBytes(2, x);
}
public GrowableByteBuffer writeInt(int x) {
return writeBytes(4, x);
}
public GrowableByteBuffer writeFloat(float x) {
return writeInt(Float.floatToIntBits(x));
}
public GrowableByteBuffer writeLong(long x) {
return writeBytes(8, x);
}
public GrowableByteBuffer writeDouble(double x) {
writeLong(Double.doubleToLongBits(x));
return this;
}
public GrowableByteBuffer writeBytes(byte[] barr) {
expandIfNeeded(barr.length);
System.arraycopy(barr, 0, elems, offset, barr.length);
offset += barr.length;
return this;
}
public GrowableByteBuffer writeBytes(GrowableByteBuffer bb) {
expandIfNeeded(bb.offset);
System.arraycopy(bb.elems, 0, elems, offset, bb.offset);
offset += bb.offset;
return this;
}
public GrowableByteBuffer withOffset(int offset, Consumer<GrowableByteBuffer> actions) {
int prevOffset = this.offset;
this.offset = offset;
actions.accept(this);
this.offset = prevOffset;
return this;
}
private GrowableByteBuffer writeBytes(int size, long x) {
expandIfNeeded(size);
for (int i = 0; i < size; i++) {
elems[offset++] = (byte) ((x >> 8 * (size - i - 1)) & 0xFF);
}
return this;
}
void expandIfNeeded(int increment) {
if (offset + increment > elems.length) {
int newsize = elems.length * 2;
while (offset + increment > newsize) {
newsize *= 2;
}
byte[] newelems = new byte[newsize];
System.arraycopy(elems, 0, newelems, 0, offset);
elems = newelems;
}
}
public byte[] bytes() {
byte[] bytes = new byte[offset];
System.arraycopy(elems, 0, bytes, 0, offset);
return bytes;
}
}

View file

@ -1,182 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.ToIntFunction;
public class IsolatedMethodBuilder extends MethodBuilder<Class<?>, String, Object[]> {
public IsolatedMethodBuilder(Lookup lookup, String name, String type) {
super(null, name, type, new IsolatedMethodPoolHelper(lookup), null);
}
static class IsolatedMethodPoolHelper implements PoolHelper<Class<?>, String, Object[]> {
Map<Object, Integer> constants = new HashMap<>();
Lookup lookup;
private IsolatedMethodPoolHelper(Lookup lookup) {
this.lookup = lookup;
}
@Override
public int putClass(Class<?> symbol) {
return putIfAbsent(symbol);
}
@Override
public int putFieldRef(Class<?> owner, CharSequence name, String type) {
try {
Field f = owner.getDeclaredField(name.toString()); //TODO: we should unreflect for a var handle
return putIfAbsent(lookup.unreflectGetter(f));
} catch (Throwable ex) {
ex.printStackTrace();
return -1;
}
}
@Override
public int putMethodRef(Class<?> owner, CharSequence name, String type, boolean isInterface) {
try {
Method m = owner.getDeclaredMethod(name.toString()); //we should unreflect according to method vs. constructor
//and static vs. private etc.
return putIfAbsent(lookup.unreflect(m));
} catch (Throwable ex) {
ex.printStackTrace();
return -1;
}
}
@Override
public int putInt(int i) {
return putIfAbsent(i);
}
@Override
public int putFloat(float f) {
return putIfAbsent(f);
}
@Override
public int putLong(long l) {
return putIfAbsent(l);
}
@Override
public int putDouble(double d) {
return putIfAbsent(d);
}
@Override
public int putString(String s) {
return putIfAbsent(s);
}
@Override
public int putInvokeDynamic(CharSequence invokedName, String invokedType, Class<?> bsmClass, CharSequence bsmName, String bsmType, Consumer<StaticArgListBuilder<Class<?>, String, Object[]>> staticArgs) {
return 0; //???
}
@Override
public int putDynamicConstant(CharSequence constName, String constType, Class<?> bsmClass, CharSequence bsmName, String bsmType, Consumer<StaticArgListBuilder<Class<?>, String, Object[]>> staticArgs) {
return 0; //???
}
@Override
public int putHandle(int refKind, Class<?> owner, CharSequence name, String type) {
return 0; //???
}
@Override
public int putHandle(int refKind, Class<?> owner, CharSequence name, String type, boolean isInterface) {
return 0; //???
}
@Override
public int putMethodType(String s) {
return 0; //???
}
@Override
public int putUtf8(CharSequence s) {
return putIfAbsent(s);
}
@Override
public int putType(String s) {
return putIfAbsent(s);
}
@Override
public int size() {
return constants.size();
}
@Override
public Object[] entries() {
return constants.keySet().toArray();
}
int putIfAbsent(Object o) {
int nextIndex = constants.size() + 1;
Object res = constants.putIfAbsent(o, nextIndex);
return res == null ?
nextIndex : (Integer)res;
}
}
public Object[] entries() {
return poolHelper.entries();
}
@Override
public byte[] build() {
byte[] arr = super.build();
int codelength_offset = 2 + 2 + 2 + 2 +
2 + 4 + 2 + 2;
int code_offset = codelength_offset + 4;
int length = ByteBuffer.wrap(arr).getInt(codelength_offset);
byte[] opcodes = new byte[length];
System.arraycopy(arr, code_offset, opcodes, 0, length);
return opcodes;
}
public static void main(String[] args) {
IsolatedMethodBuilder imb = new IsolatedMethodBuilder(MethodHandles.lookup(), "foo", "(java/lang/String;)I");
imb.withCode(C ->
C.aload_0()
.invokevirtual(String.class, "length", "()I", false)
.ireturn());
byte[] opcodes = imb.build();
System.out.println(Arrays.toString(opcodes));
}
}

View file

@ -1,712 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Consumer;
public class MacroCodeBuilder<S, T, E, C extends MacroCodeBuilder<S, T, E, C>> extends CodeBuilder<S, T, E, C> {
JumpMode jumpMode = JumpMode.NARROW;
Map<CharSequence, Integer> labels = new HashMap<>();
List<PendingJump> pendingJumps = new LinkedList<>();
class PendingJump {
CharSequence label;
int pc;
PendingJump(CharSequence label, int pc) {
this.label = label;
this.pc = pc;
}
boolean resolve(CharSequence label, int offset) {
if (this.label.equals(label)) {
//patch offset
code.withOffset(pc + 1, buf -> emitOffset(buf, jumpMode, offset - pc));
return true;
} else {
return false;
}
}
}
public enum InvocationKind {
INVOKESTATIC,
INVOKEVIRTUAL,
INVOKESPECIAL,
INVOKEINTERFACE;
}
public enum FieldAccessKind {
STATIC,
INSTANCE;
}
public enum CondKind {
EQ(0),
NE(1),
LT(2),
GE(3),
GT(4),
LE(5);
int offset;
CondKind(int offset) {
this.offset = offset;
}
public CondKind negate() {
switch (this) {
case EQ:
return NE;
case NE:
return EQ;
case LT:
return GE;
case GE:
return LT;
case GT:
return LE;
case LE:
return GT;
default:
throw new IllegalStateException("Unknown cond");
}
}
}
static class WideJumpException extends RuntimeException {
static final long serialVersionUID = 42L;
}
public MacroCodeBuilder(MethodBuilder<S, T, E> methodBuilder) {
super(methodBuilder);
}
public C load(TypeTag type, int n) {
if (type == TypeTag.Q) {
return vload(n);
} else {
switch (n) {
case 0:
return emitOp(Opcode.ILOAD_0.at(type, 4));
case 1:
return emitOp(Opcode.ILOAD_1.at(type, 4));
case 2:
return emitOp(Opcode.ILOAD_2.at(type, 4));
case 3:
return emitOp(Opcode.ILOAD_3.at(type, 4));
default:
return emitWideIfNeeded(Opcode.ILOAD.at(type), n);
}
}
}
public C store(TypeTag type, int n) {
if (type == TypeTag.Q) {
return vstore(n);
} else {
switch (n) {
case 0:
return emitOp(Opcode.ISTORE_0.at(type, 4));
case 1:
return emitOp(Opcode.ISTORE_1.at(type, 4));
case 2:
return emitOp(Opcode.ISTORE_2.at(type, 4));
case 3:
return emitOp(Opcode.ISTORE_3.at(type, 4));
default:
return emitWideIfNeeded(Opcode.ISTORE.at(type), n);
}
}
}
public C arrayload(TypeTag type) {
return emitOp(Opcode.IALOAD.at(type));
}
public C arraystore(TypeTag type, int n) {
return emitOp(Opcode.IASTORE.at(type));
}
public C const_(int i) {
switch (i) {
case -1:
return iconst_m1();
case 0:
return iconst_0();
case 1:
return iconst_1();
case 2:
return iconst_2();
case 3:
return iconst_3();
case 4:
return iconst_4();
case 5:
return iconst_5();
default:
if (i > 0 && i <= Byte.MAX_VALUE) {
return bipush(i);
} else if (i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) {
return sipush(i);
} else {
return ldc(i);
}
}
}
public C const_(long l) {
if (l == 0) {
return lconst_0();
} else if (l == 1) {
return lconst_1();
} else {
return ldc(l);
}
}
public C const_(float f) {
if (f == 0) {
return fconst_0();
} else if (f == 1) {
return fconst_1();
} else if (f == 2) {
return fconst_2();
} else {
return ldc(f);
}
}
public C const_(double d) {
if (d == 0) {
return dconst_0();
} else if (d == 1) {
return dconst_1();
} else {
return ldc(d);
}
}
public C getfield(FieldAccessKind fak, S owner, CharSequence name, T type) {
switch (fak) {
case INSTANCE:
return getfield(owner, name, type);
case STATIC:
return getstatic(owner, name, type);
default:
throw new IllegalStateException();
}
}
public C putfield(FieldAccessKind fak, S owner, CharSequence name, T type) {
switch (fak) {
case INSTANCE:
return putfield(owner, name, type);
case STATIC:
return putstatic(owner, name, type);
default:
throw new IllegalStateException();
}
}
public C invoke(InvocationKind ik, S owner, CharSequence name, T type, boolean isInterface) {
switch (ik) {
case INVOKESTATIC:
return invokestatic(owner, name, type, isInterface);
case INVOKEVIRTUAL:
return invokevirtual(owner, name, type, isInterface);
case INVOKESPECIAL:
return invokespecial(owner, name, type, isInterface);
case INVOKEINTERFACE:
if (!isInterface) throw new AssertionError();
return invokeinterface(owner, name, type);
default:
throw new IllegalStateException();
}
}
public C add(TypeTag type) {
return emitOp(Opcode.IADD.at(type));
}
public C sub(TypeTag type) {
return emitOp(Opcode.ISUB.at(type));
}
public C mul(TypeTag type) {
return emitOp(Opcode.IMUL.at(type));
}
public C div(TypeTag type) {
return emitOp(Opcode.IDIV.at(type));
}
public C rem(TypeTag type) {
return emitOp(Opcode.IREM.at(type));
}
public C neg(TypeTag type) {
return emitOp(Opcode.INEG.at(type));
}
public C shl(TypeTag type) {
return emitOp(Opcode.ISHL.at(type));
}
public C shr(TypeTag type) {
return emitOp(Opcode.ISHR.at(type));
}
public C ushr(TypeTag type) {
return emitOp(Opcode.ISHR.at(type));
}
public C and(TypeTag type) {
return emitOp(Opcode.IAND.at(type));
}
public C or(TypeTag type) {
return emitOp(Opcode.IOR.at(type));
}
public C xor(TypeTag type) {
return emitOp(Opcode.IXOR.at(type));
}
public C return_(TypeTag type) {
switch (type) {
case V:
return return_();
case Q:
return vreturn();
default:
return emitOp(Opcode.IRETURN.at(type));
}
}
@Override
public LabelledTypedBuilder typed(TypeTag typeTag) {
return super.typed(typeTag, _unused -> new LabelledTypedBuilder());
}
public class LabelledTypedBuilder extends TypedBuilder {
public C if_acmpeq(CharSequence target) {
return ifcmp(TypeTag.A, CondKind.EQ, target);
}
public C if_acmpne(CharSequence target) {
return ifcmp(TypeTag.A, CondKind.NE, target);
}
}
public C conv(TypeTag from, TypeTag to) {
switch (from) {
case B:
case C:
case S:
switch (to) {
case J:
return i2l();
case F:
return i2f();
case D:
return i2d();
}
break;
case I:
switch (to) {
case J:
return i2l();
case F:
return i2f();
case D:
return i2d();
case B:
return i2b();
case C:
return i2c();
case S:
return i2s();
}
break;
case J:
switch (to) {
case I:
return l2i();
case F:
return l2f();
case D:
return l2d();
}
break;
case F:
switch (to) {
case I:
return f2i();
case J:
return f2l();
case D:
return f2d();
}
break;
case D:
switch (to) {
case I:
return d2i();
case J:
return d2l();
case F:
return d2f();
}
break;
}
//no conversion is necessary - do nothing!
return thisBuilder();
}
public C if_null(CharSequence label) {
return emitCondJump(Opcode.IF_NULL, Opcode.IF_NONNULL, label);
}
public C if_nonnull(CharSequence label) {
return emitCondJump(Opcode.IF_NONNULL, Opcode.IF_NULL, label);
}
public C ifcmp(TypeTag type, CondKind cond, CharSequence label) {
switch (type) {
case I:
return emitCondJump(Opcode.IF_ICMPEQ, cond, label);
case A:
return emitCondJump(Opcode.IF_ACMPEQ, cond, label);
case J:
return lcmp().emitCondJump(Opcode.IFEQ, cond, label);
case D:
return dcmpg().emitCondJump(Opcode.IFEQ, cond, label);
case F:
return fcmpg().emitCondJump(Opcode.IFEQ, cond, label);
default:
throw new IllegalArgumentException("Bad cmp type");
}
}
public C goto_(CharSequence label) {
emitOp(jumpMode == JumpMode.NARROW ? Opcode.GOTO_ : Opcode.GOTO_W);
emitOffset(code, jumpMode, labelOffset(label));
return thisBuilder();
}
protected int labelOffset(CharSequence label) {
int pc = code.offset - 1;
Integer labelPc = labels.get(label);
if (labelPc == null) {
addPendingJump(label, pc);
}
return labelPc == null ? 0 : (labelPc - pc);
}
public C label(CharSequence s) {
int pc = code.offset;
Object old = labels.put(s, pc);
if (old != null) {
throw new IllegalStateException("label already exists");
}
resolveJumps(s, pc);
return thisBuilder();
}
//FIXME: address this jumpy mess - i.e. offset and state update work against each other!
public C emitCondJump(Opcode opcode, CondKind ck, CharSequence label) {
return emitCondJump(opcode.at(ck), opcode.at(ck.negate()), label);
}
public C emitCondJump(Opcode pos, Opcode neg, CharSequence label) {
if (jumpMode == JumpMode.NARROW) {
emitOp(pos);
emitOffset(code, jumpMode, labelOffset(label));
} else {
emitOp(neg);
emitOffset(code, JumpMode.NARROW, 8);
goto_w(labelOffset(label));
}
return thisBuilder();
}
void addPendingJump(CharSequence label, int pc) {
pendingJumps.add(new PendingJump(label, pc));
}
void resolveJumps(CharSequence label, int pc) {
Iterator<PendingJump> jumpsIt = pendingJumps.iterator();
while (jumpsIt.hasNext()) {
PendingJump jump = jumpsIt.next();
if (jump.resolve(label, pc)) {
jumpsIt.remove();
}
}
}
@Override
protected void emitOffset(GrowableByteBuffer buf, JumpMode jumpMode, int offset) {
if (jumpMode == JumpMode.NARROW && (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE)) {
throw new WideJumpException();
}
super.emitOffset(buf, jumpMode, offset);
}
public C jsr(CharSequence label) {
emitOp(jumpMode == JumpMode.NARROW ? Opcode.JSR : Opcode.JSR_W);
emitOffset(code, jumpMode, labelOffset(label));
return thisBuilder();
}
@SuppressWarnings("unchecked")
public C withTry(Consumer<? super C> tryBlock, Consumer<? super CatchBuilder> catchBlocks) {
int start = code.offset;
tryBlock.accept((C) this);
int end = code.offset;
CatchBuilder catchBuilder = makeCatchBuilder(start, end);
catchBlocks.accept(catchBuilder);
catchBuilder.build();
return thisBuilder();
}
void clear() {
code.offset = 0;
catchers.offset = 0;
ncatchers = 0;
labels.clear();
pendingJumps = null;
}
protected CatchBuilder makeCatchBuilder(int start, int end) {
return new CatchBuilder(start, end);
}
public class CatchBuilder {
int start, end;
String endLabel = labelName();
Map<S, Consumer<? super C>> catchers = new LinkedHashMap<>();
public Consumer<? super C> finalizer;
List<Integer> pendingGaps = new ArrayList<>();
public CatchBuilder(int start, int end) {
this.start = start;
this.end = end;
}
public CatchBuilder withCatch(S exc, Consumer<? super C> catcher) {
catchers.put(exc, catcher);
return this;
}
public CatchBuilder withFinally(Consumer<? super C> finalizer) {
this.finalizer = finalizer;
return this;
}
@SuppressWarnings("unchecked")
void build() {
if (finalizer != null) {
finalizer.accept((C) MacroCodeBuilder.this);
}
goto_(endLabel);
for (Map.Entry<S, Consumer<? super C>> catcher_entry : catchers.entrySet()) {
emitCatch(catcher_entry.getKey(), catcher_entry.getValue());
}
if (finalizer != null) {
emitFinalizer();
}
resolveJumps(endLabel, code.offset);
}
@SuppressWarnings("unchecked")
protected void emitCatch(S exc, Consumer<? super C> catcher) {
int offset = code.offset;
MacroCodeBuilder.this.withCatch(exc, start, end, offset);
catcher.accept((C) MacroCodeBuilder.this);
if (finalizer != null) {
int startFinalizer = code.offset;
finalizer.accept((C) MacroCodeBuilder.this);
pendingGaps.add(startFinalizer);
pendingGaps.add(code.offset);
}
goto_(endLabel);
}
@SuppressWarnings("unchecked")
protected void emitFinalizer() {
int offset = code.offset;
pop();
for (int i = 0; i < pendingGaps.size(); i += 2) {
MacroCodeBuilder.this.withCatch(null, pendingGaps.get(i), pendingGaps.get(i + 1), offset);
}
MacroCodeBuilder.this.withCatch(null, start, end, offset);
finalizer.accept((C) MacroCodeBuilder.this);
}
// @SuppressWarnings("unchecked")
// CatchBuilder withCatch(S exc, Consumer<? super C> catcher) {
// int offset = code.offset;
// MacroCodeBuilder.this.withCatch(exc, start, end, offset);
// catcher.accept((C)MacroCodeBuilder.this);
// return this;
// }
//
// @SuppressWarnings("unchecked")
// CatchBuilder withFinally(Consumer<? super C> catcher) {
// int offset = code.offset;
// MacroCodeBuilder.this.withCatch(null, start, end, offset);
// catcher.accept((C)MacroCodeBuilder.this);
// return this;
// }
}
@SuppressWarnings("unchecked")
public C switch_(Consumer<? super SwitchBuilder> consumer) {
int start = code.offset;
SwitchBuilder sb = makeSwitchBuilder();
consumer.accept(sb);
int nlabels = sb.cases.size();
switch (sb.switchCode()) {
case LOOKUPSWITCH: {
int[] lookupOffsets = new int[nlabels * 2];
int i = 0;
for (Integer v : sb.cases.keySet()) {
lookupOffsets[i] = v;
i += 2;
}
lookupswitch(0, lookupOffsets);
//backpatch lookup
int curr = code.offset - (8 * nlabels) - 8;
int defaultOffset = code.offset - start;
code.withOffset(curr, buf -> emitOffset(buf, JumpMode.WIDE, defaultOffset));
sb.defaultCase.accept((C) this);
curr += 12;
for (Consumer<? super C> case_ : sb.cases.values()) {
int offset = code.offset;
code.withOffset(curr, buf -> emitOffset(buf, JumpMode.WIDE, offset - start));
case_.accept((C) this);
curr += 8;
}
break;
}
case TABLESWITCH: {
int[] tableOffsets = new int[sb.hi - sb.lo + 1];
tableswitch(sb.lo, sb.hi, 0, tableOffsets);
//backpatch table
int curr = code.offset - (4 * tableOffsets.length) - 12;
int defaultOffset = code.offset - start;
code.withOffset(curr, buf -> emitOffset(buf, JumpMode.WIDE, defaultOffset));
sb.defaultCase.accept((C) this);
curr += 12;
int lastCasePc = -1;
for (int i = sb.lo; i <= sb.hi; i++) {
Consumer<? super C> case_ = sb.cases.get(i);
if (case_ != null) {
lastCasePc = code.offset;
case_.accept((C) this);
}
int offset = lastCasePc - start;
code.withOffset(curr, buf -> emitOffset(buf, JumpMode.WIDE, offset));
curr += 4;
}
}
}
resolveJumps(sb.endLabel, code.offset);
return thisBuilder();
}
private static int labelCount = 0;
String labelName() {
return "label" + labelCount++;
}
protected SwitchBuilder makeSwitchBuilder() {
return new SwitchBuilder();
}
public class SwitchBuilder {
Map<Integer, Consumer<? super C>> cases = new TreeMap<>();
int lo = Integer.MAX_VALUE;
int hi = Integer.MIN_VALUE;
String endLabel = labelName();
public Consumer<? super C> defaultCase;
@SuppressWarnings("unchecked")
public SwitchBuilder withCase(int value, Consumer<? super C> case_, boolean fallthrough) {
if (value > hi) {
hi = value;
}
if (value < lo) {
lo = value;
}
if (!fallthrough) {
Consumer<? super C> prevCase = case_;
case_ = C -> {
prevCase.accept(C);
C.goto_(endLabel);
};
}
cases.put(value, case_);
return this;
}
@SuppressWarnings("unchecked")
public SwitchBuilder withDefault(Consumer<? super C> defaultCase) {
if (this.defaultCase != null) {
throw new IllegalStateException("default already set");
}
this.defaultCase = defaultCase;
return this;
}
Opcode switchCode() {
int nlabels = cases.size();
// Determine whether to issue a tableswitch or a lookupswitch
// instruction.
long table_space_cost = 4 + ((long) hi - lo + 1); // words
long lookup_space_cost = 3 + 2 * (long) nlabels;
return
nlabels > 0 &&
table_space_cost <= lookup_space_cost
?
Opcode.TABLESWITCH : Opcode.LOOKUPSWITCH;
}
}
}

View file

@ -1,78 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
/**
* Class member builder.
*
* @param <S> the type of symbol representation
* @param <T> the type of type descriptors representation
* @param <E> the type of pool entries
* @param <M> the type of this builder
*/
public class MemberBuilder<S, T, E, M extends MemberBuilder<S, T, E, M>> extends DeclBuilder<S, T, E, M> {
CharSequence name;
T desc;
/**
* Create a member builder.
*
* @param name the name of the class member
* @param type the type descriptor of the class member
* @param poolHelper the helper to build the constant pool
* @param typeHelper the helper to use to manipulate type descriptors
*/
MemberBuilder(CharSequence name, T type, PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
super(poolHelper, typeHelper);
this.name = name;
this.desc = type;
}
/**
* Build the member.
*
* @param buf the {@code GrowableByteBuffer} to build the member into
*/
protected void build(GrowableByteBuffer buf) {
addAnnotations();
buf.writeChar(flags);
buf.writeChar(poolHelper.putUtf8(name));
buf.writeChar(poolHelper.putType(desc));
buf.writeChar(nattrs);
buf.writeBytes(attributes);
}
/**
* Build the member.
*
* @return a byte array representation of the member
*/
protected byte[] build() {
GrowableByteBuffer buf = new GrowableByteBuffer();
addAnnotations();
build(buf);
return buf.bytes();
}
}

View file

@ -1,156 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import jdk.experimental.bytecode.CodeBuilder.JumpMode;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.function.Function;
public class MethodBuilder<S, T, E> extends MemberBuilder<S, T, E, MethodBuilder<S, T, E>> {
S thisClass;
ParameterAnnotationsBuilder runtimeVisibleParameterAnnotations;
ParameterAnnotationsBuilder runtimeInvisibleParameterAnnotations;
public MethodBuilder(S thisClass, CharSequence name, T type, PoolHelper<S, T, E> pool, TypeHelper<S, T> typeHelper) {
super(name, type, pool, typeHelper);
this.thisClass = thisClass;
}
public <C extends CodeBuilder<S, T, E, ?>> MethodBuilder<S, T, E> withCode(Function<? super MethodBuilder<S, T, E>, ? extends C> func,
Consumer<? super C> code) {
C codeBuilder = func.apply(this);
int start = attributes.offset;
try {
code.accept(codeBuilder);
} catch (MacroCodeBuilder.WideJumpException ex) {
//wide jumps! Redo the code
((MacroCodeBuilder<S, T, E, ?>) codeBuilder).jumpMode = JumpMode.WIDE;
((MacroCodeBuilder<S, T, E, ?>) codeBuilder).clear();
code.accept(codeBuilder);
}
attributes.writeChar(poolHelper.putUtf8("Code"));
attributes.writeInt(0);
codeBuilder.build(attributes);
int length = attributes.offset - start;
//avoid using lambda here
int prevOffset = attributes.offset;
try {
attributes.offset = start + 2;
attributes.writeInt(length - 6);
} finally {
attributes.offset = prevOffset;
}
nattrs++;
return this;
}
public MethodBuilder<S, T, E> withCode(Consumer<? super CodeBuilder<S, T, E, ?>> code) {
return withCode(CodeBuilder::new, code);
}
@SuppressWarnings({"varargs", "unchecked"})
public MethodBuilder<S, T, E> withExceptions(S... exceptions) {
attributes.writeChar(poolHelper.putUtf8("Exceptions"));
attributes.writeInt(2 + (2 * exceptions.length));
attributes.writeChar(exceptions.length);
for (S exception : exceptions) {
attributes.writeChar(poolHelper.putClass(exception));
}
nattrs++;
return this;
}
public MethodBuilder<S, T, E> withParameterAnnotation(AnnotationsBuilder.Kind kind, int nparam, T annoType) {
getParameterAnnotations(kind).builders[nparam].withAnnotation(annoType, null);
return this;
}
public MethodBuilder<S, T, E> withParameterAnnotation(AnnotationsBuilder.Kind kind, int nparam, T annoType, Consumer<? super AnnotationsBuilder<S, T, E>.AnnotationElementBuilder> annotations) {
getParameterAnnotations(kind).builders[nparam].withAnnotation(annoType, annotations);
return this;
}
private ParameterAnnotationsBuilder getParameterAnnotations(AnnotationsBuilder.Kind kind) {
switch (kind) {
case RUNTIME_INVISIBLE:
if (runtimeInvisibleParameterAnnotations == null) {
runtimeInvisibleParameterAnnotations = new ParameterAnnotationsBuilder();
}
return runtimeInvisibleParameterAnnotations;
case RUNTIME_VISIBLE:
if (runtimeVisibleParameterAnnotations == null) {
runtimeVisibleParameterAnnotations = new ParameterAnnotationsBuilder();
}
return runtimeVisibleParameterAnnotations;
}
throw new IllegalStateException();
}
class ParameterAnnotationsBuilder {
GrowableByteBuffer parameterAnnos = new GrowableByteBuffer();
@SuppressWarnings({"unchecked", "rawtypes"})
AnnotationsBuilder<S, T, E>[] builders = new AnnotationsBuilder[nparams()];
ParameterAnnotationsBuilder() {
for (int i = 0; i < builders.length; i++) {
builders[i] = new AnnotationsBuilder<>(poolHelper, typeHelper);
}
}
byte[] build() {
parameterAnnos.writeByte(builders.length);
for (AnnotationsBuilder<S, T, E> builder : builders) {
parameterAnnos.writeBytes(builder.build());
}
return parameterAnnos.bytes();
}
int nparams() {
Iterator<T> paramsIt = typeHelper.parameterTypes(desc);
int nparams = 0;
while (paramsIt.hasNext()) {
paramsIt.next();
nparams++;
}
return nparams;
}
}
@Override
void addAnnotations() {
super.addAnnotations();
if (runtimeInvisibleParameterAnnotations != null) {
withAttribute("RuntimeInvisibleParameterAnnotations", runtimeInvisibleParameterAnnotations.build());
}
if (runtimeVisibleParameterAnnotations != null) {
withAttribute("RuntimeVisibleParameterAnnotations", runtimeVisibleParameterAnnotations.build());
}
}
}

View file

@ -1,267 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import jdk.experimental.bytecode.MacroCodeBuilder.CondKind;
public enum Opcode {
NOP(0),
ACONST_NULL(1),
ICONST_M1(2),
ICONST_0(3),
ICONST_1(4),
ICONST_2(5),
ICONST_3(6),
ICONST_4(7),
ICONST_5(8),
LCONST_0(9),
LCONST_1(10),
FCONST_0(11),
FCONST_1(12),
FCONST_2(13),
DCONST_0(14),
DCONST_1(15),
BIPUSH(16),
SIPUSH(17),
LDC(18),
LDC_W(19),
LDC2_W(20),
ILOAD(21),
LLOAD(22),
FLOAD(23),
DLOAD(24),
ALOAD(25),
ILOAD_0(26),
ILOAD_1(27),
ILOAD_2(28),
ILOAD_3(29),
LLOAD_0(30),
LLOAD_1(31),
LLOAD_2(32),
LLOAD_3(33),
FLOAD_0(34),
FLOAD_1(35),
FLOAD_2(36),
FLOAD_3(37),
DLOAD_0(38),
DLOAD_1(39),
DLOAD_2(40),
DLOAD_3(41),
ALOAD_0(42),
ALOAD_1(43),
ALOAD_2(44),
ALOAD_3(45),
IALOAD(46),
LALOAD(47),
FALOAD(48),
DALOAD(49),
AALOAD(50),
BALOAD(51),
CALOAD(52),
SALOAD(53),
ISTORE(54),
LSTORE(55),
FSTORE(56),
DSTORE(57),
ASTORE(58),
ISTORE_0(59),
ISTORE_1(60),
ISTORE_2(61),
ISTORE_3(62),
LSTORE_0(63),
LSTORE_1(64),
LSTORE_2(65),
LSTORE_3(66),
FSTORE_0(67),
FSTORE_1(68),
FSTORE_2(69),
FSTORE_3(70),
DSTORE_0(71),
DSTORE_1(72),
DSTORE_2(73),
DSTORE_3(74),
ASTORE_0(75),
ASTORE_1(76),
ASTORE_2(77),
ASTORE_3(78),
IASTORE(79),
LASTORE(80),
FASTORE(81),
DASTORE(82),
AASTORE(83),
BASTORE(84),
CASTORE(85),
SASTORE(86),
POP(87),
POP2(88),
DUP(89),
DUP_X1(90),
DUP_X2(91),
DUP2(92),
DUP2_X1(93),
DUP2_X2(94),
SWAP(95),
IADD(96),
LADD(97),
FADD(98),
DADD(99),
ISUB(100),
LSUB(101),
FSUB(102),
DSUB(103),
IMUL(104),
LMUL(105),
FMUL(106),
DMUL(107),
IDIV(108),
LDIV(109),
FDIV(110),
DDIV(111),
IREM(112),
LREM(113),
FREM(114),
DREM(115),
INEG(116),
LNEG(117),
FNEG(118),
DNEG(119),
ISHL(120),
LSHL(121),
ISHR(122),
LSHR(123),
IUSHR(124),
LUSHR(125),
IAND(126),
LAND(127),
IOR(128),
LOR(129),
IXOR(130),
LXOR(131),
IINC(132),
I2L(133),
I2F(134),
I2D(135),
L2I(136),
L2F(137),
L2D(138),
F2I(139),
F2L(140),
F2D(141),
D2I(142),
D2L(143),
D2F(144),
I2B(145),
I2C(146),
I2S(147),
LCMP(148),
FCMPL(149),
FCMPG(150),
DCMPL(151),
DCMPG(152),
IFEQ(153),
IFNE(154),
IFLT(155),
IFGE(156),
IFGT(157),
IFLE(158),
IF_ICMPEQ(159),
IF_ICMPNE(160),
IF_ICMPLT(161),
IF_ICMPGE(162),
IF_ICMPGT(163),
IF_ICMPLE(164),
IF_ACMPEQ(165),
IF_ACMPNE(166),
GOTO_(167),
JSR(168),
RET(169),
TABLESWITCH(170),
LOOKUPSWITCH(171),
IRETURN(172),
LRETURN(173),
FRETURN(174),
DRETURN(175),
ARETURN(176),
RETURN(177),
GETSTATIC(178),
PUTSTATIC(179),
GETFIELD(180),
PUTFIELD(181),
INVOKEVIRTUAL(182),
INVOKESPECIAL(183),
INVOKESTATIC(184),
INVOKEINTERFACE(185),
INVOKEDYNAMIC(186),
NEW(187),
NEWARRAY(188),
ANEWARRAY(189),
ARRAYLENGTH(190),
ATHROW(191),
CHECKCAST(192),
INSTANCEOF(193),
MONITORENTER(194),
MONITOREXIT(195),
WIDE(196),
MULTIANEWARRAY(197),
IF_NULL(198),
IF_NONNULL(199),
GOTO_W(200),
JSR_W(201),
VLOAD(203),
VSTORE(204),
VALOAD(205),
VASTORE(206),
VNEW(207),
VNEWARRAY(208),
MULTIVNEWARRAY(209),
VRETURN(210),
VGETFIELD(211),
TYPED(212),
VBOX(216),
VUNBOX(217);
int code;
Opcode(int code) {
this.code = code;
}
protected Opcode at(TypeTag type) {
return at(type, 1);
}
protected Opcode at(CondKind cond) {
return at(cond.offset, 1);
}
protected Opcode at(TypeTag type, int multiplier) {
return at(type.offset, multiplier);
}
private Opcode at(int offset, int multiplier) {
if (offset < 0) throw new AssertionError();
return Opcode.values()[code + (multiplier * offset)];
}
}

View file

@ -1,81 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import java.util.function.Consumer;
import java.util.function.ToIntBiFunction;
/**
* An interface for building and tracking constant pools.
*
* @param <S> the type of the symbol representation
* @param <T> the type of type descriptors representation
* @param <E> the type of pool entries
*/
public interface PoolHelper<S, T, E> {
int putClass(S symbol);
int putFieldRef(S owner, CharSequence name, T type);
int putMethodRef(S owner, CharSequence name, T type, boolean isInterface);
int putUtf8(CharSequence s);
int putInt(int i);
int putFloat(float f);
int putLong(long l);
int putDouble(double d);
int putString(String s);
int putType(T t);
int putMethodType(T t);
int putHandle(int refKind, S owner, CharSequence name, T type);
int putHandle(int refKind, S owner, CharSequence name, T type, boolean isInterface);
int putInvokeDynamic(CharSequence invokedName, T invokedType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, E>> staticArgs);
int putDynamicConstant(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, E>> staticArgs);
int size();
E entries();
interface StaticArgListBuilder<S, T, E> {
StaticArgListBuilder<S, T, E> add(int i);
StaticArgListBuilder<S, T, E> add(float f);
StaticArgListBuilder<S, T, E> add(long l);
StaticArgListBuilder<S, T, E> add(double d);
StaticArgListBuilder<S, T, E> add(String s);
StaticArgListBuilder<S, T, E> add(int refKind, S owner, CharSequence name, T type);
<Z> StaticArgListBuilder<S, T, E> add(Z z, ToIntBiFunction<PoolHelper<S, T, E>, Z> poolFunc);
StaticArgListBuilder<S, T, E> add(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, E>> staticArgList);
}
}

View file

@ -1,53 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
public enum PoolTag {
CONSTANT_UTF8(1),
CONSTANT_UNICODE(2),
CONSTANT_INTEGER(3),
CONSTANT_FLOAT(4),
CONSTANT_LONG(5),
CONSTANT_DOUBLE(6),
CONSTANT_CLASS(7),
CONSTANT_STRING(8),
CONSTANT_FIELDREF(9),
CONSTANT_METHODREF(10),
CONSTANT_INTERFACEMETHODREF(11),
CONSTANT_NAMEANDTYPE(12),
CONSTANT_METHODHANDLE(15),
CONSTANT_METHODTYPE(16),
CONSTANT_DYNAMIC(17),
CONSTANT_INVOKEDYNAMIC(18);
public final int tag;
PoolTag(int tag) {
this.tag = tag;
}
static PoolTag from(int tag) {
return values()[tag - 1];
}
}

View file

@ -1,28 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
public interface Type {
TypeTag getTag();
}

View file

@ -1,126 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
import java.util.Iterator;
/**
* Helper to create and manipulate type descriptors of T.
*
* @param <S> the type of symbols
* @param <T> the type of type descriptors
*/
public interface TypeHelper<S, T> {
/**
* Return the type descriptor of an element given the type
* descriptor of an array.
*
* @param t the type descriptor of the array
* @return the element type
*/
T elemtype(T t);
/**
* Return the type descriptor of an array given the type descriptor
* of an element.
*
* @param t the type descriptor of the element
* @return the type descriptor of the array
*/
T arrayOf(T t);
/**
* Return an iterator over the type descriptors of the parameters of a
* method.
*
* @param t the method type descriptor
* @return an iterator over the type descriptors of the parameters
*/
Iterator<T> parameterTypes(T t);
/**
* Return the type descriptor of a {@code TypeTag}.
*
* @param tag the {@code TypeTag} of a primitive type
* @return the type descriptor of the primitive type
*/
T fromTag(TypeTag tag);
/**
* Return the return type descriptor of a method.
*
* @param t the method type descriptor
* @return the return type descriptor
*/
T returnType(T t);
/**
* Return the type descriptor for a symbol.
*
* @param s the symbol
* @return the type descriptor
*/
T type(S s);
/**
* Return the symbol corresponding to a type descriptor.
*
* @param type the type descriptor
* @return the symbol
*/
S symbol(T type);
/**
* Return the {@code TypeTag} corresponding to a type descriptor. Reference
* types return {@code TypeTag.A}.
*
* @param t a type descriptor
* @return the corresponding {@code TypeTag}
*/
TypeTag tag(T t);
/**
* Return the symbol corresponding to a JVM type descriptor string.
*
* @param s a JVM type descriptor string
* @return the corresponding symbol
*/
S symbolFrom(String s);
/**
* Return the common supertype descriptor of two type descriptors.
*
* @param t1 a type descriptor
* @param t2 a type descriptor
* @return the common supertype descriptor
*/
T commonSupertype(T t1, T t2);
/**
* Return the type descriptor for the null type.
*
* @return the type descriptor for the null type
*/
T nullType();
}

View file

@ -1,113 +0,0 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.experimental.bytecode;
public enum TypeTag implements Type {
/**
* byte
*/
B("B", 0, 1, 8),
/**
* short
*/
S("S", 0, 1, 9),
/**
* int
*/
I("I", 0, 1, 10),
/**
* float
*/
F("F", 2, 1, 6),
/**
* long
*/
J("J", 1, 2, 11),
/**
* double
*/
D("D", 3, 2, 7),
/**
* Reference type
*/
A("A", 4, 1, -1),
/**
* char
*/
C("C", 0, 1, 5),
/**
* boolean
*/
Z("Z", 0, 1, 4),
/**
* void
*/
V("V", -1, -1, -1),
/**
* Value type
*/
Q("Q", -1, 1, -1);
String typeStr;
int offset;
int width;
int newarraycode;
TypeTag(String typeStr, int offset, int width, int newarraycode) {
this.typeStr = typeStr;
this.offset = offset;
this.width = width;
this.newarraycode = newarraycode;
}
static TypeTag commonSupertype(TypeTag t1, TypeTag t2) {
if (t1.isIntegral() && t2.isIntegral()) {
int p1 = t1.ordinal();
int p2 = t2.ordinal();
return (p1 <= p2) ? t2 : t1;
} else {
return null;
}
}
public int width() {
return width;
}
boolean isIntegral() {
switch (this) {
case B:
case S:
case I:
return true;
default:
return false;
}
}
@Override
public TypeTag getTag() {
return this;
}
}