From c08c21ebd2b636d6bc9e3543aaf980f9e4733a04 Mon Sep 17 00:00:00 2001 From: Rich Bolen Date: Tue, 20 Aug 2019 10:52:01 -0400 Subject: [PATCH 1/6] Add support for the new Dynamic constant (17) created in java 11 --- pom.xml | 6 +- src/main/javassist/bytecode/Bytecode.java | 19 ++ .../javassist/bytecode/ClassFileWriter.java | 20 +- src/main/javassist/bytecode/ConstPool.java | 217 ++++++++++++++---- src/test/javassist/bytecode/BytecodeTest.java | 36 +++ src/test/test4/Dyn.java | 22 ++ 6 files changed, 269 insertions(+), 51 deletions(-) create mode 100644 src/test/test4/Dyn.java diff --git a/pom.xml b/pom.xml index c3bd1990..fc8e2fdf 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ Javassist (JAVA programming ASSISTant) makes Java bytecode manipulation simple. It is a class library for editing bytecodes in Java. - 3.25.0-GA + 3.25.1-GA Javassist http://www.javassist.org/ @@ -151,8 +151,8 @@ maven-compiler-plugin 3.2 - 1.7 - 1.7 + 9 + 9 11 11 -parameters diff --git a/src/main/javassist/bytecode/Bytecode.java b/src/main/javassist/bytecode/Bytecode.java index 37a6d127..193e3f8a 100644 --- a/src/main/javassist/bytecode/Bytecode.java +++ b/src/main/javassist/bytecode/Bytecode.java @@ -1240,6 +1240,25 @@ public void addInvokedynamic(int bootstrap, String name, String desc) { growStack(Descriptor.dataSize(desc)); // assume ConstPool#REF_invokeStatic } + /** + * Appends DYNAMIC. + * + * @param bootstrap an index into the bootstrap_methods array + * of the bootstrap method table. + * @param name the method name. + * @param desc the method descriptor. + * @see Descriptor#ofMethod(CtClass,CtClass[]) + * @since 3.17 + */ + public void addDynamic(int bootstrap, String name, String desc) { + int nt = constPool.addNameAndTypeInfo(name, desc); + int dyn = constPool.addDynamicInfo(bootstrap, nt); + add(INVOKEDYNAMIC); + addIndex(dyn); + add(0, 0); + growStack(Descriptor.dataSize(desc)); // assume ConstPool#REF_invokeStatic + } + /** * Appends LDC or LDC_W. The pushed item is a String * object. diff --git a/src/main/javassist/bytecode/ClassFileWriter.java b/src/main/javassist/bytecode/ClassFileWriter.java index 931ffcb4..03650b75 100644 --- a/src/main/javassist/bytecode/ClassFileWriter.java +++ b/src/main/javassist/bytecode/ClassFileWriter.java @@ -693,13 +693,31 @@ public int addMethodTypeInfo(int desc) { * @since 3.17.1 */ public int addInvokeDynamicInfo(int bootstrap, - int nameAndTypeInfo) { + int nameAndTypeInfo) { output.write(InvokeDynamicInfo.tag); output.writeShort(bootstrap); output.writeShort(nameAndTypeInfo); return num++; } + /** + * Adds a new CONSTANT_InvokeDynamic_info + * structure. + * + * @param bootstrap bootstrap_method_attr_index. + * @param nameAndTypeInfo name_and_type_index. + * @return the index of the added entry. + * + * @since 3.17.1 + */ + public int addDynamicInfo(int bootstrap, + int nameAndTypeInfo) { + output.write(DynamicInfo.tag); + output.writeShort(bootstrap); + output.writeShort(nameAndTypeInfo); + return num++; + } + /** * Adds a new CONSTANT_String_info * structure. diff --git a/src/main/javassist/bytecode/ConstPool.java b/src/main/javassist/bytecode/ConstPool.java index 0447ece7..08985089 100644 --- a/src/main/javassist/bytecode/ConstPool.java +++ b/src/main/javassist/bytecode/ConstPool.java @@ -716,53 +716,99 @@ public int getMethodTypeInfo(int index) return mtinfo.descriptor; } - /** - * Reads the bootstrap_method_attr_index field of the - * CONSTANT_InvokeDynamic_info structure - * at the given index. - * - * @since 3.17 - */ - public int getInvokeDynamicBootstrap(int index) - { - InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index); - return iv.bootstrap; - } - - /** - * Reads the name_and_type_index field of the - * CONSTANT_InvokeDynamic_info structure - * at the given index. - * - * @since 3.17 - */ - public int getInvokeDynamicNameAndType(int index) - { - InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index); - return iv.nameAndType; - } - - /** - * Reads the descriptor_index field of the - * CONSTANT_NameAndType_info structure - * indirectly specified by the given index. - * - * @param index an index to a CONSTANT_InvokeDynamic_info. - * @return the descriptor of the method. - * @since 3.17 - */ - public String getInvokeDynamicType(int index) - { - InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index); - if (iv == null) - return null; - NameAndTypeInfo n = (NameAndTypeInfo)getItem(iv.nameAndType); - if(n == null) - return null; - return getUtf8Info(n.typeDescriptor); - } - - /** + /** + * Reads the bootstrap_method_attr_index field of the + * CONSTANT_InvokeDynamic_info structure + * at the given index. + * + * @since 3.17 + */ + public int getInvokeDynamicBootstrap(int index) + { + InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index); + return iv.bootstrap; + } + + /** + * Reads the name_and_type_index field of the + * CONSTANT_InvokeDynamic_info structure + * at the given index. + * + * @since 3.17 + */ + public int getInvokeDynamicNameAndType(int index) + { + InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index); + return iv.nameAndType; + } + + /** + * Reads the descriptor_index field of the + * CONSTANT_NameAndType_info structure + * indirectly specified by the given index. + * + * @param index an index to a CONSTANT_InvokeDynamic_info. + * @return the descriptor of the method. + * @since 3.17 + */ + public String getInvokeDynamicType(int index) + { + InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index); + if (iv == null) + return null; + NameAndTypeInfo n = (NameAndTypeInfo)getItem(iv.nameAndType); + if(n == null) + return null; + return getUtf8Info(n.typeDescriptor); + } + + /** + * Reads the bootstrap_method_attr_index field of the + * CONSTANT_Dynamic_info structure + * at the given index. + * + * @since 3.17 + */ + public int getDynamicBootstrap(int index) + { + DynamicInfo iv = (DynamicInfo)getItem(index); + return iv.bootstrap; + } + + /** + * Reads the name_and_type_index field of the + * CONSTANT_Dynamic_info structure + * at the given index. + * + * @since 3.17 + */ + public int getDynamicNameAndType(int index) + { + DynamicInfo iv = (DynamicInfo)getItem(index); + return iv.nameAndType; + } + + /** + * Reads the descriptor_index field of the + * CONSTANT_NameAndType_info structure + * indirectly specified by the given index. + * + * @param index an index to a CONSTANT_Dynamic_info. + * @return the descriptor of the method. + * @since 3.17 + */ + public String getDynamicType(int index) + { + DynamicInfo iv = (DynamicInfo)getItem(index); + if (iv == null) + return null; + NameAndTypeInfo n = (NameAndTypeInfo)getItem(iv.nameAndType); + if(n == null) + return null; + return getUtf8Info(n.typeDescriptor); + } + + /** * Reads the name_index field of the * CONSTANT_Module_info structure at the given index. * @@ -1196,6 +1242,18 @@ public int addInvokeDynamicInfo(int bootstrap, int nameAndType) } /** + * Adds a new CONSTANT_InvokeDynamic_info structure. + * + * @param bootstrap bootstrap_method_attr_index. + * @param nameAndType name_and_type_index. + * @return the index of the added entry. + * @since 3.17 + */ + public int addDynamicInfo(int bootstrap, int nameAndType) { + return addItem(new DynamicInfo(bootstrap, nameAndType, numOfItems)); + } + + /** * Adds a new CONSTANT_Module_info * @param nameIndex the index of the Utf8 entry. * @return the index of the added entry. @@ -1342,6 +1400,9 @@ private int readOne(DataInputStream in) throws IOException case MethodTypeInfo.tag : // 16 info = new MethodTypeInfo(in, numOfItems); break; + case DynamicInfo.tag : // 17 + info = new DynamicInfo(in, numOfItems); + break; case InvokeDynamicInfo.tag : // 18 info = new InvokeDynamicInfo(in, numOfItems); break; @@ -2322,6 +2383,68 @@ public void print(PrintWriter out) { } } +class DynamicInfo extends ConstInfo { + + static final int tag = 17; + int bootstrap, nameAndType; + + public DynamicInfo(int bootstrapMethod, + int ntIndex, int index) { + super(index); + bootstrap = bootstrapMethod; + nameAndType = ntIndex; + } + + public DynamicInfo(DataInputStream in, int index) + throws IOException { + super(index); + bootstrap = in.readUnsignedShort(); + nameAndType = in.readUnsignedShort(); + } + + @Override + public int hashCode() { + return (bootstrap << 16) ^ nameAndType; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DynamicInfo) { + DynamicInfo iv = (DynamicInfo) obj; + return iv.bootstrap == bootstrap + && iv.nameAndType == nameAndType; + } + return false; + } + + @Override + public int getTag() { + return tag; + } + + @Override + public int copy(ConstPool src, ConstPool dest, + Map map) { + return dest.addDynamicInfo(bootstrap, + src.getItem(nameAndType).copy(src, dest, map)); + } + + @Override + public void write(DataOutputStream out) throws IOException { + out.writeByte(tag); + out.writeShort(bootstrap); + out.writeShort(nameAndType); + } + + @Override + public void print(PrintWriter out) { + out.print("Dynamic #"); + out.print(bootstrap); + out.print(", name&type #"); + out.println(nameAndType); + } +} + class ModuleInfo extends ConstInfo { static final int tag = 19; diff --git a/src/test/javassist/bytecode/BytecodeTest.java b/src/test/javassist/bytecode/BytecodeTest.java index 5ddf5d5b..ec754b56 100644 --- a/src/test/javassist/bytecode/BytecodeTest.java +++ b/src/test/javassist/bytecode/BytecodeTest.java @@ -827,6 +827,42 @@ public void testInvokeDynamic() throws Exception { assertEquals("(I)V", cPool2.getUtf8Info(cPool2.getMethodTypeInfo(mtIndex))); } +// public void testDynamicInfo() throws Exception { +// ClassFile cf = new ClassFile(false, "test4.Dyn", null); +// cf.setInterfaces(new String[] { "java.lang.Cloneable" }); +// ConstPool cp = cf.getConstPool(); +// +// Bytecode code = new Bytecode(cp, 0, 1); +// code.addAload(0); +// code.addIconst(9); +// code.addLdc("nine"); +// code.addDynamic(0, "call", "I"); +// code.addOpcode(Opcode.SWAP); +// code.addOpcode(Opcode.POP); +// code.addOpcode(Opcode.IRETURN); +// +// FieldInfo fieldInfo = new FieldInfo(cp, "test", "S"); +// fieldInfo.setAccessFlags(AccessFlag.PUBLIC); +// cf.addField(fieldInfo); +// +// String desc +// = "(Ljava/lang/String;)I"; +// int mri = cp.addMethodrefInfo(cp.addClassInfo("Dyn"), "boot", desc); +// int mhi = cp.addMethodHandleInfo(ConstPool.REF_invokeStatic, mri); +// int[] args = new int[0]; +// BootstrapMethodsAttribute.BootstrapMethod[] bms +// = new BootstrapMethodsAttribute.BootstrapMethod[1]; +// bms[0] = new BootstrapMethodsAttribute.BootstrapMethod(mhi, args); +// +// cf.addAttribute(new BootstrapMethodsAttribute(cp, bms)); +// +// cf.write(new DataOutputStream(new FileOutputStream("test4/Dyn.class"))); +// +// Object obj = make(cf.getName()); +// +// assertNotNull(obj); +// } + public static Test suite() { TestSuite suite = new TestSuite("Bytecode Tests"); suite.addTestSuite(BytecodeTest.class); diff --git a/src/test/test4/Dyn.java b/src/test/test4/Dyn.java new file mode 100644 index 00000000..83418d47 --- /dev/null +++ b/src/test/test4/Dyn.java @@ -0,0 +1,22 @@ +package test4; + +public class Dyn { + + public static int test9(int i, String s) { + return 9; + } + + public int test8(int i, String s) { + return 8; + } + + public static Integer boot(String numberString) + throws NoSuchMethodException, IllegalAccessException { + return Integer.valueOf(numberString); + } + + public Integer boot2(String numberString) + throws NoSuchMethodException, IllegalAccessException { + return Integer.valueOf(numberString); + } +} From 699b301badf2f6746d091df3094d99444fa3fdd8 Mon Sep 17 00:00:00 2001 From: Rich Bolen Date: Tue, 27 Aug 2019 07:45:10 -0400 Subject: [PATCH 2/6] Incorporate feedback from the PR --- src/main/javassist/bytecode/Bytecode.java | 19 ---------- .../javassist/bytecode/ClassFileWriter.java | 18 ---------- src/main/javassist/bytecode/ConstPool.java | 2 +- src/test/javassist/bytecode/BytecodeTest.java | 36 ------------------- 4 files changed, 1 insertion(+), 74 deletions(-) diff --git a/src/main/javassist/bytecode/Bytecode.java b/src/main/javassist/bytecode/Bytecode.java index 193e3f8a..37a6d127 100644 --- a/src/main/javassist/bytecode/Bytecode.java +++ b/src/main/javassist/bytecode/Bytecode.java @@ -1240,25 +1240,6 @@ public void addInvokedynamic(int bootstrap, String name, String desc) { growStack(Descriptor.dataSize(desc)); // assume ConstPool#REF_invokeStatic } - /** - * Appends DYNAMIC. - * - * @param bootstrap an index into the bootstrap_methods array - * of the bootstrap method table. - * @param name the method name. - * @param desc the method descriptor. - * @see Descriptor#ofMethod(CtClass,CtClass[]) - * @since 3.17 - */ - public void addDynamic(int bootstrap, String name, String desc) { - int nt = constPool.addNameAndTypeInfo(name, desc); - int dyn = constPool.addDynamicInfo(bootstrap, nt); - add(INVOKEDYNAMIC); - addIndex(dyn); - add(0, 0); - growStack(Descriptor.dataSize(desc)); // assume ConstPool#REF_invokeStatic - } - /** * Appends LDC or LDC_W. The pushed item is a String * object. diff --git a/src/main/javassist/bytecode/ClassFileWriter.java b/src/main/javassist/bytecode/ClassFileWriter.java index 03650b75..966767af 100644 --- a/src/main/javassist/bytecode/ClassFileWriter.java +++ b/src/main/javassist/bytecode/ClassFileWriter.java @@ -700,24 +700,6 @@ public int addInvokeDynamicInfo(int bootstrap, return num++; } - /** - * Adds a new CONSTANT_InvokeDynamic_info - * structure. - * - * @param bootstrap bootstrap_method_attr_index. - * @param nameAndTypeInfo name_and_type_index. - * @return the index of the added entry. - * - * @since 3.17.1 - */ - public int addDynamicInfo(int bootstrap, - int nameAndTypeInfo) { - output.write(DynamicInfo.tag); - output.writeShort(bootstrap); - output.writeShort(nameAndTypeInfo); - return num++; - } - /** * Adds a new CONSTANT_String_info * structure. diff --git a/src/main/javassist/bytecode/ConstPool.java b/src/main/javassist/bytecode/ConstPool.java index 08985089..bd521001 100644 --- a/src/main/javassist/bytecode/ConstPool.java +++ b/src/main/javassist/bytecode/ConstPool.java @@ -1242,7 +1242,7 @@ public int addInvokeDynamicInfo(int bootstrap, int nameAndType) } /** - * Adds a new CONSTANT_InvokeDynamic_info structure. + * Adds a new CONSTANT_Dynamic_info structure. * * @param bootstrap bootstrap_method_attr_index. * @param nameAndType name_and_type_index. diff --git a/src/test/javassist/bytecode/BytecodeTest.java b/src/test/javassist/bytecode/BytecodeTest.java index ec754b56..5ddf5d5b 100644 --- a/src/test/javassist/bytecode/BytecodeTest.java +++ b/src/test/javassist/bytecode/BytecodeTest.java @@ -827,42 +827,6 @@ public void testInvokeDynamic() throws Exception { assertEquals("(I)V", cPool2.getUtf8Info(cPool2.getMethodTypeInfo(mtIndex))); } -// public void testDynamicInfo() throws Exception { -// ClassFile cf = new ClassFile(false, "test4.Dyn", null); -// cf.setInterfaces(new String[] { "java.lang.Cloneable" }); -// ConstPool cp = cf.getConstPool(); -// -// Bytecode code = new Bytecode(cp, 0, 1); -// code.addAload(0); -// code.addIconst(9); -// code.addLdc("nine"); -// code.addDynamic(0, "call", "I"); -// code.addOpcode(Opcode.SWAP); -// code.addOpcode(Opcode.POP); -// code.addOpcode(Opcode.IRETURN); -// -// FieldInfo fieldInfo = new FieldInfo(cp, "test", "S"); -// fieldInfo.setAccessFlags(AccessFlag.PUBLIC); -// cf.addField(fieldInfo); -// -// String desc -// = "(Ljava/lang/String;)I"; -// int mri = cp.addMethodrefInfo(cp.addClassInfo("Dyn"), "boot", desc); -// int mhi = cp.addMethodHandleInfo(ConstPool.REF_invokeStatic, mri); -// int[] args = new int[0]; -// BootstrapMethodsAttribute.BootstrapMethod[] bms -// = new BootstrapMethodsAttribute.BootstrapMethod[1]; -// bms[0] = new BootstrapMethodsAttribute.BootstrapMethod(mhi, args); -// -// cf.addAttribute(new BootstrapMethodsAttribute(cp, bms)); -// -// cf.write(new DataOutputStream(new FileOutputStream("test4/Dyn.class"))); -// -// Object obj = make(cf.getName()); -// -// assertNotNull(obj); -// } - public static Test suite() { TestSuite suite = new TestSuite("Bytecode Tests"); suite.addTestSuite(BytecodeTest.class); From 265b8fbea408078b0bcc76a13203f0846ae3cfd0 Mon Sep 17 00:00:00 2001 From: Rich Bolen Date: Tue, 27 Aug 2019 07:46:39 -0400 Subject: [PATCH 3/6] Incorporate feedback from the PR --- src/main/javassist/bytecode/ClassFileWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/javassist/bytecode/ClassFileWriter.java b/src/main/javassist/bytecode/ClassFileWriter.java index 966767af..931ffcb4 100644 --- a/src/main/javassist/bytecode/ClassFileWriter.java +++ b/src/main/javassist/bytecode/ClassFileWriter.java @@ -693,7 +693,7 @@ public int addMethodTypeInfo(int desc) { * @since 3.17.1 */ public int addInvokeDynamicInfo(int bootstrap, - int nameAndTypeInfo) { + int nameAndTypeInfo) { output.write(InvokeDynamicInfo.tag); output.writeShort(bootstrap); output.writeShort(nameAndTypeInfo); From 45764f9465c712d6dc0b69a5027ffccc5b8e2afc Mon Sep 17 00:00:00 2001 From: Rich Bolen Date: Tue, 27 Aug 2019 07:55:06 -0400 Subject: [PATCH 4/6] Incorporate feedback from the PR --- src/main/javassist/bytecode/ConstPool.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/javassist/bytecode/ConstPool.java b/src/main/javassist/bytecode/ConstPool.java index bd521001..34170e35 100644 --- a/src/main/javassist/bytecode/ConstPool.java +++ b/src/main/javassist/bytecode/ConstPool.java @@ -105,7 +105,12 @@ public final class ConstPool public static final int CONST_MethodType = MethodTypeInfo.tag; /** - * CONSTANT_MethodHandle + * CONSTANT_Dynamic + */ + public static final int CONST_Dynamic = DynamicInfo.tag; + + /** + * CONSTANT_InvokeDynamic */ public static final int CONST_InvokeDynamic = InvokeDynamicInfo.tag; From dd3612498a287f7572cc0ff7b80a47341005030b Mon Sep 17 00:00:00 2001 From: Rich Bolen Date: Wed, 28 Aug 2019 10:38:17 -0400 Subject: [PATCH 5/6] Address feedback from PR --- pom.xml | 4 ++-- src/main/javassist/bytecode/ConstPool.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index fc8e2fdf..c7b4bf81 100644 --- a/pom.xml +++ b/pom.xml @@ -151,8 +151,8 @@ maven-compiler-plugin 3.2 - 9 - 9 + 1.7 + 1.7 11 11 -parameters diff --git a/src/main/javassist/bytecode/ConstPool.java b/src/main/javassist/bytecode/ConstPool.java index 34170e35..a7537c49 100644 --- a/src/main/javassist/bytecode/ConstPool.java +++ b/src/main/javassist/bytecode/ConstPool.java @@ -1405,9 +1405,9 @@ private int readOne(DataInputStream in) throws IOException case MethodTypeInfo.tag : // 16 info = new MethodTypeInfo(in, numOfItems); break; - case DynamicInfo.tag : // 17 - info = new DynamicInfo(in, numOfItems); - break; + case DynamicInfo.tag : // 17 + info = new DynamicInfo(in, numOfItems); + break; case InvokeDynamicInfo.tag : // 18 info = new InvokeDynamicInfo(in, numOfItems); break; From a90bc27e5886d9cdd359580875e92bf0dd772a1f Mon Sep 17 00:00:00 2001 From: Rich Bolen Date: Fri, 30 Aug 2019 06:03:16 -0400 Subject: [PATCH 6/6] Remove unused file --- src/test/test4/Dyn.java | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 src/test/test4/Dyn.java diff --git a/src/test/test4/Dyn.java b/src/test/test4/Dyn.java deleted file mode 100644 index 83418d47..00000000 --- a/src/test/test4/Dyn.java +++ /dev/null @@ -1,22 +0,0 @@ -package test4; - -public class Dyn { - - public static int test9(int i, String s) { - return 9; - } - - public int test8(int i, String s) { - return 8; - } - - public static Integer boot(String numberString) - throws NoSuchMethodException, IllegalAccessException { - return Integer.valueOf(numberString); - } - - public Integer boot2(String numberString) - throws NoSuchMethodException, IllegalAccessException { - return Integer.valueOf(numberString); - } -}