From c137b17e82f90df07f4d8a5341b836a636a63ce1 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Wed, 8 Nov 2023 19:59:31 +0000 Subject: [PATCH] 8187655: jdk.lambda.vm.InterfaceAccessFlagsTest.testPrivateMethodCall needs update after nestmates support Reviewed-by: liach, asotona --- test/jdk/jdk/lambda/TEST.properties | 5 +- .../lambda/separate/AttributeInjector.java | 71 --- test/jdk/jdk/lambda/separate/ClassFile.java | 452 ------------------ .../separate/ClassToInterfaceConverter.java | 83 +--- .../lambda/vm/InterfaceAccessFlagsTest.java | 10 +- 5 files changed, 34 insertions(+), 587 deletions(-) delete mode 100644 test/jdk/jdk/lambda/separate/AttributeInjector.java delete mode 100644 test/jdk/jdk/lambda/separate/ClassFile.java diff --git a/test/jdk/jdk/lambda/TEST.properties b/test/jdk/jdk/lambda/TEST.properties index eaae109a7fc..bd37b556c82 100644 --- a/test/jdk/jdk/lambda/TEST.properties +++ b/test/jdk/jdk/lambda/TEST.properties @@ -3,4 +3,7 @@ TestNG.dirs = . maxOutputSize = 250000 -modules = jdk.compiler jdk.zipfs +modules = java.base/jdk.internal.classfile \ + java.base/jdk.internal.classfile.constantpool \ + java.base/jdk.internal.classfile.instruction \ + jdk.compiler jdk.zipfs diff --git a/test/jdk/jdk/lambda/separate/AttributeInjector.java b/test/jdk/jdk/lambda/separate/AttributeInjector.java deleted file mode 100644 index 526895211e7..00000000000 --- a/test/jdk/jdk/lambda/separate/AttributeInjector.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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 separate; - -import java.io.*; - -public class AttributeInjector implements ClassFilePreprocessor { - - private String attributeName; - private byte[] attributeData; - - public AttributeInjector(String attributeName, byte[] attributeData) { - this.attributeName = attributeName; - this.attributeData = attributeData; - } - - public byte[] preprocess(String name, byte[] cf) { - ClassFile classfile = new ClassFile(cf); - - short cpIndex = (short)classfile.constant_pool.size(); - - ClassFile.CpUtf8 entry = new ClassFile.CpUtf8(); - entry.bytes = new byte[attributeName.length()]; - for (int i = 0; i < attributeName.length(); ++i) { - entry.bytes[i] = (byte)attributeName.charAt(i); - } - - classfile.constant_pool.add(entry); - - ClassFile.Attribute attr = new ClassFile.Attribute(); - attr.attribute_name_index = cpIndex; - attr.info = attributeData; - - classfile.attributes.add(attr); - return classfile.toByteArray(); - } - -/* - public static void main(String argv[]) throws Exception { - File input = new File(argv[0]); - byte[] buffer = new byte[(int)input.length()]; - new FileInputStream(input).read(buffer); - - ClassFilePreprocessor cfp = - new AttributeInjector("RequiresBridges", new byte[0]); - byte[] cf = cfp.preprocess(argv[0], buffer); - new FileOutputStream(argv[0] + ".mod").write(cf); - } -*/ -} diff --git a/test/jdk/jdk/lambda/separate/ClassFile.java b/test/jdk/jdk/lambda/separate/ClassFile.java deleted file mode 100644 index d49e478fa23..00000000000 --- a/test/jdk/jdk/lambda/separate/ClassFile.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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 separate; - -import java.io.*; -import java.util.*; - -class CfInputStream extends ByteArrayInputStream { - private int ct; - public CfInputStream(byte[] input) { - super(input); - } - - byte u1() { return (byte)read(); } - short u2() { - int b0 = read() << 8; - int b1 = read(); - return (short)(b0 | b1); - } - int u4() { - int b0 = read() << 24; - int b1 = read() << 16; - int b2 = read() << 8; - int b3 = read(); - return b0 | b1 | b2 | b3; - } - byte[] array(int count) { - byte[] ret = new byte[count]; - read(ret, 0, count); - return ret; - } -}; - -class CfOutputStream extends ByteArrayOutputStream { - void u1(byte b) { write((int)b); } - void u2(short s) { - write((s >> 8) & 0xff); - write(s & 0xff); - } - void u4(int i) { - write((i >> 24) & 0xff); - write((i >> 16) & 0xff); - write((i >> 8) & 0xff); - write(i & 0xff); - } - void array(byte[] a) { - write(a, 0, a.length); - } - - public byte[] toByteArray() { return super.toByteArray(); } -}; - -// A quick and dirty class file parser and representation -public class ClassFile { - - int magic; - short minor_version; - short major_version; - ArrayList constant_pool; - short access_flags; - short this_class; - short super_class; - ArrayList interfaces; - ArrayList fields; - ArrayList methods; - ArrayList attributes; - - ClassFile(byte[] cf) { - CfInputStream in = new CfInputStream(cf); - - magic = in.u4(); - minor_version = in.u2(); - major_version = in.u2(); - - short cpCount = in.u2(); - constant_pool = new ArrayList<>(); - constant_pool.add(new CpNull()); - for (int i = 1; i < cpCount; ++i) { - constant_pool.add(CpEntry.newCpEntry(in)); - } - - access_flags = in.u2(); - this_class = in.u2(); - super_class = in.u2(); - - short ifaceCount = in.u2(); - interfaces = new ArrayList<>(); - for (int i = 0; i < ifaceCount; ++i) { - interfaces.add(new Interface(in)); - } - - short fieldCount = in.u2(); - fields = new ArrayList<>(); - for (int i = 0; i < fieldCount; ++i) { - fields.add(new Field(in)); - } - - short methodCount = in.u2(); - methods = new ArrayList<>(); - for (int i = 0; i < methodCount; ++i) { - methods.add(new Method(in)); - } - - short attributeCount = in.u2(); - attributes = new ArrayList<>(); - for (int i = 0; i < attributeCount; ++i) { - attributes.add(new Attribute(in)); - } - } - - byte[] toByteArray() { - CfOutputStream out = new CfOutputStream(); - - out.u4(magic); - out.u2(minor_version); - out.u2(major_version); - - out.u2((short)(constant_pool.size())); - for (CpEntry cp : constant_pool) { - cp.write(out); - } - - out.u2(access_flags); - out.u2(this_class); - out.u2(super_class); - - out.u2((short)interfaces.size()); - for (Interface iface : interfaces) { - iface.write(out); - } - - out.u2((short)fields.size()); - for (Field field : fields) { - field.write(out); - } - - out.u2((short)methods.size()); - for (Method method : methods) { - method.write(out); - } - - out.u2((short)attributes.size()); - for (Attribute attribute : attributes) { - attribute.write(out); - } - - return out.toByteArray(); - } - - static abstract class CpEntry { - byte tag; - - CpEntry(byte t) { tag = t; } - void write(CfOutputStream out) { - out.u1(tag); - } - - static CpEntry newCpEntry(CfInputStream in) { - byte tag = in.u1(); - switch (tag) { - case CpUtf8.TAG: return new CpUtf8(in); - case CpInteger.TAG: return new CpInteger(in); - case CpFloat.TAG: return new CpFloat(in); - case CpLong.TAG: return new CpLong(in); - case CpDouble.TAG: return new CpDouble(in); - case CpClass.TAG: return new CpClass(in); - case CpString.TAG: return new CpString(in); - case CpFieldRef.TAG: return new CpFieldRef(in); - case CpMethodRef.TAG: return new CpMethodRef(in); - case CpInterfaceMethodRef.TAG: - return new CpInterfaceMethodRef(in); - case CpNameAndType.TAG: return new CpNameAndType(in); - case CpMethodHandle.TAG: return new CpMethodHandle(in); - case CpMethodType.TAG: return new CpMethodType(in); - case CpInvokeDynamic.TAG: return new CpInvokeDynamic(in); - default: throw new RuntimeException("Bad cp entry tag: " + tag); - } - } - } - - static class CpNull extends CpEntry { - CpNull() { super((byte)0); } - CpNull(CfInputStream in) { super((byte)0); } - void write(CfOutputStream out) {} - } - - static class CpUtf8 extends CpEntry { - static final byte TAG = 1; - byte[] bytes; - - CpUtf8() { super(TAG); } - CpUtf8(CfInputStream in) { - this(); - short length = in.u2(); - bytes = in.array(length); - } - void write(CfOutputStream out) { - super.write(out); - out.u2((short)bytes.length); - out.array(bytes); - } - } - - static class CpU4Constant extends CpEntry { - byte[] bytes; - - CpU4Constant(byte tag) { super(tag); } - CpU4Constant(byte tag, CfInputStream in) { - this(tag); - bytes = in.array(4); - } - void write(CfOutputStream out) { super.write(out); out.array(bytes); } - } - static class CpInteger extends CpU4Constant { - static final byte TAG = 3; - CpInteger() { super(TAG); } - CpInteger(CfInputStream in) { super(TAG, in); } - } - static class CpFloat extends CpU4Constant { - static final byte TAG = 4; - CpFloat() { super(TAG); } - CpFloat(CfInputStream in) { super(TAG, in); } - } - - static class CpU8Constant extends CpEntry { - byte[] bytes; - - CpU8Constant(byte tag) { super(tag); } - CpU8Constant(byte tag, CfInputStream in) { - this(tag); - bytes = in.array(8); - } - void write(CfOutputStream out) { super.write(out); out.array(bytes); } - } - static class CpLong extends CpU8Constant { - static final byte TAG = 5; - CpLong() { super(TAG); } - CpLong(CfInputStream in) { super(TAG, in); } - } - static class CpDouble extends CpU8Constant { - static final byte TAG = 6; - CpDouble() { super(TAG); } - CpDouble(CfInputStream in) { super(TAG, in); } - } - - static class CpClass extends CpEntry { - static final byte TAG = 7; - short name_index; - - CpClass() { super(TAG); } - CpClass(CfInputStream in) { super(TAG); name_index = in.u2(); } - void write(CfOutputStream out) { - super.write(out); - out.u2(name_index); - } - } - - static class CpString extends CpEntry { - static final byte TAG = 8; - short string_index; - - CpString() { super(TAG); } - CpString(CfInputStream in) { super(TAG); string_index = in.u2(); } - void write(CfOutputStream out) { - super.write(out); - out.u2(string_index); - } - } - - static class CpRef extends CpEntry { - short class_index; - short name_and_type_index; - - CpRef(byte tag) { super(tag); } - CpRef(byte tag, CfInputStream in) { - this(tag); - class_index = in.u2(); - name_and_type_index = in.u2(); - } - void write(CfOutputStream out) { - super.write(out); - out.u2(class_index); - out.u2(name_and_type_index); - } - } - static class CpFieldRef extends CpRef { - static final byte TAG = 9; - CpFieldRef() { super(TAG); } - CpFieldRef(CfInputStream in) { super(TAG, in); } - } - static class CpMethodRef extends CpRef { - static final byte TAG = 10; - CpMethodRef() { super(TAG); } - CpMethodRef(CfInputStream in) { super(TAG, in); } - } - static class CpInterfaceMethodRef extends CpRef { - static final byte TAG = 11; - CpInterfaceMethodRef() { super(TAG); } - CpInterfaceMethodRef(CfInputStream in) { super(TAG, in); } - } - - static class CpNameAndType extends CpEntry { - static final byte TAG = 12; - short name_index; - short descriptor_index; - - CpNameAndType() { super(TAG); } - CpNameAndType(CfInputStream in) { - this(); - name_index = in.u2(); - descriptor_index = in.u2(); - } - void write(CfOutputStream out) { - super.write(out); - out.u2(name_index); - out.u2(descriptor_index); - } - } - - static class CpMethodHandle extends CpEntry { - static final byte TAG = 15; - byte reference_kind; - short reference_index; - - CpMethodHandle() { super(TAG); } - CpMethodHandle(CfInputStream in) { - this(); - reference_kind = in.u1(); - reference_index = in.u2(); - } - void write(CfOutputStream out) { - super.write(out); - out.u1(reference_kind); - out.u2(reference_index); - } - } - - static class CpMethodType extends CpEntry { - static final byte TAG = 16; - short descriptor_index; - - CpMethodType() { super(TAG); } - CpMethodType(CfInputStream in) { - this(); - descriptor_index = in.u2(); - } - void write(CfOutputStream out) { - super.write(out); - out.u2(descriptor_index); - } - } - - static class CpInvokeDynamic extends CpEntry { - static final byte TAG = 18; - short bootstrap_index; - short name_and_type_index; - - CpInvokeDynamic() { super(TAG); } - CpInvokeDynamic(CfInputStream in) { - this(); - bootstrap_index = in.u2(); - name_and_type_index = in.u2(); - } - void write(CfOutputStream out) { - super.write(out); - out.u2(bootstrap_index); - out.u2(name_and_type_index); - } - } - - static class Interface { - short index; - - Interface() {} - Interface(CfInputStream in) { index = in.u2(); } - void write(CfOutputStream out) { out.u2(index); } - } - - static class FieldOrMethod { - short access_flags; - short name_index; - short descriptor_index; - ArrayList attributes; - - FieldOrMethod() { attributes = new ArrayList<>(); } - FieldOrMethod(CfInputStream in) { - access_flags = in.u2(); - name_index = in.u2(); - descriptor_index = in.u2(); - - short attrCount = in.u2(); - attributes = new ArrayList<>(); - for (int i = 0; i < attrCount; ++i) { - attributes.add(new Attribute(in)); - } - } - void write(CfOutputStream out) { - out.u2(access_flags); - out.u2(name_index); - out.u2(descriptor_index); - out.u2((short)attributes.size()); - for (Attribute attribute : attributes) { attribute.write(out); } - } - } - - static class Field extends FieldOrMethod { - Field() {} - Field(CfInputStream in) { super(in); } - } - static class Method extends FieldOrMethod { - Method() {} - Method(CfInputStream in) { super(in); } - } - - static class Attribute { - short attribute_name_index; - byte[] info; - - Attribute() { info = new byte[0]; } - Attribute(CfInputStream in) { - attribute_name_index = in.u2(); - int length = in.u4(); - info = in.array(length); - } - void write(CfOutputStream out) { - out.u2(attribute_name_index); - out.u4(info.length); - out.array(info); - } - } -} diff --git a/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java b/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java index 61598bd035d..6b39981bfbd 100644 --- a/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java +++ b/test/jdk/jdk/lambda/separate/ClassToInterfaceConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, 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 @@ -23,75 +23,44 @@ package separate; -import java.io.*; -import java.util.*; +import jdk.internal.classfile.*; +import jdk.internal.classfile.instruction.InvokeInstruction; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static jdk.internal.classfile.Classfile.*; public class ClassToInterfaceConverter implements ClassFilePreprocessor { - private String whichClass; + private final String whichClass; public ClassToInterfaceConverter(String className) { this.whichClass = className; } - private boolean utf8Matches(ClassFile.CpEntry entry, String v) { - if (!(entry instanceof ClassFile.CpUtf8)) { - return false; - } - ClassFile.CpUtf8 utf8 = (ClassFile.CpUtf8)entry; - if (v.length() != utf8.bytes.length) { - return false; - } - for (int i = 0; i < v.length(); ++i) { - if (v.charAt(i) != utf8.bytes[i]) { - return false; + private byte[] convertToInterface(ClassModel classModel) { + // Convert method tag. Find Methodref which is only invoked by other methods + // in the interface, convert it to InterfaceMethodref. If opcode is invokevirtual, + // convert it to invokeinterface + CodeTransform ct = (b, e) -> { + if (e instanceof InvokeInstruction i && i.owner() == classModel.thisClass()) { + Opcode opcode = i.opcode() == Opcode.INVOKEVIRTUAL ? Opcode.INVOKEINTERFACE : i.opcode(); + b.invokeInstruction(opcode, i.owner().asSymbol(), + i.name().stringValue(), i.typeSymbol(), true); + } else { + b.with(e); } - } - return true; - } + }; - private void convertToInterface(ClassFile cf) { - cf.access_flags = 0x0601; // ACC_INTERFACE | ACC_ABSTRACT | ACC_PUBLIC - ArrayList new_methods = new ArrayList<>(); - // Find method and delete it - for (int i = 0; i < cf.methods.size(); ++i) { - ClassFile.Method method = cf.methods.get(i); - ClassFile.CpEntry name = cf.constant_pool.get(method.name_index); - if (!utf8Matches(name, "")) { - new_methods.add(method); - } - } - cf.methods = new_methods; - // Convert method tag. Find Methodref, which is not "" and only invoked by other methods - // in the interface, convert it to InterfaceMethodref - ArrayList cpool = new ArrayList<>(); - for (int i = 0; i < cf.constant_pool.size(); i++) { - ClassFile.CpEntry ce = cf.constant_pool.get(i); - if (ce instanceof ClassFile.CpMethodRef) { - ClassFile.CpMethodRef me = (ClassFile.CpMethodRef)ce; - ClassFile.CpNameAndType nameType = (ClassFile.CpNameAndType)cf.constant_pool.get(me.name_and_type_index); - ClassFile.CpEntry name = cf.constant_pool.get(nameType.name_index); - if (!utf8Matches(name, "") && cf.this_class == me.class_index) { - ClassFile.CpInterfaceMethodRef newEntry = new ClassFile.CpInterfaceMethodRef(); - newEntry.class_index = me.class_index; - newEntry.name_and_type_index = me.name_and_type_index; - ce = newEntry; - } - } - cpool.add(ce); - } - cf.constant_pool = cpool; + return Classfile.of().transform(classModel, + ClassTransform.dropping(ce -> ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)) + .andThen(ClassTransform.transformingMethodBodies(ct)) + .andThen(ClassTransform.endHandler(b -> b.withFlags(ACC_INTERFACE | ACC_ABSTRACT | ACC_PUBLIC))) + ); } public byte[] preprocess(String classname, byte[] bytes) { - ClassFile cf = new ClassFile(bytes); - - ClassFile.CpEntry entry = cf.constant_pool.get(cf.this_class); - ClassFile.CpEntry name = cf.constant_pool.get( - ((ClassFile.CpClass)entry).name_index); - if (utf8Matches(name, whichClass)) { - convertToInterface(cf); - return cf.toByteArray(); + ClassModel classModel = Classfile.of().parse(bytes); + if (classModel.thisClass().asInternalName().equals(whichClass)) { + return convertToInterface(classModel); } else { return bytes; // unmodified } diff --git a/test/jdk/jdk/lambda/vm/InterfaceAccessFlagsTest.java b/test/jdk/jdk/lambda/vm/InterfaceAccessFlagsTest.java index d4cf8e0b118..a604993a996 100644 --- a/test/jdk/jdk/lambda/vm/InterfaceAccessFlagsTest.java +++ b/test/jdk/jdk/lambda/vm/InterfaceAccessFlagsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, 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 @@ -23,11 +23,10 @@ package vm; -import java.io.*; - import org.testng.annotations.Test; -import separate.*; +import separate.ClassToInterfaceConverter; import separate.Compiler; +import separate.TestHarness; import static org.testng.Assert.*; import static separate.SourceModel.*; @@ -71,8 +70,7 @@ public class InterfaceAccessFlagsTest extends TestHarness { } } - /* excluded: 8187655 */ - @Test(enabled=false, groups = "vm_prototype") + @Test(groups = "vm_prototype") public void testPrivateMethodCall() { testMethodCallWithFlag(AccessFlag.PRIVATE); }