diff --git a/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java b/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java index 8b0a1ae625b..ca31213b28f 100644 --- a/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java +++ b/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -27,7 +27,7 @@ * @summary InvalidClassException is thrown when the canonical constructor * cannot be found during deserialization. * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @run testng BadCanonicalCtrTest */ @@ -38,19 +38,22 @@ import java.io.InvalidClassException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.ClassFile; +import java.lang.classfile.MethodModel; +import java.lang.constant.MethodTypeDesc; + import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.ByteCodeLoader; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static java.lang.System.out; -import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; -import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_MAXS; -import static jdk.internal.org.objectweb.asm.Opcodes.*; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_void; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; import static org.testng.Assert.assertTrue; import static org.testng.Assert.expectThrows; @@ -203,33 +206,9 @@ public class BadCanonicalCtrTest { * Assumes just a single, canonical, constructor. */ static byte[] removeConstructor(byte[] classBytes) { - ClassReader reader = new ClassReader(classBytes); - ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES); - reader.accept(new RemoveCanonicalCtrVisitor(writer), 0); - return writer.toByteArray(); - } - - /** Removes the method. */ - static class RemoveCanonicalCtrVisitor extends ClassVisitor { - static final String CTR_NAME = ""; - RemoveCanonicalCtrVisitor(ClassVisitor cv) { - super(ASM8, cv); - } - volatile boolean foundCanonicalCtr; - @Override - public MethodVisitor visitMethod(final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions) { - if (name.equals(CTR_NAME)) { // assume just a single constructor - assert foundCanonicalCtr == false; - foundCanonicalCtr = true; - return null; - } else { - return cv.visitMethod(access, name, descriptor, signature, exceptions); - } - } + var cf = ClassFile.of(); + return cf.transform(cf.parse(classBytes), ClassTransform.dropping(ce -> + ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME))); } /** @@ -237,55 +216,15 @@ public class BadCanonicalCtrTest { * Assumes just a single, canonical, constructor. */ static byte[] modifyConstructor(byte[] classBytes) { - ClassReader reader = new ClassReader(classBytes); - ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES); - reader.accept(new ModifyCanonicalCtrVisitor(writer), 0); - return writer.toByteArray(); - } - - /** Replaces whatever method it finds with (Ljava/lang/Object;)V. */ - static class ModifyCanonicalCtrVisitor extends ClassVisitor { - ModifyCanonicalCtrVisitor(ClassVisitor cv) { - super(ASM8, cv); - } - boolean foundCanonicalCtr; - String className; - @Override - public void visit(final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) { - this.className = name; - cv.visit(version, access, name, signature, superName, interfaces); - } - @Override - public MethodVisitor visitMethod(final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions) { - if (name.equals("")) { // assume just a single constructor - assert foundCanonicalCtr == false; - foundCanonicalCtr = true; - return null; - } else { - return cv.visitMethod(access, name, descriptor, signature, exceptions); - } - } - @Override - public void visitEnd() { - // must have a signature that is not the same as the test record constructor - MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "", "(Ljava/lang/Object;)V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Record", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - - cv.visitEnd(); - } + var cf = ClassFile.of(); + return cf.transform(cf.parse(classBytes), ClassTransform.dropping(ce -> + ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)) + .andThen(ClassTransform.endHandler(clb -> clb.withMethodBody(INIT_NAME, + MethodTypeDesc.of(CD_void, CD_Object), ACC_PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(Record.class.describeConstable().orElseThrow(), + INIT_NAME, MTD_void); + cob.return_(); + })))); } } diff --git a/test/jdk/java/io/Serializable/records/ProhibitedMethods.java b/test/jdk/java/io/Serializable/records/ProhibitedMethods.java index 099008b4306..371500497f9 100644 --- a/test/jdk/java/io/Serializable/records/ProhibitedMethods.java +++ b/test/jdk/java/io/Serializable/records/ProhibitedMethods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -26,7 +26,7 @@ * @bug 8246774 * @summary Basic tests for prohibited magic serialization methods * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @run testng ProhibitedMethods */ @@ -41,23 +41,23 @@ import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.io.OutputStream; import java.io.Serializable; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.ClassFile; +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.math.BigDecimal; -import java.util.function.Function; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; + import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.ByteCodeLoader; +import org.testng.Assert; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static java.lang.System.out; -import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; -import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_MAXS; -import static jdk.internal.org.objectweb.asm.Opcodes.*; +import static java.lang.classfile.ClassFile.ACC_PRIVATE; +import static java.lang.constant.ConstantDescs.CD_String; +import static java.lang.constant.ConstantDescs.CD_void; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.expectThrows; @@ -219,103 +219,38 @@ public class ProhibitedMethods { // -- machinery for augmenting record classes with prohibited serial methods -- + static final String WRITE_OBJECT_NAME = "writeObject"; + static final MethodTypeDesc WRITE_OBJECT_DESC = MethodTypeDesc.ofDescriptor("(Ljava/io/ObjectOutputStream;)V"); + static byte[] addWriteObject(byte[] classBytes) { - return addMethod(classBytes, cv -> new WriteObjectVisitor(cv)); + return addMethod(classBytes, WRITE_OBJECT_NAME, WRITE_OBJECT_DESC); } + static final String READ_OBJECT_NAME = "readObject"; + static final MethodTypeDesc READ_OBJECT_DESC = MethodTypeDesc.ofDescriptor("(Ljava/io/ObjectInputStream;)V"); + static byte[] addReadObject(byte[] classBytes) { - return addMethod(classBytes, cv -> new ReadObjectVisitor(cv)); + return addMethod(classBytes, READ_OBJECT_NAME, READ_OBJECT_DESC); } + static final String READ_OBJECT_NO_DATA_NAME = "readObjectNoData"; + static final MethodTypeDesc READ_OBJECT_NO_DATA_DESC = MethodTypeDesc.of(CD_void); + static byte[] addReadObjectNoData(byte[] classBytes) { - return addMethod(classBytes, cv -> new ReadObjectNoDataVisitor(cv)); + return addMethod(classBytes, READ_OBJECT_NO_DATA_NAME, READ_OBJECT_NO_DATA_DESC); } static byte[] addMethod(byte[] classBytes, - Function classVisitorCreator) { - ClassReader reader = new ClassReader(classBytes); - ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES); - reader.accept(classVisitorCreator.apply(writer), 0); - return writer.toByteArray(); - } - - static abstract class AbstractVisitor extends ClassVisitor { - final String nameOfMethodToAdd; - AbstractVisitor(ClassVisitor cv, String nameOfMethodToAdd) { - super(ASM8, cv); - this.nameOfMethodToAdd = nameOfMethodToAdd; - } - @Override - public MethodVisitor visitMethod(final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions) { - // the method-to-be-added should not already exist - assert !name.equals(nameOfMethodToAdd) : "Unexpected " + name + " method"; - return cv.visitMethod(access, name, descriptor, signature, exceptions); - } - @Override - public void visitEnd() { - throw new UnsupportedOperationException("implement me"); - } - } - - /** A visitor that generates and adds a writeObject method. */ - static final class WriteObjectVisitor extends AbstractVisitor { - static final String WRITE_OBJECT_NAME = "writeObject"; - static final String WRITE_OBJECT_DESC = "(Ljava/io/ObjectOutputStream;)V"; - WriteObjectVisitor(ClassVisitor cv) { super(cv, WRITE_OBJECT_NAME); } - @Override - public void visitEnd() { - MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, WRITE_OBJECT_NAME, WRITE_OBJECT_DESC, null, null); - mv.visitCode(); - mv.visitLdcInsn(WRITE_OBJECT_NAME + " should not be invoked"); - mv.visitMethodInsn(INVOKESTATIC, "org/testng/Assert", "fail", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - cv.visitEnd(); - } - } - - /** A visitor that generates and adds a readObject method. */ - static final class ReadObjectVisitor extends AbstractVisitor { - static final String READ_OBJECT_NAME = "readObject"; - static final String READ_OBJECT_DESC = "(Ljava/io/ObjectInputStream;)V"; - ReadObjectVisitor(ClassVisitor cv) { super(cv, READ_OBJECT_NAME); } - @Override - public void visitEnd() { - MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, READ_OBJECT_NAME, READ_OBJECT_DESC, null, null); - mv.visitCode(); - mv.visitLdcInsn(READ_OBJECT_NAME + " should not be invoked"); - mv.visitMethodInsn(INVOKESTATIC, "org/testng/Assert", "fail", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - cv.visitEnd(); - } - } - - /** A visitor that generates and adds a readObjectNoData method. */ - static final class ReadObjectNoDataVisitor extends AbstractVisitor { - static final String READ_OBJECT_NO_DATA_NAME = "readObjectNoData"; - static final String READ_OBJECT_NO_DATA_DESC = "()V"; - ReadObjectNoDataVisitor(ClassVisitor cv) { super(cv, READ_OBJECT_NO_DATA_NAME); } - @Override - public void visitEnd() { - MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, READ_OBJECT_NO_DATA_NAME, READ_OBJECT_NO_DATA_DESC, null, null); - mv.visitCode(); - mv.visitLdcInsn(READ_OBJECT_NO_DATA_NAME + " should not be invoked"); - mv.visitMethodInsn(INVOKESTATIC, "org/testng/Assert", "fail", "(Ljava/lang/String;)V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - cv.visitEnd(); - } + String name, MethodTypeDesc desc) { + var cf = ClassFile.of(); + return cf.transform(cf.parse(classBytes), ClassTransform.endHandler(clb -> { + clb.withMethodBody(name, desc, ACC_PRIVATE, cob -> { + cob.constantInstruction(name + " should not be invoked"); + cob.invokestatic(Assert.class.describeConstable().orElseThrow(), "fail", + MethodTypeDesc.of(CD_void, CD_String)); + cob.return_(); + }); + })); } // -- infra sanity -- diff --git a/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java b/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java index 0d88074bdbc..31397ad60cb 100644 --- a/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java +++ b/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -26,7 +26,7 @@ * @bug 8246774 * @summary Basic tests for prohibited magic serialPersistentFields * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @run testng SerialPersistentFieldsTest */ @@ -38,23 +38,34 @@ import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.io.ObjectStreamField; import java.io.Serializable; +import java.lang.classfile.ClassBuilder; +import java.lang.classfile.ClassElement; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.ClassFile; +import java.lang.classfile.FieldModel; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; +import java.lang.constant.DynamicConstantDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.math.BigDecimal; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.FieldVisitor; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.Type; + import jdk.test.lib.ByteCodeLoader; import jdk.test.lib.compiler.InMemoryJavaCompiler; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static java.lang.System.out; -import static jdk.internal.org.objectweb.asm.ClassWriter.*; -import static jdk.internal.org.objectweb.asm.Opcodes.*; +import static java.lang.classfile.ClassFile.ACC_FINAL; +import static java.lang.classfile.ClassFile.ACC_PRIVATE; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_Class; +import static java.lang.constant.ConstantDescs.CD_String; +import static java.lang.constant.ConstantDescs.CD_void; +import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -218,105 +229,62 @@ public class SerialPersistentFieldsTest { static byte[] addSerialPersistentFields(byte[] classBytes, ObjectStreamField[] spf) { - ClassReader reader = new ClassReader(classBytes); - ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES); - reader.accept(new SerialPersistentFieldsVisitor(writer, spf), 0); - return writer.toByteArray(); + var cf = ClassFile.of(); + var model = cf.parse(classBytes); + return cf.transform(model, new SerialPersistentFieldsVisitor(model.thisClass().asSymbol(), spf)); } /** A visitor that adds a serialPersistentFields field, and assigns it in clinit. */ - static final class SerialPersistentFieldsVisitor extends ClassVisitor { + static final class SerialPersistentFieldsVisitor implements ClassTransform { static final String FIELD_NAME = "serialPersistentFields"; - static final String FIELD_DESC = "[Ljava/io/ObjectStreamField;"; + static final ClassDesc CD_ObjectStreamField = ObjectStreamField.class.describeConstable().orElseThrow(); + static final ClassDesc FIELD_DESC = CD_ObjectStreamField.arrayType(); final ObjectStreamField[] spf; - String className; - SerialPersistentFieldsVisitor(ClassVisitor cv, ObjectStreamField[] spf) { - super(ASM8, cv); + final ClassDesc className; + SerialPersistentFieldsVisitor(ClassDesc className, ObjectStreamField[] spf) { + this.className = className; this.spf = spf; } + @Override - public void visit(final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) { - this.className = name; - cv.visit(version, access, name, signature, superName, interfaces); - } - @Override - public FieldVisitor visitField(final int access, - final String name, - final String descriptor, - final String signature, - final Object value) { - // the field-to-be-added should not already exist - assert !name.equals("serialPersistentFields") : "Unexpected " + name + " field"; - return cv.visitField(access, name, descriptor, signature, value); - } - @Override - public void visitEnd() { - { - FieldVisitor fv = cv.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, - FIELD_NAME, - FIELD_DESC, - null, - null); - fv.visitEnd(); + public void accept(ClassBuilder builder, ClassElement element) { + if (element instanceof FieldModel fieldModel) { + var name = fieldModel.fieldName().stringValue(); + assert !name.equals(FIELD_NAME) : "Unexpected " + FIELD_NAME + " field"; + builder.accept(fieldModel); + } else { + builder.accept(element); } - { - MethodVisitor mv = cv.visitMethod(ACC_STATIC, "", "()V", null, null); - mv.visitCode(); - mv.visitIntInsn(BIPUSH, spf.length); - mv.visitTypeInsn(ANEWARRAY, "java/io/ObjectStreamField"); + } + + @Override + public void atEnd(ClassBuilder builder) { + builder.withField(FIELD_NAME, FIELD_DESC, ACC_PRIVATE | ACC_STATIC | ACC_FINAL); + builder.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, cob -> { + cob.bipush(spf.length); + cob.anewarray(CD_ObjectStreamField); for (int i = 0; i < spf.length; i++) { ObjectStreamField osf = spf[i]; - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, i); - mv.visitTypeInsn(NEW, "java/io/ObjectStreamField"); - mv.visitInsn(DUP); - mv.visitLdcInsn(osf.getName()); - if (osf.getType().isPrimitive()) { - mv.visitFieldInsn(GETSTATIC, getPrimitiveBoxClass(osf.getType()), "TYPE", "Ljava/lang/Class;"); + cob.dup(); + cob.bipush(i); + cob.new_(CD_ObjectStreamField); + cob.dup(); + cob.constantInstruction(osf.getName()); + if (osf.isPrimitive()) { + cob.constantInstruction(DynamicConstantDesc.ofNamed( + ConstantDescs.BSM_PRIMITIVE_CLASS, String.valueOf(osf.getTypeCode()), CD_Class)); } else { - mv.visitLdcInsn(Type.getType(osf.getType())); + // Currently Classfile API cannot encode primitive classdescs as condy + cob.constantInstruction(osf.getType().describeConstable().orElseThrow()); } - mv.visitMethodInsn(INVOKESPECIAL, "java/io/ObjectStreamField", "", "(Ljava/lang/String;Ljava/lang/Class;)V", false); - mv.visitInsn(AASTORE); + cob.invokespecial(CD_ObjectStreamField, INIT_NAME, MethodTypeDesc.of(CD_void, CD_String, CD_Class)); + cob.aastore(); } - mv.visitFieldInsn(PUTSTATIC, className, "serialPersistentFields", "[Ljava/io/ObjectStreamField;"); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - } - cv.visitEnd(); - } - - static String getPrimitiveBoxClass(final Class clazz) { - if (!clazz.isPrimitive()) - throw new AssertionError("unexpected non-primitive:" + clazz); - - if (clazz == Integer.TYPE) { - return "java/lang/Integer"; - } else if (clazz == Boolean.TYPE) { - return "java/lang/Boolean"; - } else if (clazz == Byte.TYPE) { - return "java/lang/Byte"; - } else if (clazz == Character.TYPE) { - return "java/lang/Character"; - } else if (clazz == Short.TYPE) { - return "java/lang/Short"; - } else if (clazz == Double.TYPE) { - return "java/lang/Double"; - } else if (clazz == Float.TYPE) { - return "java/lang/Float"; - } else if (clazz == Long.TYPE) { - return "java/lang/Long"; - } else { - throw new AssertionError("unknown:" + clazz); - } + cob.putstatic(className, FIELD_NAME, FIELD_DESC); + cob.return_(); + }); } } diff --git a/test/jdk/java/lang/Class/getSimpleName/GetSimpleNameTest.java b/test/jdk/java/lang/Class/getSimpleName/GetSimpleNameTest.java index 0dc966caf12..34ce8f46663 100644 --- a/test/jdk/java/lang/Class/getSimpleName/GetSimpleNameTest.java +++ b/test/jdk/java/lang/Class/getSimpleName/GetSimpleNameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -24,10 +24,24 @@ /* @test * @bug 8057919 * @summary Class.getSimpleName() should work for non-JLS compliant class names - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview */ -import jdk.internal.org.objectweb.asm.*; -import static jdk.internal.org.objectweb.asm.Opcodes.*; + +import java.lang.classfile.ClassBuilder; +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.attribute.EnclosingMethodAttribute; +import java.lang.classfile.attribute.InnerClassInfo; +import java.lang.classfile.attribute.InnerClassesAttribute; +import java.lang.constant.ClassDesc; +import java.lang.reflect.AccessFlag; +import java.util.Optional; + +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; public class GetSimpleNameTest { static class NestedClass {} @@ -121,88 +135,89 @@ public class GetSimpleNameTest { } static class BytecodeGenerator { - final String innerName; - final String outerName; + final ClassDesc innerName; + final ClassDesc outerName; final String simpleName; BytecodeGenerator(String innerName, String outerName, String simpleName) { - this.innerName = intl(innerName); - this.outerName = intl(outerName); + this.innerName = ClassDesc.of(innerName); + this.outerName = ClassDesc.of(outerName); this.simpleName = simpleName; } - static String intl(String name) { return name.replace('.', '/'); } - - static void makeDefaultCtor(ClassWriter cw) { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); + static void makeDefaultCtor(ClassBuilder clb) { + clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cb -> { + cb.aload(0); + cb.invokespecial(CD_Object, INIT_NAME, MTD_void); + cb.return_(); + }); } - void makeCtxk(ClassWriter cw, boolean isInner) { + void makeCtxk(ClassBuilder clb, boolean isInner) { if (isInner) { - cw.visitOuterClass(outerName, "f", "()V"); + clb.with(EnclosingMethodAttribute.of(outerName, + Optional.of("f"), Optional.of(MTD_void))); } else { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f", "()V", null, null); - mv.visitCode(); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); + clb.withMethodBody("f", MTD_void, ACC_PUBLIC | ACC_STATIC, + CodeBuilder::return_); } } byte[] getNestedClasses(boolean isInner) { - String name = (isInner ? innerName : outerName); - ClassWriter cw = new ClassWriter(0); - cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null); - - cw.visitInnerClass(innerName, outerName, simpleName, ACC_PUBLIC | ACC_STATIC); - - makeDefaultCtor(cw); - cw.visitEnd(); - return cw.toByteArray(); + var name = (isInner ? innerName : outerName); + return ClassFile.of().build(name, clb -> { + clb.withSuperclass(CD_Object); + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); + clb.with(InnerClassesAttribute.of( + InnerClassInfo.of(innerName, + Optional.of(outerName), + Optional.of(simpleName)))); + makeDefaultCtor(clb); + }); } byte[] getInnerClasses(boolean isInner) { - String name = (isInner ? innerName : outerName); - ClassWriter cw = new ClassWriter(0); - cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null); - - cw.visitInnerClass(innerName, outerName, simpleName, ACC_PUBLIC); - - makeDefaultCtor(cw); - cw.visitEnd(); - return cw.toByteArray(); + var name = (isInner ? innerName : outerName); + return ClassFile.of().build(name, clb -> { + clb.withSuperclass(CD_Object); + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); + clb.with(InnerClassesAttribute.of( + InnerClassInfo.of(innerName, + Optional.of(outerName), + Optional.of(simpleName), + AccessFlag.PUBLIC))); + makeDefaultCtor(clb); + }); } byte[] getLocalClasses(boolean isInner) { - String name = (isInner ? innerName : outerName); - ClassWriter cw = new ClassWriter(0); - cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null); - - cw.visitInnerClass(innerName, null, simpleName, ACC_PUBLIC | ACC_STATIC); - makeCtxk(cw, isInner); - - makeDefaultCtor(cw); - cw.visitEnd(); - return cw.toByteArray(); + var name = (isInner ? innerName : outerName); + return ClassFile.of().build(name, clb -> { + clb.withSuperclass(CD_Object); + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); + clb.with(InnerClassesAttribute.of( + InnerClassInfo.of(innerName, + Optional.empty(), + Optional.of(simpleName), + AccessFlag.PUBLIC, AccessFlag.STATIC))); + makeDefaultCtor(clb); + makeCtxk(clb, isInner); + }); } byte[] getAnonymousClasses(boolean isInner) { - String name = (isInner ? innerName : outerName); - ClassWriter cw = new ClassWriter(0); - cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null); - - cw.visitInnerClass(innerName, null, null, ACC_PUBLIC | ACC_STATIC); - makeCtxk(cw, isInner); - - makeDefaultCtor(cw); - cw.visitEnd(); - return cw.toByteArray(); + var name = (isInner ? innerName : outerName); + return ClassFile.of().build(name, clb -> { + clb.withSuperclass(CD_Object); + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); + clb.with(InnerClassesAttribute.of( + InnerClassInfo.of(innerName, + Optional.empty(), + Optional.empty(), + AccessFlag.PUBLIC, AccessFlag.STATIC))); + makeDefaultCtor(clb); + makeCtxk(clb, isInner); + }); } } } diff --git a/test/jdk/java/lang/ModuleTests/AnnotationsTest.java b/test/jdk/java/lang/ModuleTests/AnnotationsTest.java index 479230ad75a..60487584273 100644 --- a/test/jdk/java/lang/ModuleTests/AnnotationsTest.java +++ b/test/jdk/java/lang/ModuleTests/AnnotationsTest.java @@ -22,9 +22,15 @@ */ import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassBuilder; +import java.lang.classfile.ClassElement; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; @@ -36,13 +42,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; -import jdk.internal.org.objectweb.asm.AnnotationVisitor; -import jdk.internal.org.objectweb.asm.Attribute; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.commons.ModuleTargetAttribute; import jdk.test.lib.util.ModuleInfoWriter; import org.testng.annotations.Test; @@ -51,9 +50,7 @@ import static org.testng.Assert.*; /** * @test * @enablePreview - * @modules java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.org.objectweb.asm.commons - * java.base/jdk.internal.module + * @modules java.base/jdk.internal.module * @library /test/lib * @build jdk.test.lib.util.ModuleInfoWriter * @run testng AnnotationsTest @@ -149,23 +146,39 @@ public class AnnotationsTest { * Adds the Deprecated annotation to the given module-info class file. */ static byte[] addDeprecated(byte[] bytes, boolean forRemoval, String since) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS - + ClassWriter.COMPUTE_FRAMES); + var cf = ClassFile.of(); + var oldModel = cf.parse(bytes); + return cf.transform(oldModel, new ClassTransform() { + boolean rvaaFound = false; - ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) { }; + @Override + public void accept(ClassBuilder builder, ClassElement element) { + if (!rvaaFound && element instanceof RuntimeVisibleAnnotationsAttribute rvaa) { + rvaaFound = true; + var res = new ArrayList(rvaa.annotations().size() + 1); + res.addAll(rvaa.annotations()); + res.add(createDeprecated()); + builder.accept(RuntimeVisibleAnnotationsAttribute.of(res)); + return; + } + builder.accept(element); + } - ClassReader cr = new ClassReader(bytes); - List attrs = new ArrayList<>(); - attrs.add(new ModuleTargetAttribute()); - cr.accept(cv, attrs.toArray(new Attribute[0]), 0); + @Override + public void atEnd(ClassBuilder builder) { + if (!rvaaFound) { + builder.accept(RuntimeVisibleAnnotationsAttribute.of(List.of(createDeprecated()))); + } + } - AnnotationVisitor annotationVisitor - = cv.visitAnnotation("Ljava/lang/Deprecated;", true); - annotationVisitor.visit("forRemoval", forRemoval); - annotationVisitor.visit("since", since); - annotationVisitor.visitEnd(); - - return cw.toByteArray(); + private java.lang.classfile.Annotation createDeprecated() { + return java.lang.classfile.Annotation.of( + Deprecated.class.describeConstable().orElseThrow(), + AnnotationElement.of("forRemoval", AnnotationValue.ofBoolean(forRemoval)), + AnnotationElement.of("since", AnnotationValue.ofString(since)) + ); + } + }); } /** diff --git a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/AnnotationTypeMismatchTest.java b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/AnnotationTypeMismatchTest.java index ab22fff85a6..9c6bfabf82b 100644 --- a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/AnnotationTypeMismatchTest.java +++ b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/AnnotationTypeMismatchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -26,18 +26,21 @@ * @bug 8228988 8266598 * @summary An annotation-typed property of an annotation that is represented as an * incompatible property of another type should yield an AnnotationTypeMismatchException. - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @run main AnnotationTypeMismatchTest */ -import jdk.internal.org.objectweb.asm.AnnotationVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.Type; - import java.lang.annotation.AnnotationTypeMismatchException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.constant.ClassDesc; + +import static java.lang.constant.ConstantDescs.CD_Object; public class AnnotationTypeMismatchTest { @@ -46,12 +49,15 @@ public class AnnotationTypeMismatchTest { * @AnAnnotation(value = AnEnum.VALUE) // would now be: value = @Value * class Carrier { } */ - ClassWriter writer = new ClassWriter(0); - writer.visit(Opcodes.V1_8, 0, "sample/Carrier", null, Type.getInternalName(Object.class), null); - AnnotationVisitor v = writer.visitAnnotation(Type.getDescriptor(AnAnnotation.class), true); - v.visitEnum("value", Type.getDescriptor(AnEnum.class), "VALUE"); - writer.visitEnd(); - byte[] b = writer.toByteArray(); + byte[] b = ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> { + clb.withSuperclass(CD_Object); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of( + AnAnnotation.class.describeConstable().orElseThrow(), + AnnotationElement.of("value", AnnotationValue.of(AnEnum.VALUE)) + ) + )); + }); ByteArrayClassLoader cl = new ByteArrayClassLoader(AnnotationTypeMismatchTest.class.getClassLoader()); cl.init(b); AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class); diff --git a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/ArityTypeMismatchTest.java b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/ArityTypeMismatchTest.java index b6e40e12021..e8908b05ffa 100644 --- a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/ArityTypeMismatchTest.java +++ b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/ArityTypeMismatchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -27,18 +27,21 @@ * @summary Annotation property which is compiled as an array property but * changed observed as a singular element should throw an * AnnotationTypeMismatchException - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @run main ArityTypeMismatchTest */ -import jdk.internal.org.objectweb.asm.AnnotationVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.Type; - import java.lang.annotation.AnnotationTypeMismatchException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.constant.ClassDesc; + +import static java.lang.constant.ConstantDescs.CD_Object; public class ArityTypeMismatchTest { @@ -54,15 +57,15 @@ public class ArityTypeMismatchTest { * * where @AnAnnotation expects a singular value. */ - ClassWriter writer = new ClassWriter(0); - writer.visit(Opcodes.V1_8, 0, "sample/Carrier", null, Type.getInternalName(Object.class), null); - AnnotationVisitor v = writer.visitAnnotation(Type.getDescriptor(AnAnnotation.class), true); - AnnotationVisitor v2 = v.visitArray("value"); - v2.visit(null, "v"); - v2.visitEnd(); - v.visitEnd(); - writer.visitEnd(); - byte[] b = writer.toByteArray(); + byte[] b = ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> { + clb.withSuperclass(CD_Object); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of( + AnAnnotation.class.describeConstable().orElseThrow(), + AnnotationElement.of("value", AnnotationValue.of(new String[] {"v"})) + ) + )); + }); ByteArrayClassLoader cl = new ByteArrayClassLoader(ArityTypeMismatchTest.class.getClassLoader()); cl.init(b); AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class); diff --git a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/ArrayTypeMismatchTest.java b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/ArrayTypeMismatchTest.java index ff85703c5f8..15897b1ca51 100644 --- a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/ArrayTypeMismatchTest.java +++ b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/ArrayTypeMismatchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -26,21 +26,27 @@ * @bug 8266766 * @summary An array property of a type that is no longer of a type that is a legal member of an * annotation should throw an AnnotationTypeMismatchException. - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @run main ArrayTypeMismatchTest */ -import jdk.internal.org.objectweb.asm.AnnotationVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.Type; - import java.lang.annotation.Annotation; import java.lang.annotation.AnnotationTypeMismatchException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; import java.lang.reflect.InvocationTargetException; +import static java.lang.classfile.ClassFile.ACC_ABSTRACT; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.constant.ConstantDescs.CD_Object; + public class ArrayTypeMismatchTest { public static void main(String[] args) throws Exception { @@ -67,8 +73,7 @@ public class ArrayTypeMismatchTest { throw new IllegalStateException("Found value: " + value); } catch (InvocationTargetException ite) { Throwable cause = ite.getCause(); - if (cause instanceof AnnotationTypeMismatchException) { - AnnotationTypeMismatchException e = ((AnnotationTypeMismatchException) cause); + if (cause instanceof AnnotationTypeMismatchException e) { if (!e.element().getName().equals("value")) { throw new IllegalStateException("Unexpected element: " + e.element()); } else if (!e.foundType().equals("Array with component tag: @")) { @@ -81,34 +86,35 @@ public class ArrayTypeMismatchTest { } private static byte[] carrierType() { - ClassWriter writer = new ClassWriter(0); - writer.visit(Opcodes.V1_8, 0, "sample/Carrier", null, Type.getInternalName(Object.class), null); - AnnotationVisitor v = writer.visitAnnotation("Lsample/Host;", true); - AnnotationVisitor a = v.visitArray("value"); - a.visitAnnotation(null, Type.getDescriptor(NoAnnotation.class)).visitEnd(); - a.visitEnd(); - v.visitEnd(); - writer.visitEnd(); - return writer.toByteArray(); + return ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> { + clb.withSuperclass(CD_Object); + var badAnnotationArray = AnnotationValue.ofArray(AnnotationValue.ofAnnotation( + java.lang.classfile.Annotation.of( + NoAnnotation.class.describeConstable().orElseThrow() + ))); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + java.lang.classfile.Annotation.of(ClassDesc.of("sample", "Host"), + AnnotationElement.of("value", badAnnotationArray) + ) + )); + }); } private static byte[] annotationType() { - ClassWriter writer = new ClassWriter(0); - writer.visit(Opcodes.V1_8, - Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE | Opcodes.ACC_ANNOTATION, - "sample/Host", - null, - Type.getInternalName(Object.class), - new String[]{Type.getInternalName(Annotation.class)}); - AnnotationVisitor a = writer.visitAnnotation(Type.getDescriptor(Retention.class), true); - a.visitEnum("value", Type.getDescriptor(RetentionPolicy.class), RetentionPolicy.RUNTIME.name()); - writer.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT, - "value", - Type.getMethodDescriptor(Type.getType(NoAnnotation[].class)), - null, - null).visitEnd(); - writer.visitEnd(); - return writer.toByteArray(); + return ClassFile.of().build(ClassDesc.of("sample", "Host"), clb -> { + clb.withSuperclass(CD_Object); + clb.withInterfaceSymbols(Annotation.class.describeConstable().orElseThrow()); + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.ABSTRACT, AccessFlag.INTERFACE, + AccessFlag.ANNOTATION); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + java.lang.classfile.Annotation.of( + Retention.class.describeConstable().orElseThrow(), + AnnotationElement.of("value", AnnotationValue.of(RetentionPolicy.RUNTIME)) + ) + )); + clb.withMethod("value", MethodTypeDesc.of(NoAnnotation[].class.describeConstable() + .orElseThrow()), ACC_PUBLIC | ACC_ABSTRACT, mb -> {}); + }); } public interface NoAnnotation { } diff --git a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java index 5000aa0ee65..43e62c66e9b 100644 --- a/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java +++ b/test/jdk/java/lang/annotation/AnnotationTypeMismatchException/EnumTypeMismatchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -26,18 +26,21 @@ * @bug 8228988 8266598 * @summary An enumeration-typed property of an annotation that is represented as an * incompatible property of another type should yield an AnnotationTypeMismatchException. - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @run main EnumTypeMismatchTest */ -import jdk.internal.org.objectweb.asm.AnnotationVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.Type; - import java.lang.annotation.AnnotationTypeMismatchException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.constant.ClassDesc; + +import static java.lang.constant.ConstantDescs.CD_Object; public class EnumTypeMismatchTest { @@ -46,12 +49,14 @@ public class EnumTypeMismatchTest { * @AnAnnotation(value = @AnAnnotation) // would now be: value = AnEnum.VALUE * class Carrier { } */ - ClassWriter writer = new ClassWriter(0); - writer.visit(Opcodes.V1_8, 0, "sample/Carrier", null, Type.getInternalName(Object.class), null); - AnnotationVisitor v = writer.visitAnnotation(Type.getDescriptor(AnAnnotation.class), true); - v.visitAnnotation("value", Type.getDescriptor(AnAnnotation.class)).visitEnd(); - writer.visitEnd(); - byte[] b = writer.toByteArray(); + ClassDesc anAnnotationDesc = AnAnnotation.class.describeConstable().orElseThrow(); + byte[] b = ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> { + clb.withSuperclass(CD_Object); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(anAnnotationDesc, AnnotationElement.of("value", + AnnotationValue.ofAnnotation(Annotation.of(anAnnotationDesc)))) + )); + }); ByteArrayClassLoader cl = new ByteArrayClassLoader(EnumTypeMismatchTest.class.getClassLoader()); cl.init(b); AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class); diff --git a/test/jdk/java/lang/annotation/AnnotationVerifier.java b/test/jdk/java/lang/annotation/AnnotationVerifier.java index 5606763e285..012f8ef2b1c 100644 --- a/test/jdk/java/lang/annotation/AnnotationVerifier.java +++ b/test/jdk/java/lang/annotation/AnnotationVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -39,8 +39,8 @@ import java.util.stream.Stream; * @test * @bug 8158510 * @summary Verify valid annotation - * @modules java.base/jdk.internal.org.objectweb.asm * @modules java.base/sun.reflect.annotation + * @enablePreview * @clean AnnotationWithVoidReturn AnnotationWithParameter * AnnotationWithExtraInterface AnnotationWithException * AnnotationWithHashCode AnnotationWithDefaultMember diff --git a/test/jdk/java/lang/annotation/ClassFileGenerator.java b/test/jdk/java/lang/annotation/ClassFileGenerator.java index e5c5f40f4f4..a7dbbcca58f 100644 --- a/test/jdk/java/lang/annotation/ClassFileGenerator.java +++ b/test/jdk/java/lang/annotation/ClassFileGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -22,18 +22,39 @@ */ /* - * Create class file using ASM, slightly modified the ASMifier output + * Create class file using Class-File API, slightly modified the ASMifier output */ - - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import jdk.internal.org.objectweb.asm.*; +import java.io.Serializable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.AnnotationDefaultAttribute; +import java.lang.classfile.attribute.ExceptionsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; +import static java.lang.classfile.ClassFile.ACC_ABSTRACT; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.constant.ConstantDescs.CD_Exception; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.MTD_void; +import static java.lang.reflect.AccessFlag.ABSTRACT; +import static java.lang.reflect.AccessFlag.INTERFACE; +import static java.lang.reflect.AccessFlag.PUBLIC; public class ClassFileGenerator { + private static final ClassDesc CD_Annotation = java.lang.annotation.Annotation.class.describeConstable().orElseThrow(); + private static final ClassDesc CD_Retention = Retention.class.describeConstable().orElseThrow(); public static void main(String... args) throws Exception { classFileWriter("AnnotationWithVoidReturn.class", AnnotationWithVoidReturnDump.dump()); @@ -63,35 +84,19 @@ public class ClassFileGenerator { */ - private static class AnnotationWithVoidReturnDump implements Opcodes { - public static byte[] dump() throws Exception { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - AnnotationVisitor av0; - - cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, - "AnnotationWithVoidReturn", null, - "java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); - - { - av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); - av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", - "RUNTIME"); - av0.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()V", null, null); - mv.visitEnd(); - } - { - av0 = mv.visitAnnotationDefault(); - av0.visit(null, new Integer(1)); - av0.visitEnd(); - } - cw.visitEnd(); - - return cw.toByteArray(); - + private static class AnnotationWithVoidReturnDump { + public static byte[] dump() { + return ClassFile.of().build(ClassDesc.of("AnnotationWithVoidReturn"), clb -> { + clb.withSuperclass(CD_Object); + clb.withInterfaceSymbols(CD_Annotation); + clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(CD_Retention, AnnotationElement.of("value", + AnnotationValue.of(RetentionPolicy.RUNTIME))) + )); + clb.withMethod("m", MTD_void, ACC_PUBLIC | ACC_ABSTRACT, + mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1)))); + }); } } @@ -104,38 +109,19 @@ public class ClassFileGenerator { */ - private static class AnnotationWithParameterDump implements Opcodes { - public static byte[] dump() throws Exception { - - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - AnnotationVisitor av0; - - cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, - "AnnotationWithParameter", null, - "java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); - - { - av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); - av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", - "RUNTIME"); - av0.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, - "badValue", - "(I)I", // Bad method with a parameter - null, null); - mv.visitEnd(); - } - { - av0 = mv.visitAnnotationDefault(); - av0.visit(null, new Integer(-1)); - av0.visitEnd(); - } - cw.visitEnd(); - - return cw.toByteArray(); + private static class AnnotationWithParameterDump { + public static byte[] dump() { + return ClassFile.of().build(ClassDesc.of("AnnotationWithParameter"), clb -> { + clb.withSuperclass(CD_Object); + clb.withInterfaceSymbols(CD_Annotation); + clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(CD_Retention, AnnotationElement.of("value", + AnnotationValue.of(RetentionPolicy.RUNTIME))) + )); + clb.withMethod("m", MethodTypeDesc.of(CD_int, CD_int), ACC_PUBLIC | ACC_ABSTRACT, + mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(-1)))); + }); } } @@ -148,35 +134,19 @@ public class ClassFileGenerator { */ - private static class AnnotationWithExtraInterfaceDump implements Opcodes { - public static byte[] dump() throws Exception { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - AnnotationVisitor av0; - - cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, - "AnnotationWithExtraInterface", null, - "java/lang/Object", new String[]{"java/lang/annotation/Annotation", - "java/io/Serializable"}); - - { - av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); - av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", - "RUNTIME"); - av0.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null); - mv.visitEnd(); - } - { - av0 = mv.visitAnnotationDefault(); - av0.visit(null, new Integer(1)); - av0.visitEnd(); - } - cw.visitEnd(); - - return cw.toByteArray(); + private static class AnnotationWithExtraInterfaceDump { + public static byte[] dump() { + return ClassFile.of().build(ClassDesc.of("AnnotationWithExtraInterface"), clb -> { + clb.withSuperclass(CD_Object); + clb.withInterfaceSymbols(CD_Annotation, Serializable.class.describeConstable().orElseThrow()); + clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(CD_Retention, AnnotationElement.of("value", + AnnotationValue.of(RetentionPolicy.RUNTIME))) + )); + clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT, + mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1)))); + }); } } @@ -189,35 +159,21 @@ public class ClassFileGenerator { */ - private static class AnnotationWithExceptionDump implements Opcodes { - public static byte[] dump() throws Exception { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - AnnotationVisitor av0; - - cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, - "AnnotationWithException", null, - "java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); - - { - av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); - av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", - "RUNTIME"); - av0.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, - new String[] {"java/lang/Exception"}); - mv.visitEnd(); - } - { - av0 = mv.visitAnnotationDefault(); - av0.visit(null, new Integer(1)); - av0.visitEnd(); - } - cw.visitEnd(); - - return cw.toByteArray(); + private static class AnnotationWithExceptionDump { + public static byte[] dump() { + return ClassFile.of().build(ClassDesc.of("AnnotationWithException"), clb -> { + clb.withSuperclass(CD_Object); + clb.withInterfaceSymbols(CD_Annotation); + clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(CD_Retention, AnnotationElement.of("value", + AnnotationValue.of(RetentionPolicy.RUNTIME))) + )); + clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT, mb -> { + mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))); + mb.with(ExceptionsAttribute.ofSymbols(CD_Exception)); + }); + }); } } @@ -230,34 +186,19 @@ public class ClassFileGenerator { */ - private static class AnnotationWithHashCodeDump implements Opcodes { - public static byte[] dump() throws Exception { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - AnnotationVisitor av0; - - cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, - "AnnotationWithHashCode", null, - "java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); - - { - av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); - av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", - "RUNTIME"); - av0.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "hashCode", "()I", null, null); - mv.visitEnd(); - } - { - av0 = mv.visitAnnotationDefault(); - av0.visit(null, new Integer(1)); - av0.visitEnd(); - } - cw.visitEnd(); - - return cw.toByteArray(); + private static class AnnotationWithHashCodeDump { + public static byte[] dump() { + return ClassFile.of().build(ClassDesc.of("AnnotationWithHashCode"), clb -> { + clb.withSuperclass(CD_Object); + clb.withInterfaceSymbols(CD_Annotation); + clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(CD_Retention, AnnotationElement.of("value", + AnnotationValue.of(RetentionPolicy.RUNTIME))) + )); + clb.withMethod("hashCode", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT, + mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1)))); + }); } } @@ -271,47 +212,26 @@ public class ClassFileGenerator { */ - private static class AnnotationWithDefaultMemberDump implements Opcodes { + private static class AnnotationWithDefaultMemberDump { public static byte[] dump() throws Exception { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv, dv; - AnnotationVisitor av0; - - cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, - "AnnotationWithDefaultMember", null, - "java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); - - { - av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); - av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", - "RUNTIME"); - av0.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null); - mv.visitEnd(); - } - { - av0 = mv.visitAnnotationDefault(); - av0.visit(null, new Integer(1)); - av0.visitEnd(); - } - { - dv = cw.visitMethod(ACC_PUBLIC, "d", "()I", null, null); - dv.visitMaxs(1, 1); - dv.visitCode(); - dv.visitInsn(Opcodes.ICONST_2); - dv.visitInsn(Opcodes.IRETURN); - dv.visitEnd(); - } - { - av0 = dv.visitAnnotationDefault(); - av0.visit(null, new Integer(2)); - av0.visitEnd(); - } - cw.visitEnd(); - - return cw.toByteArray(); + return ClassFile.of().build(ClassDesc.of("AnnotationWithDefaultMember"), clb -> { + clb.withSuperclass(CD_Object); + clb.withInterfaceSymbols(CD_Annotation); + clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(CD_Retention, AnnotationElement.of("value", + AnnotationValue.of(RetentionPolicy.RUNTIME))) + )); + clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT, + mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1)))); + clb.withMethod("d", MethodTypeDesc.of(CD_int), ACC_PUBLIC, mb -> { + mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(2))); + mb.withCode(cob -> { + cob.iconst_2(); + cob.ireturn(); + }); + }); + }); } } @@ -324,34 +244,19 @@ public class ClassFileGenerator { */ - private static class AnnotationWithoutAnnotationAccessModifierDump implements Opcodes { - public static byte[] dump() throws Exception { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - AnnotationVisitor av0; - - cw.visit(52, ACC_PUBLIC + /* ACC_ANNOTATION +*/ ACC_ABSTRACT + ACC_INTERFACE, - "AnnotationWithoutAnnotationAccessModifier", null, - "java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); - - { - av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); - av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", - "RUNTIME"); - av0.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null); - mv.visitEnd(); - } - { - av0 = mv.visitAnnotationDefault(); - av0.visit(null, new Integer(1)); - av0.visitEnd(); - } - cw.visitEnd(); - - return cw.toByteArray(); + private static class AnnotationWithoutAnnotationAccessModifierDump { + public static byte[] dump() { + return ClassFile.of().build(ClassDesc.of("AnnotationWithoutAnnotationAccessModifier"), clb -> { + clb.withSuperclass(CD_Object); + clb.withInterfaceSymbols(CD_Annotation); + clb.withFlags(PUBLIC, /*AccessFlag.ANNOTATION,*/ ABSTRACT, AccessFlag.INTERFACE); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(CD_Retention, AnnotationElement.of("value", + AnnotationValue.of(RetentionPolicy.RUNTIME))) + )); + clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT, + mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1)))); + }); } } @@ -365,24 +270,16 @@ public class ClassFileGenerator { */ - private static class HolderXDump implements Opcodes { - public static byte[] dump() throws Exception { - ClassWriter cw = new ClassWriter(0); - - cw.visit(52, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, - "HolderX", null, - "java/lang/Object", new String[0]); - - { - AnnotationVisitor av0; - av0 = cw.visitAnnotation("LGoodAnnotation;", true); - av0.visitEnd(); - av0 = cw.visitAnnotation("LAnnotationWithoutAnnotationAccessModifier;", true); - av0.visitEnd(); - } - cw.visitEnd(); - - return cw.toByteArray(); + private static class HolderXDump { + public static byte[] dump() { + return ClassFile.of().build(ClassDesc.of("HolderX"), clb -> { + clb.withSuperclass(CD_Object); + clb.withFlags(PUBLIC, ABSTRACT, INTERFACE); + clb.with(RuntimeVisibleAnnotationsAttribute.of( + Annotation.of(ClassDesc.of("GoodAnnotation")), + Annotation.of(ClassDesc.of("ClassFileGenerator$AnnotationWithoutAnnotationAccessModifier")) + )); + }); } } } diff --git a/test/jdk/java/lang/instrument/MakeJAR2.sh b/test/jdk/java/lang/instrument/MakeJAR2.sh index c796d807799..cb31c640919 100644 --- a/test/jdk/java/lang/instrument/MakeJAR2.sh +++ b/test/jdk/java/lang/instrument/MakeJAR2.sh @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 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 @@ -87,7 +87,8 @@ ${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} bootreporter/*.java cd .. ${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ - --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED ${AGENT}.java asmlib/*.java + --enable-preview --release 23 \ + ${AGENT}.java asmlib/*.java ${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -classpath .${PATHSEP}bootpath ${APP}.java echo "Manifest-Version: 1.0" > ${AGENT}.mf diff --git a/test/jdk/java/lang/instrument/NativeMethodPrefixAgent.java b/test/jdk/java/lang/instrument/NativeMethodPrefixAgent.java index 37e0acd62c0..e8b5bbe7dd9 100644 --- a/test/jdk/java/lang/instrument/NativeMethodPrefixAgent.java +++ b/test/jdk/java/lang/instrument/NativeMethodPrefixAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -21,25 +21,29 @@ * questions. */ -/** +/* * @test * @bug 6263319 * @requires ((vm.opt.StartFlightRecording == null) | (vm.opt.StartFlightRecording == false)) & ((vm.opt.FlightRecorder == null) | (vm.opt.FlightRecorder == false)) * @summary test setNativeMethodPrefix * @author Robert Field, Sun Microsystems * - * @modules java.base/jdk.internal.org.objectweb.asm - * java.management + * @enablePreview + * @modules java.management * java.instrument * @run shell/timeout=240 MakeJAR2.sh NativeMethodPrefixAgent NativeMethodPrefixApp 'Can-Retransform-Classes: true' 'Can-Set-Native-Method-Prefix: true' * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-CheckIntrinsics -javaagent:NativeMethodPrefixAgent.jar NativeMethodPrefixApp */ +import asmlib.Instrumentor; + +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.instrument.*; import java.security.ProtectionDomain; import java.io.*; -import asmlib.*; +import static java.lang.constant.ConstantDescs.*; class NativeMethodPrefixAgent { @@ -54,6 +58,8 @@ class NativeMethodPrefixAgent { } static class Tr implements ClassFileTransformer { + private static final ClassDesc CD_StringIdCallbackReporter = ClassDesc.ofInternalName("bootreporter/StringIdCallbackReporter"); + private static final MethodTypeDesc MTD_void_String_int = MethodTypeDesc.of(CD_void, CD_String, CD_int); final String trname; final int transformId; @@ -76,11 +82,13 @@ class NativeMethodPrefixAgent { try { byte[] newcf = Instrumentor.instrFor(classfileBuffer) .addNativeMethodTrackingInjection( - "wrapped_" + trname + "_", - (h)->{ - h.push(h.getName()); - h.push(transformId); - h.invokeStatic("bootreporter/StringIdCallbackReporter", "tracker", "(Ljava/lang/String;I)V", false); + "wrapped_" + trname + "_", (name, h) -> { + h.constantInstruction(name); + h.constantInstruction(transformId); + h.invokestatic( + CD_StringIdCallbackReporter, + "tracker", + MTD_void_String_int); }) .apply(); /*** debugging ... diff --git a/test/jdk/java/lang/instrument/RetransformAgent.java b/test/jdk/java/lang/instrument/RetransformAgent.java index 698449cac14..f5eadabad16 100644 --- a/test/jdk/java/lang/instrument/RetransformAgent.java +++ b/test/jdk/java/lang/instrument/RetransformAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -21,23 +21,28 @@ * questions. */ -/** +/* * @test * @bug 6274264 6274241 5070281 * @summary test retransformClasses * @author Robert Field, Sun Microsystems * - * @modules java.base/jdk.internal.org.objectweb.asm - * java.instrument + * @enablePreview + * @modules java.instrument * @run shell/timeout=240 MakeJAR2.sh RetransformAgent RetransformApp 'Can-Retransform-Classes: true' * @run main/othervm -javaagent:RetransformAgent.jar RetransformApp */ +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.instrument.*; import java.security.ProtectionDomain; import java.io.*; import asmlib.*; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.CD_void; + class RetransformAgent { static ClassFileTransformer t1, t2, t3, t4; @@ -48,6 +53,8 @@ class RetransformAgent { 11, 40, 20, 11, 40, 20, 11, 40, 20, 11, 40, 20}; static class Tr implements ClassFileTransformer { + private static final ClassDesc CD_RetransformAgent = RetransformAgent.class.describeConstable().orElseThrow(); + private static final MethodTypeDesc MTD_void_int = MethodTypeDesc.of(CD_void, CD_int); final String trname; final boolean onLoad; final int loadIndex; @@ -83,9 +90,11 @@ class RetransformAgent { byte[] newcf = Instrumentor.instrFor(classfileBuffer) .addMethodEntryInjection( nname, - (h)->{ - h.push(fixedIndex); - h.invokeStatic("RetransformAgent", "callTracker", "(I)V", false); + cb -> { + cb.constantInstruction(fixedIndex); + cb.invokestatic( + CD_RetransformAgent, + "callTracker", MTD_void_int); }) .apply(); /*** debugging ... diff --git a/test/jdk/java/lang/instrument/asmlib/Instrumentor.java b/test/jdk/java/lang/instrument/asmlib/Instrumentor.java index 97862a3c791..ed5e219dd4d 100644 --- a/test/jdk/java/lang/instrument/asmlib/Instrumentor.java +++ b/test/jdk/java/lang/instrument/asmlib/Instrumentor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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,171 +23,133 @@ package asmlib; -import java.io.PrintStream; +import java.lang.classfile.AccessFlags; +import java.lang.classfile.ClassBuilder; +import java.lang.classfile.ClassElement; +import java.lang.classfile.ClassModel; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.CodeModel; +import java.lang.classfile.CodeTransform; +import java.lang.classfile.MethodBuilder; +import java.lang.classfile.MethodElement; +import java.lang.classfile.MethodModel; +import java.lang.classfile.MethodTransform; +import java.lang.classfile.Opcode; +import java.lang.classfile.TypeKind; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; - +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BiConsumer; import java.util.function.Consumer; -import jdk.internal.org.objectweb.asm.Type; + +import static java.lang.classfile.ClassFile.ACC_NATIVE; public class Instrumentor { - public static class InstrHelper { - private final MethodVisitor mv; - private final String name; - - InstrHelper(MethodVisitor mv, String name) { - this.mv = mv; - this.name = name; - } - - public String getName() { - return this.name; - } - - public void invokeStatic(String owner, String name, String desc, boolean itf) { - mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf); - } - - public void invokeSpecial(String owner, String name, String desc) { - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false); - } - - public void invokeVirtual(String owner, String name, String desc) { - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false); - } - - public void push(int val) { - if (val >= -1 && val <= 5) { - mv.visitInsn(Opcodes.ICONST_0 + val); - } else if (val >= Byte.MIN_VALUE && val <= Byte.MAX_VALUE) { - mv.visitIntInsn(Opcodes.BIPUSH, val); - } else if (val >= Short.MIN_VALUE && val <= Short.MAX_VALUE) { - mv.visitIntInsn(Opcodes.SIPUSH, val); - } else { - mv.visitLdcInsn(val); - } - } - - public void push(Object val) { - mv.visitLdcInsn(val); - } - - public void println(String s) { - mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(System.class), "out", Type.getDescriptor(PrintStream.class)); - mv.visitLdcInsn(s); - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(PrintStream.class), "println", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)), false); - } - } public static Instrumentor instrFor(byte[] classData) { return new Instrumentor(classData); } - - private final ClassReader cr; - private final ClassWriter output; - private ClassVisitor instrumentingVisitor = null; - private final AtomicInteger matches = new AtomicInteger(0); + private final ClassModel model; + private ClassTransform transform = ClassTransform.ACCEPT_ALL; + private final AtomicBoolean dirty = new AtomicBoolean(false); private Instrumentor(byte[] classData) { - cr = new ClassReader(classData); - output = new ClassWriter(ClassWriter.COMPUTE_MAXS); - instrumentingVisitor = output; + model = ClassFile.of().parse(classData); } - public synchronized Instrumentor addMethodEntryInjection(String methodName, Consumer injector) { - instrumentingVisitor = new ClassVisitor(Opcodes.ASM7, instrumentingVisitor) { - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); - - if (name.equals(methodName)) { - matches.getAndIncrement(); - - mv = new MethodVisitor(Opcodes.ASM7, mv) { - @Override - public void visitCode() { - injector.accept(new InstrHelper(mv, name)); - } - }; - } - return mv; + public synchronized Instrumentor addMethodEntryInjection(String methodName, Consumer injector) { + transform = transform.andThen(ClassTransform.transformingMethodBodies(mm -> { + if (mm.methodName().equalsString(methodName)) { + dirty.set(true); + return true; } - }; + return false; + }, new CodeTransform() { + @Override + public void atStart(CodeBuilder builder) { + injector.accept(builder); + } + + @Override + public void accept(CodeBuilder builder, CodeElement element) { + builder.accept(element); + } + })); return this; } - public synchronized Instrumentor addNativeMethodTrackingInjection(String prefix, Consumer injector) { - instrumentingVisitor = new ClassVisitor(Opcodes.ASM9, instrumentingVisitor) { - private final Set> wmGenerators = new HashSet<>(); - private String className; + public synchronized Instrumentor addNativeMethodTrackingInjection(String prefix, BiConsumer injector) { + transform = transform.andThen(ClassTransform.ofStateful(() -> new ClassTransform() { + private final Set> wmGenerators = new HashSet<>(); @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - this.className = name; - super.visit(version, access, name, signature, superName, interfaces); - } - - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - if ((access & Opcodes.ACC_NATIVE) != 0) { - matches.getAndIncrement(); + public void accept(ClassBuilder builder, ClassElement element) { + if (element instanceof MethodModel mm && mm.flags().has(AccessFlag.NATIVE)) { + dirty.set(true); + String name = mm.methodName().stringValue(); String newName = prefix + name; - wmGenerators.add((v)->{ - MethodVisitor mv = v.visitMethod(access & ~Opcodes.ACC_NATIVE, name, desc, signature, exceptions); - mv.visitCode(); - injector.accept(new InstrHelper(mv, name)); - Type[] argTypes = Type.getArgumentTypes(desc); - Type retType = Type.getReturnType(desc); - - boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; - if (!isStatic) { - mv.visitIntInsn(Opcodes.ALOAD, 0); // load "this" - } - - // load the method parameters - if (argTypes.length > 0) { - int ptr = isStatic ? 0 : 1; - for(Type argType : argTypes) { - mv.visitIntInsn(argType.getOpcode(Opcodes.ILOAD), ptr); - ptr += argType.getSize(); + MethodTypeDesc mt = mm.methodTypeSymbol(); + wmGenerators.add(clb -> clb.transformMethod(mm, new MethodTransform() { + @Override + public void accept(MethodBuilder mb, MethodElement me) { + if (me instanceof AccessFlags flags) { + mb.withFlags(flags.flagsMask() & ~ACC_NATIVE); + } else if (!(me instanceof CodeModel)) { + mb.with(me); } } - mv.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKESPECIAL, className, newName, desc, false); - mv.visitInsn(retType.getOpcode(Opcodes.IRETURN)); + @Override + public void atEnd(MethodBuilder mb) { + Consumer injection = cb -> injector.accept(name, cb); + mb.withCode(injection.andThen(cb -> { + int ptr; + boolean isStatic = mm.flags().has(AccessFlag.STATIC); + if (!isStatic) { + cb.aload(0); // load "this" + ptr = 1; + } else { + ptr = 0; + } - mv.visitMaxs(1, 1); // dummy call; let ClassWriter to deal with this - mv.visitEnd(); - }); - return super.visitMethod(access, newName, desc, signature, exceptions); + // load method parameters + for (int i = 0; i < mt.parameterCount(); i++) { + TypeKind kind = TypeKind.from(mt.parameterType(i)); + cb.loadInstruction(kind, ptr); + ptr += kind.slotSize(); + } + + cb.invokeInstruction(isStatic ? Opcode.INVOKESTATIC : Opcode.INVOKESPECIAL, + model.thisClass().asSymbol(), newName, mt, false); + cb.returnInstruction(TypeKind.from(mt.returnType())); + })); + } + })); + + builder.withMethod(newName, mt, mm.flags().flagsMask(), mm::forEachElement); + } else { + builder.accept(element); } - return super.visitMethod(access, name, desc, signature, exceptions); } @Override - public void visitEnd() { - wmGenerators.stream().forEach((e) -> { - e.accept(cv); - }); - super.visitEnd(); + public void atEnd(ClassBuilder builder) { + wmGenerators.forEach(e -> e.accept(builder)); } - }; - + })); return this; } public synchronized byte[] apply() { - cr.accept(instrumentingVisitor, ClassReader.SKIP_DEBUG + ClassReader.EXPAND_FRAMES); + var bytes = ClassFile.of().transform(model, transform); - return matches.get() == 0 ? null : output.toByteArray(); + return dirty.get() ? bytes : null; } } diff --git a/test/jdk/java/lang/invoke/8022701/BogoLoader.java b/test/jdk/java/lang/invoke/8022701/BogoLoader.java index 568ff62089e..ac06718b42a 100644 --- a/test/jdk/java/lang/invoke/8022701/BogoLoader.java +++ b/test/jdk/java/lang/invoke/8022701/BogoLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,18 +24,14 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.ClassFile; import java.util.Map; import java.util.Set; import java.util.Vector; -import jdk.internal.org.objectweb.asm.*; public class BogoLoader extends ClassLoader { - static interface VisitorMaker { - ClassVisitor make(ClassVisitor visitor); - } - - /** * Use this property to verify that the desired classloading is happening. */ @@ -55,7 +51,7 @@ public class BogoLoader extends ClassLoader { /** * Map from class names to a bytecode transformer factory. */ - private Map replaced; + private Map replaced; /** * Keep track (not terribly efficiently) of which classes have already @@ -67,7 +63,7 @@ public class BogoLoader extends ClassLoader { return ! nonSystem.contains(name) && ! replaced.containsKey(name); } - public BogoLoader(Set non_system, Map replaced) { + public BogoLoader(Set non_system, Map replaced) { super(Thread.currentThread().getContextClassLoader()); this.nonSystem = non_system; this.replaced = replaced; @@ -126,11 +122,8 @@ public class BogoLoader extends ClassLoader { if (verbose) { System.err.println("Replacing class " + name); } - ClassReader cr = new ClassReader(classData); - ClassWriter cw = new ClassWriter(0); - VisitorMaker vm = replaced.get(name); - cr.accept(vm.make(cw), 0); - classData = cw.toByteArray(); + var cf = ClassFile.of(); + classData = cf.transform(cf.parse(classData), replaced.get(name)); } clazz = defineClass(name, classData, 0, classData.length); } catch (java.io.EOFException ioe) { diff --git a/test/jdk/java/lang/invoke/8022701/MHIllegalAccess.java b/test/jdk/java/lang/invoke/8022701/MHIllegalAccess.java index 18d4a4c6752..0880985638d 100644 --- a/test/jdk/java/lang/invoke/8022701/MHIllegalAccess.java +++ b/test/jdk/java/lang/invoke/8022701/MHIllegalAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -21,60 +21,53 @@ * questions. */ -/** +/* * @test * @bug 8022701 * @summary Illegal access exceptions via methodhandle invocations threw wrong error. - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @compile -XDignore.symbol.file BogoLoader.java InvokeSeveralWays.java MHIllegalAccess.java MethodSupplier.java * @run main/othervm MHIllegalAccess */ +import java.lang.classfile.AccessFlags; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.MethodModel; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.HashSet; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; -public class MHIllegalAccess implements Opcodes { +import static java.lang.classfile.ClassFile.ACC_PRIVATE; +import static java.lang.classfile.ClassFile.ACC_PROTECTED; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; - public static void main(String args[]) throws Throwable { +public class MHIllegalAccess { + + public static void main(String[] args) throws Throwable { System.out.println("Classpath is " + System.getProperty("java.class.path")); System.out.println(); /** * Make method m be private to provoke an IllegalAccessError. */ - BogoLoader.VisitorMaker privatize = new BogoLoader.VisitorMaker() { - public ClassVisitor make(ClassVisitor cv) { - return new ClassVisitor(Opcodes.ASM5, cv) { - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - if (name.equals("m")) - access = (access | ACC_PRIVATE) & ~ (ACC_PUBLIC | ACC_PROTECTED); - return super.visitMethod(access, name, desc, signature, exceptions); - } - }; - } - }; + var privatize = ClassTransform.transformingMethods(m -> m.methodName().equalsString("m"), (mb, me) -> { + if (me instanceof AccessFlags af) { + mb.withFlags((af.flagsMask() | ACC_PRIVATE) & ~ (ACC_PUBLIC | ACC_PROTECTED)); + } else { + mb.accept(me); + } + }); /** * Rename method m as nemo to provoke a NoSuchMethodError. */ - BogoLoader.VisitorMaker changeName = new BogoLoader.VisitorMaker() { - public ClassVisitor make(ClassVisitor cv) { - return new ClassVisitor(Opcodes.ASM5, cv) { - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - if (name.equals("m")) - name = "nemo"; - return super.visitMethod(access, name, desc, signature, exceptions); - } - }; - } - }; + ClassTransform changeName = (cb, ce) -> { + if (ce instanceof MethodModel mm && mm.methodName().equalsString("m")) { + cb.withMethod("nemo", mm.methodTypeSymbol(), mm.flags().flagsMask(), mm::forEachElement); + } else { + cb.accept(ce); + } + }; int failures = 0; failures += testOneError(privatize, args, IllegalAccessError.class); @@ -94,8 +87,8 @@ public class MHIllegalAccess implements Opcodes { * @throws ClassNotFoundException * @throws Throwable */ - private static int testOneError(BogoLoader.VisitorMaker vm, String[] args, Class expected) throws ClassNotFoundException, Throwable { - HashMap replace = new HashMap(); + private static int testOneError(ClassTransform vm, String[] args, Class expected) throws ClassNotFoundException, Throwable { + var replace = new HashMap(); replace.put("MethodSupplier", vm); HashSet in_bogus = new HashSet(); diff --git a/test/jdk/java/lang/invoke/DefineClassTest.java b/test/jdk/java/lang/invoke/DefineClassTest.java index d44bd3b699c..6a9ee82de39 100644 --- a/test/jdk/java/lang/invoke/DefineClassTest.java +++ b/test/jdk/java/lang/invoke/DefineClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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,31 +23,38 @@ /* @test * @modules java.base/java.lang:open - * java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @run testng/othervm test.DefineClassTest * @summary Basic test for java.lang.invoke.MethodHandles.Lookup.defineClass */ package test; +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; import java.lang.invoke.MethodHandles.Lookup; -import static java.lang.invoke.MethodHandles.*; -import static java.lang.invoke.MethodHandles.Lookup.*; +import java.lang.reflect.AccessFlag; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; - -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import static jdk.internal.org.objectweb.asm.Opcodes.*; - import org.testng.annotations.Test; + +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; +import static java.lang.invoke.MethodHandles.*; +import static java.lang.invoke.MethodHandles.Lookup.*; import static org.testng.Assert.*; public class DefineClassTest { private static final String THIS_PACKAGE = DefineClassTest.class.getPackageName(); + private static final ClassDesc CD_Runnable = Runnable.class.describeConstable().orElseThrow(); + private static final ClassDesc CD_MissingSuperClass = ClassDesc.of("MissingSuperClass"); /** * Test that a class has the same class loader, and is in the same package and @@ -251,25 +258,15 @@ public class DefineClassTest { * Generates a class file with the given class name */ byte[] generateClass(String className) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS - + ClassWriter.COMPUTE_FRAMES); - cw.visit(V9, - ACC_PUBLIC + ACC_SUPER, - className.replace(".", "/"), - null, - "java/lang/Object", - null); - - // - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(ClassDesc.of(className), clb -> { + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); + clb.withSuperclass(CD_Object); + clb.withMethodBody(INIT_NAME, MTD_void, PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(CD_Object, INIT_NAME, MTD_void); + cob.return_(); + }); + }); } /** @@ -280,33 +277,19 @@ public class DefineClassTest { String targetClass, String targetMethod) throws Exception { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS - + ClassWriter.COMPUTE_FRAMES); - cw.visit(V9, - ACC_PUBLIC + ACC_SUPER, - className.replace(".", "/"), - null, - "java/lang/Object", - new String[] { "java/lang/Runnable" }); - - // - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - // run() - String tc = targetClass.replace(".", "/"); - mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null); - mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(ClassDesc.of(className), clb -> { + clb.withSuperclass(CD_Object); + clb.withInterfaceSymbols(CD_Runnable); + clb.withMethodBody(INIT_NAME, MTD_void, PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(CD_Object, INIT_NAME, MTD_void); + cob.return_(); + }); + clb.withMethodBody("run", MTD_void, PUBLIC, cob -> { + cob.invokestatic(ClassDesc.of(targetClass), targetMethod, MTD_void); + cob.return_(); + }); + }); } /** @@ -317,75 +300,41 @@ public class DefineClassTest { String targetClass, String targetMethod) throws Exception { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS - + ClassWriter.COMPUTE_FRAMES); - cw.visit(V9, - ACC_PUBLIC + ACC_SUPER, - className.replace(".", "/"), - null, - "java/lang/Object", - null); - - // - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - // - String tc = targetClass.replace(".", "/"); - mv = cw.visitMethod(ACC_STATIC, "", "()V", null, null); - mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(ClassDesc.of(className), clb -> { + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); + clb.withSuperclass(CD_Object); + clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(CD_Object, INIT_NAME, MTD_void); + cob.return_(); + }); + clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, cob -> { + cob.invokestatic(ClassDesc.of(targetClass), targetMethod, MTD_void); + cob.return_(); + }); + }); } /** * Generates a non-linkable class file with the given class name */ byte[] generateNonLinkableClass(String className) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS - + ClassWriter.COMPUTE_FRAMES); - cw.visit(V14, - ACC_PUBLIC + ACC_SUPER, - className.replace(".", "/"), - null, - "MissingSuperClass", - null); - - // - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "MissingSuperClass", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(ClassDesc.of(className), clb -> { + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); + clb.withSuperclass(CD_MissingSuperClass); + clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(CD_MissingSuperClass, INIT_NAME, MTD_void); + cob.return_(); + }); + }); } /** * Generates a class file with the given class name */ byte[] generateModuleInfo() { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS - + ClassWriter.COMPUTE_FRAMES); - cw.visit(V14, - ACC_MODULE, - "module-info", - null, - null, - null); - - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(ClassDesc.of("module-info"), cb -> cb.withFlags(AccessFlag.MODULE)); } private int nextNumber() { diff --git a/test/jdk/java/lang/invoke/MethodHandles/classData/ClassDataTest.java b/test/jdk/java/lang/invoke/MethodHandles/classData/ClassDataTest.java index ab5d81d4ec5..edcc095c77b 100644 --- a/test/jdk/java/lang/invoke/MethodHandles/classData/ClassDataTest.java +++ b/test/jdk/java/lang/invoke/MethodHandles/classData/ClassDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -25,17 +25,26 @@ * @test * @bug 8230501 * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @run testng/othervm ClassDataTest */ import java.io.IOException; import java.io.OutputStream; import java.io.UncheckedIOException; +import java.lang.classfile.ClassBuilder; +import java.lang.classfile.ClassFile; +import java.lang.classfile.TypeKind; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; +import java.lang.constant.DirectMethodHandleDesc; +import java.lang.constant.DynamicConstantDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; +import java.lang.reflect.AccessFlag; import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; @@ -43,18 +52,20 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.stream.Stream; -import jdk.internal.org.objectweb.asm.*; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import static java.lang.classfile.ClassFile.*; +import static java.lang.constant.ConstantDescs.*; import static java.lang.invoke.MethodHandles.Lookup.*; -import static jdk.internal.org.objectweb.asm.Opcodes.*; import static org.testng.Assert.*; public class ClassDataTest { private static final Lookup LOOKUP = MethodHandles.lookup(); + private static final ClassDesc CD_ClassDataTest = ClassDataTest.class.describeConstable().orElseThrow(); @Test public void testOriginalAccess() throws IllegalAccessException { @@ -294,15 +305,13 @@ public class ClassDataTest { public void classDataMap() throws ReflectiveOperationException { ClassByteBuilder builder = new ClassByteBuilder("map"); // generate classData static method - Handle bsm = new Handle(H_INVOKESTATIC, "ClassDataTest", "getClassDataEntry", - "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;", - false); + DirectMethodHandleDesc bsm = ConstantDescs.ofConstantBootstrap(CD_ClassDataTest, "getClassDataEntry", CD_Object); // generate two accessor methods to get the entries from class data byte[] bytes = builder.classData(ACC_PUBLIC|ACC_STATIC, Map.class) .classData(ACC_PUBLIC|ACC_STATIC, "getClass", - Class.class, new ConstantDynamic("class", Type.getDescriptor(Class.class), bsm)) + Class.class, DynamicConstantDesc.ofNamed(bsm, "class", CD_Class)) .classData(ACC_PUBLIC|ACC_STATIC, "getMethod", - MethodHandle.class, new ConstantDynamic("method", Type.getDescriptor(MethodHandle.class), bsm)) + MethodHandle.class, DynamicConstantDesc.ofNamed(bsm, "method", CD_MethodHandle)) .build(); // generate a hidden class @@ -342,29 +351,28 @@ public class ClassDataTest { private static final String MHS_CLS = "java/lang/invoke/MethodHandles"; private static final String CLASS_DATA_BSM_DESCR = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;"; - private final ClassWriter cw; - private final String classname; + private Consumer cw; + private final ClassDesc classname; /** * A builder to generate a class file to access class data * @param classname */ ClassByteBuilder(String classname) { - this.classname = classname; - this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(V14, ACC_FINAL, classname, null, OBJECT_CLS, null); - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, OBJECT_CLS, "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); + this.classname = ClassDesc.ofInternalName(classname); + this.cw = clb -> { + clb.withSuperclass(CD_Object); + clb.withFlags(AccessFlag.FINAL); + clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(CD_Object, INIT_NAME, MTD_void); + cob.return_(); + }); + }; } byte[] build() { - cw.visitEnd(); - byte[] bytes = cw.toByteArray(); + byte[] bytes = ClassFile.of().build(classname, cw); Path p = Paths.get(classname + ".class"); try (OutputStream os = Files.newOutputStream(p)) { os.write(bytes); @@ -378,20 +386,14 @@ public class ClassDataTest { * Generate classData method to load class data via condy */ ClassByteBuilder classData(int accessFlags, Class returnType) { - MethodType mtype = MethodType.methodType(returnType); - MethodVisitor mv = cw.visitMethod(accessFlags, - "classData", - mtype.descriptorString(), null, null); - mv.visitCode(); - Handle bsm = new Handle(H_INVOKESTATIC, MHS_CLS, "classData", - CLASS_DATA_BSM_DESCR, - false); - ConstantDynamic dynamic = new ConstantDynamic("_", Type.getDescriptor(returnType), bsm); - mv.visitLdcInsn(dynamic); - mv.visitInsn(returnType == int.class ? IRETURN : - (returnType == float.class ? FRETURN : ARETURN)); - mv.visitMaxs(0, 0); - mv.visitEnd(); + ClassDesc returnDesc = returnType.describeConstable().orElseThrow(); + MethodTypeDesc mt = MethodTypeDesc.of(returnDesc); + cw = cw.andThen(clb -> { + clb.withMethodBody("classData", mt, accessFlags, cob -> { + cob.constantInstruction(DynamicConstantDesc.ofNamed(BSM_CLASS_DATA, DEFAULT_NAME, returnDesc)); + cob.returnInstruction(TypeKind.from(returnType)); + }); + }); return this; } @@ -399,32 +401,26 @@ public class ClassDataTest { * Generate classDataAt method to load an element from class data via condy */ ClassByteBuilder classDataAt(int accessFlags, Class returnType, int index) { - MethodType mtype = MethodType.methodType(returnType); - MethodVisitor mv = cw.visitMethod(accessFlags, - "classData", - mtype.descriptorString(), null, null); - mv.visitCode(); - Handle bsm = new Handle(H_INVOKESTATIC, "java/lang/invoke/MethodHandles", "classDataAt", - "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;I)Ljava/lang/Object;", - false); - ConstantDynamic dynamic = new ConstantDynamic("_", Type.getDescriptor(returnType), bsm, index); - mv.visitLdcInsn(dynamic); - mv.visitInsn(returnType == int.class? IRETURN : ARETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); + ClassDesc returnDesc = returnType.describeConstable().orElseThrow(); + MethodTypeDesc mt = MethodTypeDesc.of(returnDesc); + cw = cw.andThen(clb -> { + clb.withMethodBody("classData", mt, accessFlags, cob -> { + cob.constantInstruction(DynamicConstantDesc.ofNamed(BSM_CLASS_DATA_AT, DEFAULT_NAME, returnDesc, index)); + cob.returnInstruction(TypeKind.from(returnType)); + }); + }); return this; } - ClassByteBuilder classData(int accessFlags, String name, Class returnType, ConstantDynamic dynamic) { - MethodType mtype = MethodType.methodType(returnType); - MethodVisitor mv = cw.visitMethod(accessFlags, - name, - mtype.descriptorString(), null, null); - mv.visitCode(); - mv.visitLdcInsn(dynamic); - mv.visitInsn(returnType == int.class? IRETURN : ARETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); + ClassByteBuilder classData(int accessFlags, String name, Class returnType, DynamicConstantDesc dynamic) { + ClassDesc returnDesc = returnType.describeConstable().orElseThrow(); + MethodTypeDesc mt = MethodTypeDesc.of(returnDesc); + cw = cw.andThen(clb -> { + clb.withMethodBody(name, mt, accessFlags, cob -> { + cob.constantInstruction(dynamic); + cob.returnInstruction(TypeKind.from(returnType)); + }); + }); return this; } } diff --git a/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java b/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java index b4d19fe8a05..0f149959928 100644 --- a/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java +++ b/test/jdk/java/lang/invoke/accessProtectedSuper/BogoLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,19 +24,16 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.ClassFile; import java.util.Map; import java.util.Set; import java.util.Vector; -import jdk.internal.org.objectweb.asm.*; + // Compile with -XDignore.symbol.file=true public class BogoLoader extends ClassLoader { - static interface VisitorMaker { - ClassVisitor make(ClassVisitor visitor); - } - - /** * Use this property to verify that the desired classloading is happening. */ @@ -56,7 +53,7 @@ public class BogoLoader extends ClassLoader { /** * Map from class names to a bytecode transformer factory. */ - private Map replaced; + private Map replaced; /** * Keep track (not terribly efficiently) of which classes have already @@ -68,7 +65,7 @@ public class BogoLoader extends ClassLoader { return ! nonSystem.contains(name) && ! replaced.containsKey(name); } - public BogoLoader(Set non_system, Map replaced) { + public BogoLoader(Set non_system, Map replaced) { super(Thread.currentThread().getContextClassLoader()); this.nonSystem = non_system; this.replaced = replaced; @@ -127,11 +124,8 @@ public class BogoLoader extends ClassLoader { if (verbose) { System.err.println("Replacing class " + name); } - ClassReader cr = new ClassReader(classData); - ClassWriter cw = new ClassWriter(0); - VisitorMaker vm = replaced.get(name); - cr.accept(vm.make(cw), 0); - classData = cw.toByteArray(); + var cf = ClassFile.of(); + classData = cf.transform(cf.parse(classData), replaced.get(name)); } clazz = defineClass(name, classData, 0, classData.length); } catch (java.io.EOFException ioe) { diff --git a/test/jdk/java/lang/invoke/accessProtectedSuper/Test.java b/test/jdk/java/lang/invoke/accessProtectedSuper/Test.java index f24e1fc08ac..4ad03bb068a 100644 --- a/test/jdk/java/lang/invoke/accessProtectedSuper/Test.java +++ b/test/jdk/java/lang/invoke/accessProtectedSuper/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -21,64 +21,53 @@ * questions. */ -/** +/* * @test * @bug 8022718 * @summary Runtime accessibility checking: protected class, if extended, should be accessible from another package - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @compile -XDignore.symbol.file BogoLoader.java MethodInvoker.java Test.java anotherpkg/MethodSupplierOuter.java * @run main/othervm Test */ -import java.lang.reflect.InvocationTargetException; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.attribute.InnerClassInfo; +import java.lang.classfile.attribute.InnerClassesAttribute; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.Utf8Entry; import java.lang.reflect.Method; import java.util.HashMap; import java.util.HashSet; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; + +import static java.lang.classfile.ClassFile.ACC_PRIVATE; +import static java.lang.classfile.ClassFile.ACC_PROTECTED; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; interface MyFunctionalInterface { void invokeMethodReference(); } -class MakeProtected implements BogoLoader.VisitorMaker, Opcodes { - - final boolean whenVisitInner; - - MakeProtected(boolean when_visit_inner) { - super(); - whenVisitInner = when_visit_inner; - } - - public ClassVisitor make(ClassVisitor cv) { - return new ClassVisitor(Opcodes.ASM7, cv) { - - @Override - public void visitInnerClass(String name, String outerName, - String innerName, int access) { - if (whenVisitInner) { - int access_ = (ACC_PROTECTED | access) & ~(ACC_PRIVATE | ACC_PUBLIC); - System.out.println("visitInnerClass: name = " + name - + ", outerName = " + outerName - + ", innerName = " + innerName - + ", access original = 0x" + Integer.toHexString(access) - + ", access modified to 0x" + Integer.toHexString(access_)); - access = access_; - } - super.visitInnerClass(name, outerName, innerName, access); - } - }; - } -}; - public class Test { - public static void main(String argv[]) throws Exception, Throwable { - BogoLoader.VisitorMaker makeProtectedNop = new MakeProtected(false); - BogoLoader.VisitorMaker makeProtectedMod = new MakeProtected(true); + public static void main(String[] argv) throws Throwable { + ClassTransform makeProtectedNop = ClassTransform.ACCEPT_ALL; + ClassTransform makeProtectedMod = (cb, ce) -> { + if (ce instanceof InnerClassesAttribute ica) { + cb.accept(InnerClassesAttribute.of(ica.classes().stream().map(ici -> { + // AccessFlags doesn't support inner class flags yet + var flags = (ACC_PROTECTED | ici.flagsMask()) & ~(ACC_PRIVATE | ACC_PUBLIC); + System.out.println("visitInnerClass: name = " + ici.innerClass().asInternalName() + + ", outerName = " + ici.outerClass().map(ClassEntry::asInternalName).orElse("null") + + ", innerName = " + ici.innerName().map(Utf8Entry::stringValue).orElse("null") + + ", access original = 0x" + Integer.toHexString(ici.flagsMask()) + + ", access modified to 0x" + Integer.toHexString(flags)); + return InnerClassInfo.of(ici.innerClass(), ici.outerClass(), ici.innerName(), flags); + }).toList())); + } else { + cb.accept(ce); + } + }; int errors = 0; errors += tryModifiedInvocation(makeProtectedNop); @@ -89,12 +78,11 @@ public class Test { } } - private static int tryModifiedInvocation(BogoLoader.VisitorMaker makeProtected) - throws Throwable, ClassNotFoundException { - HashMap replace - = new HashMap(); + private static int tryModifiedInvocation(ClassTransform makeProtected) + throws Throwable { + var replace = new HashMap(); replace.put("anotherpkg.MethodSupplierOuter$MethodSupplier", makeProtected); - HashSet in_bogus = new HashSet(); + var in_bogus = new HashSet(); in_bogus.add("MethodInvoker"); in_bogus.add("MyFunctionalInterface"); in_bogus.add("anotherpkg.MethodSupplierOuter"); // seems to be never loaded diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java b/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java index b3b1651fa59..ce4f4f75906 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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,9 +23,10 @@ /* * @test - * @modules java.base/jdk.internal.org.objectweb.asm - * jdk.compiler + * @modules jdk.compiler * @library /test/lib + * @enablePreview + * @comment Change enablePreview with the flag in setup's compileSources * @compile BadClassFile.jcod * BadClassFile2.jcod * BadClassFileVersion.jcod @@ -36,11 +37,9 @@ import java.io.File; import java.io.IOException; +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; import java.lang.invoke.MethodHandles.Lookup; - -import static java.lang.invoke.MethodHandles.lookup; -import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; - import java.lang.reflect.Array; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; @@ -51,8 +50,6 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Stream; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Type; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.Utils; @@ -60,7 +57,11 @@ import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import static jdk.internal.org.objectweb.asm.Opcodes.*; +import static java.lang.classfile.ClassFile.*; +import static java.lang.constant.ConstantDescs.CD_Enum; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.invoke.MethodHandles.lookup; +import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; import static org.testng.Assert.*; interface HiddenTest { @@ -77,7 +78,7 @@ public class BasicTest { @BeforeTest static void setup() throws IOException { - compileSources(SRC_DIR, CLASSES_DIR); + compileSources(SRC_DIR, CLASSES_DIR, "--enable-preview", "--release", "23"); hiddenClassBytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenClass.class")); // compile with --release 10 with no NestHost and NestMembers attribute @@ -264,8 +265,8 @@ public class BasicTest { */ @Test(dataProvider = "emptyClasses") public void emptyHiddenClass(String name, int accessFlags) throws Exception { - byte[] bytes = (accessFlags == ACC_ENUM) ? classBytes(name, Enum.class, accessFlags) - : classBytes(name, accessFlags); + byte[] bytes = (accessFlags == ACC_ENUM) ? classBytes(name, CD_Enum, accessFlags) + : classBytes(name, accessFlags); Class hc = lookup().defineHiddenClass(bytes, false).lookupClass(); switch (accessFlags) { case ACC_SYNTHETIC: @@ -514,14 +515,13 @@ public class BasicTest { } private static byte[] classBytes(String classname, int accessFlags) { - return classBytes(classname, Object.class, accessFlags); + return classBytes(classname, CD_Object, accessFlags); } - private static byte[] classBytes(String classname, Class supertType, int accessFlags) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); - cw.visit(V14, ACC_PUBLIC|accessFlags, classname, null, Type.getInternalName(supertType), null); - cw.visitEnd(); - - return cw.toByteArray(); + private static byte[] classBytes(String classname, ClassDesc superType, int accessFlags) { + return ClassFile.of().build(ClassDesc.ofInternalName(classname), clb -> clb + .withVersion(JAVA_14_VERSION, 0) + .withFlags(accessFlags | ACC_PUBLIC) + .withSuperclass(superType)); } } diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/HiddenNestmateTest.java b/test/jdk/java/lang/invoke/defineHiddenClass/HiddenNestmateTest.java index 79668a1963f..9043ce0fd85 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/HiddenNestmateTest.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/HiddenNestmateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -24,28 +24,35 @@ /* * @test * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @build HiddenNestmateTest * @run testng/othervm HiddenNestmateTest */ +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.invoke.*; import java.lang.invoke.MethodHandles.Lookup; +import java.lang.reflect.AccessFlag; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.stream.Stream; import java.util.Arrays; -import jdk.internal.org.objectweb.asm.*; import org.testng.annotations.Test; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; import static java.lang.invoke.MethodHandles.Lookup.*; -import static jdk.internal.org.objectweb.asm.Opcodes.*; import static org.testng.Assert.*; public class HiddenNestmateTest { + private static final ClassDesc CD_HiddenNestmateTest = HiddenNestmateTest.class.describeConstable().orElseThrow(); private static final byte[] bytes = classBytes("HiddenInjected"); private static void assertNestmate(Lookup lookup) { @@ -165,34 +172,20 @@ public class HiddenNestmateTest { } private static byte[] classBytes(String classname) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); - MethodVisitor mv; - - cw.visit(V12, ACC_FINAL, classname, null, "java/lang/Object", null); - - { - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - } - { - // access a private member of the nest host class - mv = cw.visitMethod(ACC_PUBLIC, "test", "(LHiddenNestmateTest;)I", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, "HiddenNestmateTest", "privMethod", "()I"); - mv.visitInsn(IRETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - } - cw.visitEnd(); - - return cw.toByteArray(); + return ClassFile.of().build(ClassDesc.ofInternalName(classname), clb -> { + clb.withSuperclass(CD_Object); + clb.withFlags(AccessFlag.FINAL); + clb.withMethodBody(INIT_NAME, MTD_void, PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(CD_Object, INIT_NAME, MTD_void); + cob.return_(); + }); + clb.withMethodBody("test", MethodTypeDesc.of(CD_int, CD_HiddenNestmateTest), PUBLIC, cob -> { + cob.aload(1); + cob.invokevirtual(CD_HiddenNestmateTest, "privMethod", MethodTypeDesc.of(CD_int)); + cob.ireturn(); + }); + }); } private int privMethod() { return 1234; } diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.java b/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.java index fb458bb309c..90fa01ca2c9 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/PreviewHiddenClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -24,22 +24,24 @@ /* * @test * @bug 8245432 - * @modules java.base/jdk.internal.org.objectweb.asm - * jdk.compiler + * @modules jdk.compiler * @library /test/lib * @build jdk.test.lib.Utils * jdk.test.lib.compiler.CompilerUtils * @run testng PreviewHiddenClass * @summary verify UnsupportedClassVersionError thrown when defining a hidden class * with preview minor version but --enable-preview is not set + * @comment This test itself cannot enablePreview, or hidden class definition + * will pass */ +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; import java.lang.invoke.MethodHandles; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import jdk.internal.org.objectweb.asm.ClassReader; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.Utils; @@ -62,9 +64,9 @@ public class PreviewHiddenClass { } byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenInterface.class")); - ClassReader reader = new ClassReader(bytes); - int minor = reader.readUnsignedShort(4); - assertTrue(minor == 65535); + var dis = new DataInputStream(new ByteArrayInputStream(bytes)); + dis.skipBytes(4); // 0xCAFEBABE + assertEquals(dis.readUnsignedShort(), 65535); // Minor version MethodHandles.lookup().defineHiddenClass(bytes, false); } } diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java b/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java index adcbd382902..656da048db9 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -25,19 +25,28 @@ * @test * @bug 8266925 * @summary hidden class members can't be statically invocable - * @modules java.base/jdk.internal.misc java.base/jdk.internal.org.objectweb.asm + * @modules java.base/jdk.internal.misc + * @enablePreview * @build java.base/* * @run testng StaticInvocableTest */ +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; import java.lang.invoke.LookupHelper; -import jdk.internal.org.objectweb.asm.*; +import java.lang.reflect.AccessFlag; import org.testng.annotations.Test; -import static jdk.internal.org.objectweb.asm.Opcodes.*; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; public class StaticInvocableTest { public static void main(String[] args) throws Throwable { @@ -106,28 +115,19 @@ public class StaticInvocableTest { * } */ public static byte[] dumpClass(String pkg) { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - - cw.visit(52, ACC_SUPER | ACC_PUBLIC, pkg+"/MyClass", null, "java/lang/Object", null); - { - mv = cw.visitMethod(0, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "get", "(I)Ljava/lang/Object;", null, null); - mv.visitCode(); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(ClassDesc.of(pkg.replace('/', '.'), "MyClass"), clb -> { + clb.withSuperclass(CD_Object); + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); + clb.withMethodBody(INIT_NAME, MTD_void, 0, cob -> { + cob.aload(0); + cob.invokespecial(CD_Object, INIT_NAME, MTD_void); + cob.return_(); + }); + clb.withMethodBody("get", MethodTypeDesc.of(CD_Object, CD_int), + ACC_PUBLIC | ACC_STATIC, cob -> { + cob.aconst_null(); + cob.areturn(); + }); + }); } } diff --git a/test/jdk/java/lang/invoke/lambda/LambdaAsm.java b/test/jdk/java/lang/invoke/lambda/LambdaAsm.java index f0d79988783..ebca93d639a 100644 --- a/test/jdk/java/lang/invoke/lambda/LambdaAsm.java +++ b/test/jdk/java/lang/invoke/lambda/LambdaAsm.java @@ -25,35 +25,35 @@ * @test * @bug 8027232 * @library /test/lib/ - * @modules java.base/jdk.internal.org.objectweb.asm - * jdk.jdeps/com.sun.tools.classfile - * jdk.zipfs + * @modules jdk.zipfs + * @enablePreview * @compile LambdaAsm.java * @run main/othervm LambdaAsm - * @summary ensures that j.l.i.InvokerByteCodeGenerator and ASM visitMethodInsn - * generate bytecodes with correct constant pool references + * @summary ensures that j.l.i.InvokerByteCodeGenerator and Class-File API + * generate bytecodes with correct constant pool references */ -import com.sun.tools.classfile.Attribute; -import com.sun.tools.classfile.ClassFile; -import com.sun.tools.classfile.Code_attribute; -import com.sun.tools.classfile.ConstantPool; -import com.sun.tools.classfile.ConstantPool.CPInfo; -import com.sun.tools.classfile.Instruction; -import com.sun.tools.classfile.Method; -import java.io.ByteArrayInputStream; import java.io.IOException; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.classfile.Opcode; +import java.lang.classfile.attribute.CodeAttribute; +import java.lang.classfile.constantpool.ConstantPool; +import java.lang.classfile.constantpool.MethodRefEntry; +import java.lang.classfile.instruction.InvokeInstruction; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.nio.charset.Charset; import java.nio.file.Files; import java.util.ArrayList; import java.nio.file.DirectoryStream; import java.nio.file.Path; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.process.OutputAnalyzer; +import static java.lang.constant.ConstantDescs.*; +import static java.lang.classfile.ClassFile.*; import static java.nio.file.Files.*; -import static jdk.internal.org.objectweb.asm.Opcodes.*; import static jdk.test.lib.process.ProcessTools.*; public class LambdaAsm { @@ -99,16 +99,14 @@ public class LambdaAsm { } static void checkMethod(String cname, String mname, ConstantPool cp, - Code_attribute code) throws ConstantPool.InvalidIndex { - for (Instruction i : code.getInstructions()) { - String iname = i.getMnemonic(); - if ("invokespecial".equals(iname) - || "invokestatic".equals(iname)) { - int idx = i.getByte(2); + CodeAttribute code) throws IllegalArgumentException { + for (var inst : code.elements()) { + if (inst instanceof InvokeInstruction inv && (inv.opcode() == Opcode.INVOKESPECIAL + || inv.opcode() == Opcode.INVOKEINTERFACE)) { + var ref = inv.method(); System.out.println("Verifying " + cname + ":" + mname + - " instruction:" + iname + " index @" + idx); - CPInfo cpinfo = cp.get(idx); - if (cpinfo instanceof ConstantPool.CONSTANT_Methodref_info) { + " instruction:" + inv.opcode() + " index @" + ref.index()); + if (ref instanceof MethodRefEntry) { throw new RuntimeException("unexpected CP type expected " + "InterfaceMethodRef, got MethodRef, " + cname + ", " + mname); @@ -117,21 +115,20 @@ public class LambdaAsm { } } - static int checkMethod(ClassFile cf, String mthd) throws Exception { - if (cf.major_version < 52) { + static int checkMethod(ClassModel cf, String mthd) throws Exception { + if (cf.majorVersion() < 52) { throw new RuntimeException("unexpected class file version, in " - + cf.getName() + "expected 52, got " + cf.major_version); + + cf.thisClass().asInternalName() + "expected 52, got " + + cf.majorVersion()); } int count = 0; - for (Method m : cf.methods) { - String mname = m.getName(cf.constant_pool); + for (var m : cf.methods()) { + String mname = m.methodName().stringValue(); if (mname.equals(mthd)) { - for (Attribute a : m.attributes) { - if ("Code".equals(a.getName(cf.constant_pool))) { - count++; - checkMethod(cf.getName(), mname, cf.constant_pool, - (Code_attribute) a); - } + for (var a : m.findAttributes(Attributes.CODE)) { + count++; + checkMethod(cf.thisClass().asInternalName(), mname, + cf.constantPool(), a); } } } @@ -146,9 +143,9 @@ public class LambdaAsm { "A$I$$Lambda.*.class")) { for (Path p : ds) { System.out.println(p.toFile()); - ClassFile cf = ClassFile.read(p.toFile()); + ClassModel cm = ClassFile.of().parse(p); // Check those methods implementing Supplier.get - mcount += checkMethod(cf, "get"); + mcount += checkMethod(cm, "get"); count++; } } @@ -163,23 +160,21 @@ public class LambdaAsm { } static void verifyASM() throws Exception { - ClassWriter cw = new ClassWriter(0); - cw.visit(V1_8, ACC_PUBLIC, "X", null, "java/lang/Object", null); - MethodVisitor mv = cw.visitMethod(ACC_STATIC, "foo", - "()V", null, null); - mv.visitMaxs(2, 1); - mv.visitMethodInsn(INVOKESTATIC, - "java/util/function/Function.class", - "identity", "()Ljava/util/function/Function;", true); - mv.visitInsn(RETURN); - cw.visitEnd(); - byte[] carray = cw.toByteArray(); + var functionDesc = ClassDesc.ofInternalName("java/util/function/Function"); + byte[] carray = ClassFile.of().build(ClassDesc.of("X"), clb -> clb + .withVersion(JAVA_8_VERSION, 0) + .withFlags(ACC_PUBLIC) + .withSuperclass(CD_Object) + .withMethodBody("foo", MTD_void, ACC_STATIC, cob -> cob + .invokestatic(functionDesc, "identity", MethodTypeDesc.of(functionDesc), true) + ) + ); // for debugging // write((new File("X.class")).toPath(), carray, CREATE, TRUNCATE_EXISTING); // verify using javap/classfile reader - ClassFile cf = ClassFile.read(new ByteArrayInputStream(carray)); - int mcount = checkMethod(cf, "foo"); + ClassModel cm = ClassFile.of().parse(carray); + int mcount = checkMethod(cm, "foo"); if (mcount < 1) { throw new RuntimeException("unexpected method count, expected 1" + "but got " + mcount); diff --git a/test/jdk/java/lang/invoke/lambda/LambdaStackTrace.java b/test/jdk/java/lang/invoke/lambda/LambdaStackTrace.java index 6ae63e4b7d9..0aa6d542588 100644 --- a/test/jdk/java/lang/invoke/lambda/LambdaStackTrace.java +++ b/test/jdk/java/lang/invoke/lambda/LambdaStackTrace.java @@ -25,17 +25,19 @@ * @test * @bug 8025636 * @library /test/lib/ - * @modules java.base/jdk.internal.org.objectweb.asm - * jdk.compiler + * @modules jdk.compiler + * @enablePreview * @compile LambdaStackTrace.java * @run main LambdaStackTrace * @summary Synthetic frames should be hidden in exceptions */ -import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.test.lib.compiler.CompilerUtils; import java.io.IOException; +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.charset.Charset; @@ -43,10 +45,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT; -import static jdk.internal.org.objectweb.asm.Opcodes.ACC_INTERFACE; -import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; -import static jdk.internal.org.objectweb.asm.Opcodes.V1_7; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_String; +import static java.lang.classfile.ClassFile.*; + public class LambdaStackTrace { @@ -132,24 +134,27 @@ public class LambdaStackTrace { // interface Maker { // Object make(); // } - ClassWriter cw = new ClassWriter(0); - cw.visit(V1_7, ACC_INTERFACE | ACC_ABSTRACT, "Maker", null, "java/lang/Object", null); - cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "make", - "()Ljava/lang/Object;", null, null); - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(ClassDesc.of("Maker"), clb -> clb + .withVersion(JAVA_7_VERSION, 0) + .withFlags(ACC_INTERFACE | ACC_ABSTRACT) + .withSuperclass(CD_Object) + .withMethod("make", MethodTypeDesc.of(CD_Object), + ACC_PUBLIC | ACC_ABSTRACT, mb -> {}) + ); } private static byte[] generateStringMaker() { // interface StringMaker extends Maker { // String make(); // } - ClassWriter cw = new ClassWriter(0); - cw.visit(V1_7, ACC_INTERFACE | ACC_ABSTRACT, "StringMaker", null, "java/lang/Object", new String[]{"Maker"}); - cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "make", - "()Ljava/lang/String;", null, null); - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(ClassDesc.of("StringMaker"), clb -> clb + .withVersion(JAVA_7_VERSION, 0) + .withFlags(ACC_INTERFACE | ACC_ABSTRACT) + .withSuperclass(CD_Object) + .withInterfaceSymbols(ClassDesc.of("Maker")) + .withMethod("make", MethodTypeDesc.of(CD_String), + ACC_PUBLIC | ACC_ABSTRACT, mb -> {}) + ); } diff --git a/test/jdk/java/lang/invoke/lookup/SpecialStatic.java b/test/jdk/java/lang/invoke/lookup/SpecialStatic.java index 4d85261732e..59db5d29788 100644 --- a/test/jdk/java/lang/invoke/lookup/SpecialStatic.java +++ b/test/jdk/java/lang/invoke/lookup/SpecialStatic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -24,18 +24,27 @@ /* @test * @bug 8032400 * @summary JSR292: invokeSpecial: InternalError attempting to lookup a method - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @compile -XDignore.symbol.file SpecialStatic.java * @run testng test.java.lang.invoke.lookup.SpecialStatic */ package test.java.lang.invoke.lookup; +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodHandleDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import jdk.internal.org.objectweb.asm.*; +import java.lang.reflect.AccessFlag; + import org.testng.annotations.*; -import static jdk.internal.org.objectweb.asm.Opcodes.*; + +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.*; +import static java.lang.constant.DirectMethodHandleDesc.Kind.SPECIAL; import static org.testng.Assert.*; /** @@ -72,6 +81,12 @@ public class SpecialStatic { private static ClassLoader cl = new CustomClassLoader(); private static Class t1, t3; + private static final MethodTypeDesc MTD_int = MethodTypeDesc.of(CD_int); + private static final MethodTypeDesc MTD_Lookup = MethodTypeDesc.of(CD_MethodHandles_Lookup); + private static final String METHOD_NAME = "m"; + private static final ClassDesc CD_T1 = ClassDesc.of("T1"); + private static final ClassDesc CD_T2 = ClassDesc.of("T2"); + private static final ClassDesc CD_T3 = ClassDesc.of("T3"); static { try { t1 = cl.loadClass("T1"); @@ -103,93 +118,60 @@ public class SpecialStatic { } public static byte[] dumpT1() { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - - cw.visit(52, ACC_PUBLIC + ACC_SUPER, "T1", null, "java/lang/Object", null); - - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - - mv = cw.visitMethod(ACC_PUBLIC, "m", "()I", null, null); - mv.visitCode(); - mv.visitIntInsn(BIPUSH, 1); - mv.visitInsn(IRETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(CD_T1, clb -> { + clb.withSuperclass(CD_Object); + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); + clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(CD_Object, INIT_NAME, MTD_void); + cob.return_(); + }); + clb.withMethodBody(METHOD_NAME, MTD_int, ACC_PUBLIC, cob -> { + cob.bipush(1); + cob.ireturn(); + }); + }); } public static byte[] dumpT2() { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - - cw.visit(52, ACC_PUBLIC + ACC_SUPER, "T2", null, "T1", null); - - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "T1", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - - mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m", "()I", null, null); - mv.visitCode(); - mv.visitIntInsn(BIPUSH, 2); - mv.visitInsn(IRETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(CD_T2, clb -> { + clb.withSuperclass(CD_T1); + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); + clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(CD_T1, INIT_NAME, MTD_void); + cob.return_(); + }); + clb.withMethodBody(METHOD_NAME, MTD_int, ACC_PUBLIC | ACC_STATIC, cob -> { + cob.bipush(2); + cob.ireturn(); + }); + }); } public static byte[] dumpT3() { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - - cw.visit(52, ACC_PUBLIC + ACC_SUPER, "T3", null, "T2", null); - - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "T2", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - - mv = cw.visitMethod(ACC_PUBLIC, "m", "()I", null, null); - mv.visitCode(); - mv.visitIntInsn(BIPUSH, 3); - mv.visitInsn(IRETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - - // getMethodHandle - mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "getMethodHandle", "()Ljava/lang/invoke/MethodHandle;", null, null); - mv.visitCode(); - mv.visitLdcInsn(new Handle(H_INVOKESPECIAL, "T1", "m", "()I")); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 0); - mv.visitEnd(); - - // getLookup - mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "getLookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", null, null); - mv.visitCode(); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 0); - mv.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(CD_T3, clb -> { + clb.withSuperclass(CD_T2); + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); + clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(CD_T2, INIT_NAME, MTD_void); + cob.return_(); + }); + clb.withMethodBody(METHOD_NAME, MTD_int, ACC_PUBLIC, cob -> { + cob.bipush(3); + cob.ireturn(); + }); + clb.withMethodBody("getMethodHandle", MethodTypeDesc.of(CD_MethodHandle), + ACC_PUBLIC | ACC_STATIC, cob -> { + cob.constantInstruction(MethodHandleDesc.ofMethod(SPECIAL, CD_T1, METHOD_NAME, MTD_int)); + cob.areturn(); + }); + clb.withMethodBody("getLookup", MTD_Lookup, + ACC_PUBLIC | ACC_STATIC, cob -> { + cob.invokestatic(CD_MethodHandles, "lookup", MTD_Lookup); + cob.areturn(); + }); + }); } } diff --git a/test/jdk/java/lang/reflect/Method/invoke/TestPrivateInterfaceMethodReflect.java b/test/jdk/java/lang/reflect/Method/invoke/TestPrivateInterfaceMethodReflect.java index e386d463049..17f9c6665c1 100644 --- a/test/jdk/java/lang/reflect/Method/invoke/TestPrivateInterfaceMethodReflect.java +++ b/test/jdk/java/lang/reflect/Method/invoke/TestPrivateInterfaceMethodReflect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -26,15 +26,21 @@ * @bug 8026213 * @summary Reflection support for private methods in interfaces * @author Robert Field - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @run main TestPrivateInterfaceMethodReflect */ +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.*; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; +import static java.lang.classfile.ClassFile.ACC_PRIVATE; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; public class TestPrivateInterfaceMethodReflect { @@ -42,10 +48,10 @@ public class TestPrivateInterfaceMethodReflect { static final String CLASS_NAME = "PrivateInterfaceMethodReflectTest_Class"; static final int EXPECTED = 1234; - static class TestClassLoader extends ClassLoader implements Opcodes { + static class TestClassLoader extends ClassLoader { @Override - public Class findClass(String name) throws ClassNotFoundException { + public Class findClass(String name) throws ClassNotFoundException { byte[] b; try { b = loadClassData(name); @@ -56,39 +62,28 @@ public class TestPrivateInterfaceMethodReflect { return defineClass(name, b, 0, b.length); } - private byte[] loadClassData(String name) throws Exception { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - switch (name) { - case INTERFACE_NAME: - cw.visit(V1_8, ACC_ABSTRACT | ACC_INTERFACE | ACC_PUBLIC, INTERFACE_NAME, null, "java/lang/Object", null); - { - mv = cw.visitMethod(ACC_PRIVATE, "privInstance", "()I", null, null); - mv.visitCode(); - mv.visitLdcInsn(EXPECTED); - mv.visitInsn(IRETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - break; - case CLASS_NAME: - cw.visit(52, ACC_SUPER | ACC_PUBLIC, CLASS_NAME, null, "java/lang/Object", new String[]{INTERFACE_NAME}); - { - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - break; - default: - break; - } - cw.visitEnd(); - - return cw.toByteArray(); + private byte[] loadClassData(String name) { + return switch (name) { + case INTERFACE_NAME -> ClassFile.of().build(ClassDesc.ofInternalName(INTERFACE_NAME), clb -> { + clb.withFlags(AccessFlag.ABSTRACT, AccessFlag.INTERFACE, AccessFlag.PUBLIC); + clb.withSuperclass(CD_Object); + clb.withMethodBody("privInstance", MethodTypeDesc.of(CD_int), ACC_PRIVATE, cob -> { + cob.constantInstruction(EXPECTED); + cob.ireturn(); + }); + }); + case CLASS_NAME -> ClassFile.of().build(ClassDesc.of(CLASS_NAME), clb -> { + clb.withFlags(AccessFlag.PUBLIC); + clb.withSuperclass(CD_Object); + clb.withInterfaceSymbols(ClassDesc.ofInternalName(INTERFACE_NAME)); + clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { + cob.aload(0); + cob.invokespecial(CD_Object, INIT_NAME, MTD_void); + cob.return_(); + }); + }); + default -> throw new IllegalArgumentException(); + }; } } @@ -96,7 +91,7 @@ public class TestPrivateInterfaceMethodReflect { TestClassLoader tcl = new TestClassLoader(); Class itf = tcl.loadClass(INTERFACE_NAME); Class k = tcl.loadClass(CLASS_NAME); - Object inst = k.newInstance(); + Object inst = k.getDeclaredConstructor().newInstance(); Method[] meths = itf.getDeclaredMethods(); if (meths.length != 1) { throw new Exception("Expected one method in " + INTERFACE_NAME + " instead " + meths.length); diff --git a/test/jdk/java/lang/reflect/records/IsRecordTest.java b/test/jdk/java/lang/reflect/records/IsRecordTest.java index 12893c2e996..fcac5a9b40c 100644 --- a/test/jdk/java/lang/reflect/records/IsRecordTest.java +++ b/test/jdk/java/lang/reflect/records/IsRecordTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -25,23 +25,27 @@ * @test * @bug 8255560 * @summary Class::isRecord should check that the current class is final and not abstract - * @modules java.base/jdk.internal.org.objectweb.asm + * @enablePreview * @library /test/lib * @run testng/othervm IsRecordTest * @run testng/othervm/java.security.policy=allPermissions.policy IsRecordTest */ -import java.io.IOException; -import java.io.UncheckedIOException; +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.lang.reflect.AccessFlag; import java.util.List; import java.util.Map; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Opcodes; + +import java.lang.classfile.attribute.RecordAttribute; +import java.lang.classfile.attribute.RecordComponentInfo; import jdk.test.lib.ByteCodeLoader; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static java.lang.System.out; -import static jdk.internal.org.objectweb.asm.ClassWriter.*; +import static java.lang.classfile.ClassFile.ACC_ABSTRACT; +import static java.lang.classfile.ClassFile.ACC_FINAL; +import static java.lang.constant.ConstantDescs.CD_int; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; @@ -82,9 +86,9 @@ public class IsRecordTest { out.println("\n--- testDirectSubClass isFinal=%s, isAbstract=%s, extendsJLR=%s, withRecordAttr=%s, expectIsRecord=%s ---" .formatted(isFinal, isAbstract, extendsJLR, withRecordAttr, expectIsRecord)); - List rc = null; + List rc = null; if (withRecordAttr) - rc = List.of(new RecordComponentEntry("x", "I")); + rc = List.of(RecordComponentInfo.of("x", CD_int)); String superName = extendsJLR ? "java/lang/Record" : "java/lang/Object"; var classBytes = generateClassBytes("C", isFinal, isAbstract, superName, rc); Class cls = ByteCodeLoader.load("C", classBytes); @@ -109,9 +113,9 @@ public class IsRecordTest { out.println("\n--- testIndirectSubClass isFinal=%s, isAbstract=%s withRecordAttr=%s ---" .formatted(isFinal, isAbstract, withRecordAttr)); - List rc = null; + List rc = null; if (withRecordAttr) - rc = List.of(new RecordComponentEntry("x", "I")); + rc = List.of(RecordComponentInfo.of("x", CD_int)); var supFooClassBytes = generateClassBytes("SupFoo", false, isAbstract, "java/lang/Record", rc); var subFooClassBytes = generateClassBytes("SubFoo", isFinal, isAbstract, "SupFoo", rc); var allClassBytes = Map.of("SupFoo", supFooClassBytes, @@ -161,29 +165,18 @@ public class IsRecordTest { boolean isFinal, boolean isAbstract, String superName, - List components) { - ClassWriter cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES); - - int access = 0; - if (isFinal) - access = access | Opcodes.ACC_FINAL; - if (isAbstract) - access = access | Opcodes.ACC_ABSTRACT; - - cw.visit(Opcodes.V16, - access, - className, - null, - superName, - null); - - if (components != null) - components.forEach(rc -> cw.visitRecordComponent(rc.name(), rc.descriptor(), null)); - - cw.visitEnd(); - return cw.toByteArray(); + List components) { + return ClassFile.of().build(ClassDesc.ofInternalName(className), clb -> { + int access = 0; + if (isFinal) + access = access | ACC_FINAL; + if (isAbstract) + access = access | ACC_ABSTRACT; + clb.withFlags(access); + clb.withSuperclass(ClassDesc.ofInternalName(superName)); + if (components != null) + clb.accept(RecordAttribute.of(components)); + }); } - record RecordComponentEntry (String name, String descriptor) { } - } diff --git a/test/jdk/java/util/ServiceLoader/BadProvidersTest.java b/test/jdk/java/util/ServiceLoader/BadProvidersTest.java index 58613c7b5e3..7a42854cb9e 100644 --- a/test/jdk/java/util/ServiceLoader/BadProvidersTest.java +++ b/test/jdk/java/util/ServiceLoader/BadProvidersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -24,16 +24,20 @@ /** * @test * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm - * jdk.compiler + * @modules jdk.compiler + * @enablePreview * @build jdk.test.lib.compiler.CompilerUtils * @run testng/othervm BadProvidersTest * @summary Basic test of ServiceLoader with bad provider and bad provider * factories deployed on the module path */ +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.module.Configuration; import java.lang.module.ModuleFinder; +import java.lang.reflect.AccessFlag; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -45,14 +49,17 @@ import java.util.ServiceLoader.Provider; import java.util.Set; import java.util.stream.Collectors; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import static jdk.internal.org.objectweb.asm.Opcodes.*; - import jdk.test.lib.compiler.CompilerUtils; import org.testng.annotations.Test; import org.testng.annotations.DataProvider; + +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; + import static org.testng.Assert.*; /** @@ -207,55 +214,36 @@ public class BadProvidersTest { public void testWithTwoFactoryMethods() throws Exception { Path mods = compileTest(TEST1_MODULE); - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS - + ClassWriter.COMPUTE_FRAMES); - cw.visit(V9, - ACC_PUBLIC + ACC_SUPER, - "p/ProviderFactory", - null, - "java/lang/Object", - null); + var bytes = ClassFile.of().build(ClassDesc.of("p", "ProviderFactory"), clb -> { + clb.withSuperclass(CD_Object); + clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER); - // public static p.Service provider() - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, - "provider", - "()Lp/Service;", - null, - null); - mv.visitTypeInsn(NEW, "p/ProviderFactory$1"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, - "p/ProviderFactory$1", - "", "()V", - false); - mv.visitInsn(ARETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); + var providerFactory$1 = ClassDesc.of("p", "ProviderFactory$1"); - // public static p.ProviderFactory$1 provider() - mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, - "provider", - "()Lp/ProviderFactory$1;", - null, - null); - mv.visitTypeInsn(NEW, "p/ProviderFactory$1"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, - "p/ProviderFactory$1", - "", - "()V", - false); - mv.visitInsn(ARETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); + // public static p.Service provider() + clb.withMethodBody("provider", MethodTypeDesc.of(ClassDesc.of("p", "Service")), + ACC_PUBLIC | ACC_STATIC, cob -> { + cob.new_(providerFactory$1); + cob.dup(); + cob.invokespecial(providerFactory$1, INIT_NAME, MTD_void); + cob.areturn(); + }); - cw.visitEnd(); + // public static p.ProviderFactory$1 provider() + clb.withMethodBody("provider", MethodTypeDesc.of(providerFactory$1), + ACC_PUBLIC | ACC_STATIC, cob -> { + cob.new_(providerFactory$1); + cob.dup(); + cob.invokespecial(providerFactory$1, INIT_NAME, MTD_void); + cob.areturn(); + }); + }); // write the class bytes into the compiled module directory Path classFile = mods.resolve(TEST1_MODULE) .resolve("p") .resolve("ProviderFactory.class"); - Files.write(classFile, cw.toByteArray()); + Files.write(classFile, bytes); // load providers and instantiate each one loadProviders(mods, TEST1_MODULE).forEach(Provider::get);