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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,18 +25,23 @@
* @test
* @bug 8186046
* @summary Test for an interface using condy with default overpass methods
* @library /lib/testlibrary/bytecode
* @build jdk.experimental.bytecode.BasicClassBuilder
* @library /java/lang/invoke/common
* @build test.java.lang.invoke.lib.InstructionHelper
* @modules java.base/jdk.internal.classfile
* java.base/jdk.internal.classfile.attribute
* java.base/jdk.internal.classfile.constantpool
* java.base/jdk.internal.classfile.instruction
* java.base/jdk.internal.classfile.components
* @run testng CondyInterfaceWithOverpassMethods
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyInterfaceWithOverpassMethods
*/
import jdk.experimental.bytecode.BasicClassBuilder;
import jdk.experimental.bytecode.Flag;
import jdk.experimental.bytecode.TypedCodeBuilder;
import jdk.internal.classfile.Classfile;
import org.testng.annotations.BeforeClass;
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.MethodType;
@ -70,24 +75,32 @@ public class CondyInterfaceWithOverpassMethods {
Class<?> thisClass = CondyInterfaceWithOverpassMethods.class;
String genClassName = thisClass.getSimpleName() + "$Code";
String bsmClassName = thisClass.getCanonicalName().replace('.', '/');
String bsmClassName = thisClass.descriptorString();
String bsmMethodName = "bsm";
String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class,
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();
String.class, Class.class).toMethodDescriptorString();
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);
}

View File

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

View File

@ -26,6 +26,11 @@
* @bug 8186046
* @summary Test nested dynamic constant declarations that are recursive
* @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/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyNestedTest
*/
@ -34,21 +39,17 @@ import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class CondyNestedTest {
static final Class[] THROWABLES = {InvocationTargetException.class, StackOverflowError.class};
private static final MethodHandles.Lookup L = MethodHandles.lookup();
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();
//
// /**
@ -65,97 +66,178 @@ public class CondyNestedTest {
// */
// public static byte[] generator() throws Exception {
// String genClassName = L.lookupClass().getSimpleName() + "_Code";
// 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();
// ClassDesc genClassDesc = ClassDesc.of(genClassName);
// 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 ->
// M.withFlags(Flag.ACC_PUBLIC)
// .withCode(TypedCodeBuilder::new, C ->
// C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_()
// ))
// .withMethod("main", "([Ljava/lang/String;)V", M ->
// M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
// .withCode(TypedCodeBuilder::new, C -> {
// C.aload_0().iconst_0().aaload();
// C.invokevirtual("java/lang/String", "intern", "()Ljava/lang/String;", false);
// C.astore_1();
//
// C.aload_1();
// C.ldc("condy_bsm_condy_bsm");
// C.ifcmp(TypeTag.A, MacroCodeBuilder.CondKind.NE, "CASE1");
// C.invokestatic(genClassName, "condy_bsm_condy_bsm", "()Ljava/lang/Object;", false).return_();
//
// C.label("CASE1");
// C.aload_1();
// C.ldc("indy_bsmIndy_condy_bsm");
// C.ifcmp(TypeTag.A, MacroCodeBuilder.CondKind.NE, "CASE2");
// C.invokestatic(genClassName, "indy_bsmIndy_condy_bsm", "()Ljava/lang/Object;", false).return_();
//
// C.label("CASE2");
// C.aload_1();
// C.ldc("indy_bsm_condy_bsm");
// C.ifcmp(TypeTag.A, MacroCodeBuilder.CondKind.NE, "CASE3");
// C.invokestatic(genClassName, "indy_bsm_condy_bsm", "()Ljava/lang/Object;", false).return_();
//
// C.label("CASE3");
// C.return_();
// }))
// .withMethod("bsm", bsmDescriptor, M ->
// M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
// .withCode(TypedCodeBuilder::new, C -> {
// C.aload_2();
// C.instanceof_("java/lang/invoke/MethodType");
// C.iconst_0();
// C.ifcmp(TypeTag.I, MacroCodeBuilder.CondKind.EQ, "CONDY");
// C.new_("java/lang/invoke/ConstantCallSite").dup();
// C.ldc("java/lang/String", PoolHelper::putClass);
// C.aload_1();
// C.invokestatic("java/lang/invoke/MethodHandles", "constant", "(Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;", false);
// C.invokespecial("java/lang/invoke/ConstantCallSite", "<init>", "(Ljava/lang/invoke/MethodHandle;)V", false);
// C.areturn();
// C.label("CONDY");
// C.aload_1().areturn();
// }))
// .withMethod("bsmIndy", bsmIndyDescriptor, M ->
// M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
// .withCode(TypedCodeBuilder::new, C -> {
// C.new_("java/lang/invoke/ConstantCallSite").dup();
// C.ldc("java/lang/String", PoolHelper::putClass);
// C.aload_1();
// C.invokestatic("java/lang/invoke/MethodHandles", "constant", "(Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;", false);
// C.invokespecial("java/lang/invoke/ConstantCallSite", "<init>", "(Ljava/lang/invoke/MethodHandle;)V", false);
// C.areturn();
// }))
// .withMethod("condy_bsm_condy_bsm", "()Ljava/lang/Object;", M ->
// M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
// .withCode(TypedCodeBuilder::new, C ->
// C.ldc("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()))
// .withMethod("indy_bsmIndy_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, "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();
// )
// )
// // an indy bsm, that returns a call site whose target is MethodHandles.constant(String.class, methodName)
// .withMethod("bsmIndy", MethodTypeDesc.ofDescriptor(bsmIndyDescriptor),
// Classfile.ACC_PUBLIC + Classfile.ACC_PUBLIC, methodBuilder -> methodBuilder
// .withCode(codeBuilder -> codeBuilder
// .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()
// )
// )
// .withMethod("condy_bsm_condy_bsm", MethodTypeDesc.of(ConstantDescs.CD_Object),
// Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
// .withCode(codeBuilder -> codeBuilder
// .ldc(DynamicConstantDesc.ofNamed(
// bsmMhDesc,
// "name",
// ConstantDescs.CD_String,
// DynamicConstantDesc.ofNamed(
// bsmMhDesc,
// "name",
// ConstantDescs.CD_String,
// "DUMMY_ARG"
// )
// )
// )
// .areturn()
// )
// )
// .withMethod("indy_bsmIndy_condy_bsm", MethodTypeDesc.of(ConstantDescs.CD_Object),
// Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
// .withCode(codeBuilder -> codeBuilder
// .invokedynamic(DynamicCallSiteDesc.of(
// bsmIndyMhDesc,
// "name",
// MethodTypeDesc.of(ConstantDescs.CD_String),
// DynamicConstantDesc.ofNamed(
// bsmMhDesc,
// "name",
// ConstantDescs.CD_String,
// "DUMMY_ARG"
// )
// )
// )
// .areturn()
// )
// )
// .withMethod("indy_bsm_condy_bsm", MethodTypeDesc.of(ConstantDescs.CD_Object),
// Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, methodBuilder -> methodBuilder
// .withCode(codeBuilder -> codeBuilder
// .invokedynamic(DynamicCallSiteDesc.of(
// bsmMhDesc,
// "name",
// MethodTypeDesc.of(ConstantDescs.CD_String),
// DynamicConstantDesc.ofNamed(
// bsmMhDesc,
// "name",
// ConstantDescs.CD_String,
// "DUMMY_ARG"
// )
// )
// )
// .areturn()
// )
// )
// );
//
// File f = new File(genClassName + ".class");
// if (f.getParentFile() != null) {
@ -163,15 +245,13 @@ public class CondyNestedTest {
// }
// new FileOutputStream(f).write(byteArray);
// return byteArray;
//
// }
static void test(Method m, Class<? extends Throwable>... ts) {
Throwable caught = null;
try {
m.invoke(null);
}
catch (Throwable t) {
} catch (Throwable t) {
caught = t;
}

View File

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

View File

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

View File

@ -25,22 +25,23 @@
* @test
* @bug 8186046
* @summary Test bootstrap arguments for condy
* @library /lib/testlibrary/bytecode /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper
* @library /java/lang/invoke/common
* @build test.java.lang.invoke.lib.InstructionHelper
* @modules java.base/jdk.internal.classfile
* java.base/jdk.internal.classfile.attribute
* java.base/jdk.internal.classfile.constantpool
* java.base/jdk.internal.classfile.instruction
* java.base/jdk.internal.classfile.components
* @run testng CondyStaticArgumentsTest
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyStaticArgumentsTest
*/
import jdk.experimental.bytecode.PoolHelper;
import org.testng.Assert;
import org.testng.annotations.Test;
import test.java.lang.invoke.lib.InstructionHelper;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandleInfo;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.constant.*;
import java.lang.invoke.*;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.MathContext;
@ -51,6 +52,8 @@ import static java.lang.invoke.MethodType.methodType;
public class CondyStaticArgumentsTest {
static final MethodHandles.Lookup L = MethodHandles.lookup();
private static final DirectMethodHandleDesc bigDecimalMhDesc = directMhDesc("bigDecimal");
private static final DirectMethodHandleDesc mathContextMhDesc = directMhDesc("mathContext");
static class BSMInfo {
final String methodName;
@ -65,8 +68,7 @@ public class CondyStaticArgumentsTest {
.get();
try {
handle = MethodHandles.lookup().unreflect(m);
}
catch (Exception e) {
} catch (Exception e) {
throw new Error(e);
}
descriptor = handle.type().toMethodDescriptorString();
@ -103,18 +105,18 @@ public class CondyStaticArgumentsTest {
MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "constant-name", String.class,
bi.methodName, bi.handle.type(),
S -> S.add(1).add(2L).add(3.0f).add(4.0d)
.add("java/lang/Number", PoolHelper::putClass)
.add("something", PoolHelper::putString)
.add("(IJFD)V", PoolHelper::putMethodType)
.add(mhi, (P, Z) -> {
return P.putHandle(mhi.getReferenceKind(), "CondyStaticArgumentsTest", mhi.getName(), bi.descriptor);
}));
1, 2L, 3.0f, 4.0d,
ClassDesc.ofDescriptor(Number.class.descriptorString()),
"something",
MethodTypeDesc.ofDescriptor("(IJFD)V"),
MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.valueOf(mhi.getReferenceKind()),
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");
}
static MathContext mathContext(MethodHandles.Lookup l, String value, Class<?> type) {
switch (value) {
case "UNLIMITED":
@ -145,22 +147,6 @@ public class CondyStaticArgumentsTest {
.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
public void testCondyWithCondy() throws Throwable {
BSMInfo bi = BSMInfo.of("condyWithCondy");
@ -168,9 +154,18 @@ public class CondyStaticArgumentsTest {
MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "big-decimal-math-context", String.class,
bi.methodName, bi.handle.type(),
S -> S.add(null, (P, v) -> {
return bigDecimalPoolHelper("3.14159265358979323846", "DECIMAL32", P);
}));
DynamicConstantDesc.ofNamed(
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");
}
@ -193,9 +188,27 @@ public class CondyStaticArgumentsTest {
MethodHandle mh = InstructionHelper.invokedynamic(
L, "big-decimal-math-context", methodType(String.class),
bi.methodName, bi.handle.type(),
S -> S.add(null, (P, v) -> {
return bigDecimalPoolHelper("3.14159265358979323846", "DECIMAL32", P);
}));
DynamicConstantDesc.ofNamed(
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");
}
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
* @bug 8186046
* @summary Test invalid name in name and type
* @library /lib/testlibrary/bytecode /java/lang/invoke/common
* @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper
* @library /java/lang/invoke/common
* @build test.java.lang.invoke.lib.InstructionHelper
* @modules java.base/jdk.internal.classfile
* java.base/jdk.internal.classfile.attribute
* java.base/jdk.internal.classfile.constantpool
* java.base/jdk.internal.classfile.instruction
* java.base/jdk.internal.classfile.components
* @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyTypeValidationTest
*/
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import test.java.lang.invoke.lib.InstructionHelper;
@ -49,29 +55,36 @@ public class CondyTypeValidationTest {
.toMethodDescriptorString();
@DataProvider
public Object[][] invalidTypesProvider() throws Exception {
public Object[][] invalidTypesProvider() {
return Stream.of(
// ByteCode API checks for the following invalid types
// "",
// "[",
// "A",
// "a",
"L/java/lang/Object",
Stream.generate(() -> "[").limit(256).collect(Collectors.joining("", "", "I")))
.map(e -> new Object[]{e}).toArray(Object[][]::new);
new Object[]{"L/java/lang/Object", "not a valid reference type descriptor"},
new Object[]{
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)
public void testInvalidTypes(String type) throws Exception {
MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", type,
"bsm", BSM_TYPE,
S -> {
});
@Test(dataProvider = "invalidTypesProvider")
public void testInvalidTypes(String type, String errMessContent) throws Exception {
try {
MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", type,
"bsm", BSM_TYPE
);
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage().contains(errMessContent));
}
}
@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"));
int l = t.size();
for (int i = 0; i < l; i++) {
@ -86,8 +99,7 @@ public class CondyTypeValidationTest {
public void testValidTypes(String type) throws Exception {
MethodHandle mh = InstructionHelper.ldcDynamicConstant(
L, "name", type,
"bsm", BSM_TYPE,
S -> {
});
"bsm", BSM_TYPE
);
}
}

View File

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

View File

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

View File

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