8294977: Convert test/jdk/java tests from ASM library to Classfile API

Reviewed-by: asotona
This commit is contained in:
Chen Liang 2024-02-19 14:07:46 +00:00 committed by Jaikiran Pai
parent 82609b1ebc
commit f6d7e30b84
31 changed files with 1109 additions and 1476 deletions

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 * @summary InvalidClassException is thrown when the canonical constructor
* cannot be found during deserialization. * cannot be found during deserialization.
* @library /test/lib * @library /test/lib
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @run testng BadCanonicalCtrTest * @run testng BadCanonicalCtrTest
*/ */
@ -38,19 +38,22 @@ import java.io.InvalidClassException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass; import java.io.ObjectStreamClass;
import jdk.internal.org.objectweb.asm.ClassReader; import java.lang.classfile.ClassTransform;
import jdk.internal.org.objectweb.asm.ClassVisitor; import java.lang.classfile.ClassFile;
import jdk.internal.org.objectweb.asm.ClassWriter; import java.lang.classfile.MethodModel;
import jdk.internal.org.objectweb.asm.MethodVisitor; import java.lang.constant.MethodTypeDesc;
import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.compiler.InMemoryJavaCompiler;
import jdk.test.lib.ByteCodeLoader; import jdk.test.lib.ByteCodeLoader;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import static java.lang.System.out; import static java.lang.System.out;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static java.lang.classfile.ClassFile.ACC_PUBLIC;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_MAXS; import static java.lang.constant.ConstantDescs.CD_Object;
import static jdk.internal.org.objectweb.asm.Opcodes.*; 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.assertTrue;
import static org.testng.Assert.expectThrows; import static org.testng.Assert.expectThrows;
@ -203,33 +206,9 @@ public class BadCanonicalCtrTest {
* Assumes just a single, canonical, constructor. * Assumes just a single, canonical, constructor.
*/ */
static byte[] removeConstructor(byte[] classBytes) { static byte[] removeConstructor(byte[] classBytes) {
ClassReader reader = new ClassReader(classBytes); var cf = ClassFile.of();
ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES); return cf.transform(cf.parse(classBytes), ClassTransform.dropping(ce ->
reader.accept(new RemoveCanonicalCtrVisitor(writer), 0); ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)));
return writer.toByteArray();
}
/** Removes the <init> method. */
static class RemoveCanonicalCtrVisitor extends ClassVisitor {
static final String CTR_NAME = "<init>";
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);
}
}
} }
/** /**
@ -237,55 +216,15 @@ public class BadCanonicalCtrTest {
* Assumes just a single, canonical, constructor. * Assumes just a single, canonical, constructor.
*/ */
static byte[] modifyConstructor(byte[] classBytes) { static byte[] modifyConstructor(byte[] classBytes) {
ClassReader reader = new ClassReader(classBytes); var cf = ClassFile.of();
ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES); return cf.transform(cf.parse(classBytes), ClassTransform.dropping(ce ->
reader.accept(new ModifyCanonicalCtrVisitor(writer), 0); ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME))
return writer.toByteArray(); .andThen(ClassTransform.endHandler(clb -> clb.withMethodBody(INIT_NAME,
} MethodTypeDesc.of(CD_void, CD_Object), ACC_PUBLIC, cob -> {
cob.aload(0);
/** Replaces whatever <init> method it finds with <init>(Ljava/lang/Object;)V. */ cob.invokespecial(Record.class.describeConstable().orElseThrow(),
static class ModifyCanonicalCtrVisitor extends ClassVisitor { INIT_NAME, MTD_void);
ModifyCanonicalCtrVisitor(ClassVisitor cv) { cob.return_();
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("<init>")) { // 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, "<init>", "(Ljava/lang/Object;)V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Record", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
cv.visitEnd();
}
} }
} }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,7 @@
* @bug 8246774 * @bug 8246774
* @summary Basic tests for prohibited magic serialization methods * @summary Basic tests for prohibited magic serialization methods
* @library /test/lib * @library /test/lib
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @run testng ProhibitedMethods * @run testng ProhibitedMethods
*/ */
@ -41,23 +41,23 @@ import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass; import java.io.ObjectStreamClass;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.Serializable; 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.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.math.BigDecimal; 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.compiler.InMemoryJavaCompiler;
import jdk.test.lib.ByteCodeLoader; import jdk.test.lib.ByteCodeLoader;
import org.testng.Assert;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import static java.lang.System.out; import static java.lang.System.out;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static java.lang.classfile.ClassFile.ACC_PRIVATE;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_MAXS; import static java.lang.constant.ConstantDescs.CD_String;
import static jdk.internal.org.objectweb.asm.Opcodes.*; import static java.lang.constant.ConstantDescs.CD_void;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
import static org.testng.Assert.expectThrows; import static org.testng.Assert.expectThrows;
@ -219,103 +219,38 @@ public class ProhibitedMethods {
// -- machinery for augmenting record classes with prohibited serial methods -- // -- 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) { 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) { 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) { 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, static byte[] addMethod(byte[] classBytes,
Function<ClassVisitor,ClassVisitor> classVisitorCreator) { String name, MethodTypeDesc desc) {
ClassReader reader = new ClassReader(classBytes); var cf = ClassFile.of();
ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES); return cf.transform(cf.parse(classBytes), ClassTransform.endHandler(clb -> {
reader.accept(classVisitorCreator.apply(writer), 0); clb.withMethodBody(name, desc, ACC_PRIVATE, cob -> {
return writer.toByteArray(); cob.constantInstruction(name + " should not be invoked");
} cob.invokestatic(Assert.class.describeConstable().orElseThrow(), "fail",
MethodTypeDesc.of(CD_void, CD_String));
static abstract class AbstractVisitor extends ClassVisitor { cob.return_();
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();
}
} }
// -- infra sanity -- // -- infra sanity --

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,7 @@
* @bug 8246774 * @bug 8246774
* @summary Basic tests for prohibited magic serialPersistentFields * @summary Basic tests for prohibited magic serialPersistentFields
* @library /test/lib * @library /test/lib
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @run testng SerialPersistentFieldsTest * @run testng SerialPersistentFieldsTest
*/ */
@ -38,23 +38,34 @@ import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass; import java.io.ObjectStreamClass;
import java.io.ObjectStreamField; import java.io.ObjectStreamField;
import java.io.Serializable; 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.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.math.BigDecimal; 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.ByteCodeLoader;
import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.compiler.InMemoryJavaCompiler;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import static java.lang.System.out; import static java.lang.System.out;
import static jdk.internal.org.objectweb.asm.ClassWriter.*; import static java.lang.classfile.ClassFile.ACC_FINAL;
import static jdk.internal.org.objectweb.asm.Opcodes.*; 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.assertEquals;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
@ -218,105 +229,62 @@ public class SerialPersistentFieldsTest {
static byte[] addSerialPersistentFields(byte[] classBytes, static byte[] addSerialPersistentFields(byte[] classBytes,
ObjectStreamField[] spf) { ObjectStreamField[] spf) {
ClassReader reader = new ClassReader(classBytes); var cf = ClassFile.of();
ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES); var model = cf.parse(classBytes);
reader.accept(new SerialPersistentFieldsVisitor(writer, spf), 0); return cf.transform(model, new SerialPersistentFieldsVisitor(model.thisClass().asSymbol(), spf));
return writer.toByteArray();
} }
/** A visitor that adds a serialPersistentFields field, and assigns it in clinit. */ /** 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_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; final ObjectStreamField[] spf;
String className; final ClassDesc className;
SerialPersistentFieldsVisitor(ClassVisitor cv, ObjectStreamField[] spf) { SerialPersistentFieldsVisitor(ClassDesc className, ObjectStreamField[] spf) {
super(ASM8, cv); this.className = className;
this.spf = spf; this.spf = spf;
} }
@Override @Override
public void visit(final int version, public void accept(ClassBuilder builder, ClassElement element) {
final int access, if (element instanceof FieldModel fieldModel) {
final String name, var name = fieldModel.fieldName().stringValue();
final String signature, assert !name.equals(FIELD_NAME) : "Unexpected " + FIELD_NAME + " field";
final String superName, builder.accept(fieldModel);
final String[] interfaces) { } else {
this.className = name; builder.accept(element);
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();
} }
{ }
MethodVisitor mv = cv.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
mv.visitCode(); @Override
mv.visitIntInsn(BIPUSH, spf.length); public void atEnd(ClassBuilder builder) {
mv.visitTypeInsn(ANEWARRAY, "java/io/ObjectStreamField"); 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++) { for (int i = 0; i < spf.length; i++) {
ObjectStreamField osf = spf[i]; ObjectStreamField osf = spf[i];
mv.visitInsn(DUP); cob.dup();
mv.visitIntInsn(BIPUSH, i); cob.bipush(i);
mv.visitTypeInsn(NEW, "java/io/ObjectStreamField"); cob.new_(CD_ObjectStreamField);
mv.visitInsn(DUP); cob.dup();
mv.visitLdcInsn(osf.getName()); cob.constantInstruction(osf.getName());
if (osf.getType().isPrimitive()) { if (osf.isPrimitive()) {
mv.visitFieldInsn(GETSTATIC, getPrimitiveBoxClass(osf.getType()), "TYPE", "Ljava/lang/Class;"); cob.constantInstruction(DynamicConstantDesc.ofNamed(
ConstantDescs.BSM_PRIMITIVE_CLASS, String.valueOf(osf.getTypeCode()), CD_Class));
} else { } 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", "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V", false); cob.invokespecial(CD_ObjectStreamField, INIT_NAME, MethodTypeDesc.of(CD_void, CD_String, CD_Class));
mv.visitInsn(AASTORE); cob.aastore();
} }
mv.visitFieldInsn(PUTSTATIC, className, "serialPersistentFields", "[Ljava/io/ObjectStreamField;"); cob.putstatic(className, FIELD_NAME, FIELD_DESC);
mv.visitInsn(RETURN); cob.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);
}
} }
} }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,10 +24,24 @@
/* @test /* @test
* @bug 8057919 * @bug 8057919
* @summary Class.getSimpleName() should work for non-JLS compliant class names * @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 { public class GetSimpleNameTest {
static class NestedClass {} static class NestedClass {}
@ -121,88 +135,89 @@ public class GetSimpleNameTest {
} }
static class BytecodeGenerator { static class BytecodeGenerator {
final String innerName; final ClassDesc innerName;
final String outerName; final ClassDesc outerName;
final String simpleName; final String simpleName;
BytecodeGenerator(String innerName, String outerName, String simpleName) { BytecodeGenerator(String innerName, String outerName, String simpleName) {
this.innerName = intl(innerName); this.innerName = ClassDesc.of(innerName);
this.outerName = intl(outerName); this.outerName = ClassDesc.of(outerName);
this.simpleName = simpleName; this.simpleName = simpleName;
} }
static String intl(String name) { return name.replace('.', '/'); } static void makeDefaultCtor(ClassBuilder clb) {
clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cb -> {
static void makeDefaultCtor(ClassWriter cw) { cb.aload(0);
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); cb.invokespecial(CD_Object, INIT_NAME, MTD_void);
mv.visitCode(); cb.return_();
mv.visitVarInsn(ALOAD, 0); });
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
} }
void makeCtxk(ClassWriter cw, boolean isInner) { void makeCtxk(ClassBuilder clb, boolean isInner) {
if (isInner) { if (isInner) {
cw.visitOuterClass(outerName, "f", "()V"); clb.with(EnclosingMethodAttribute.of(outerName,
Optional.of("f"), Optional.of(MTD_void)));
} else { } else {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f", "()V", null, null); clb.withMethodBody("f", MTD_void, ACC_PUBLIC | ACC_STATIC,
mv.visitCode(); CodeBuilder::return_);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
} }
} }
byte[] getNestedClasses(boolean isInner) { byte[] getNestedClasses(boolean isInner) {
String name = (isInner ? innerName : outerName); var name = (isInner ? innerName : outerName);
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(name, clb -> {
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null); clb.withSuperclass(CD_Object);
clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
cw.visitInnerClass(innerName, outerName, simpleName, ACC_PUBLIC | ACC_STATIC); clb.with(InnerClassesAttribute.of(
InnerClassInfo.of(innerName,
makeDefaultCtor(cw); Optional.of(outerName),
cw.visitEnd(); Optional.of(simpleName))));
return cw.toByteArray(); makeDefaultCtor(clb);
});
} }
byte[] getInnerClasses(boolean isInner) { byte[] getInnerClasses(boolean isInner) {
String name = (isInner ? innerName : outerName); var name = (isInner ? innerName : outerName);
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(name, clb -> {
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null); clb.withSuperclass(CD_Object);
clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
cw.visitInnerClass(innerName, outerName, simpleName, ACC_PUBLIC); clb.with(InnerClassesAttribute.of(
InnerClassInfo.of(innerName,
makeDefaultCtor(cw); Optional.of(outerName),
cw.visitEnd(); Optional.of(simpleName),
return cw.toByteArray(); AccessFlag.PUBLIC)));
makeDefaultCtor(clb);
});
} }
byte[] getLocalClasses(boolean isInner) { byte[] getLocalClasses(boolean isInner) {
String name = (isInner ? innerName : outerName); var name = (isInner ? innerName : outerName);
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(name, clb -> {
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null); clb.withSuperclass(CD_Object);
clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
cw.visitInnerClass(innerName, null, simpleName, ACC_PUBLIC | ACC_STATIC); clb.with(InnerClassesAttribute.of(
makeCtxk(cw, isInner); InnerClassInfo.of(innerName,
Optional.empty(),
makeDefaultCtor(cw); Optional.of(simpleName),
cw.visitEnd(); AccessFlag.PUBLIC, AccessFlag.STATIC)));
return cw.toByteArray(); makeDefaultCtor(clb);
makeCtxk(clb, isInner);
});
} }
byte[] getAnonymousClasses(boolean isInner) { byte[] getAnonymousClasses(boolean isInner) {
String name = (isInner ? innerName : outerName); var name = (isInner ? innerName : outerName);
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(name, clb -> {
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null); clb.withSuperclass(CD_Object);
clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
cw.visitInnerClass(innerName, null, null, ACC_PUBLIC | ACC_STATIC); clb.with(InnerClassesAttribute.of(
makeCtxk(cw, isInner); InnerClassInfo.of(innerName,
Optional.empty(),
makeDefaultCtor(cw); Optional.empty(),
cw.visitEnd(); AccessFlag.PUBLIC, AccessFlag.STATIC)));
return cw.toByteArray(); makeDefaultCtor(clb);
makeCtxk(clb, isInner);
});
} }
} }
} }

View file

@ -22,9 +22,15 @@
*/ */
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.annotation.Annotation; 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.Configuration;
import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder; import java.lang.module.ModuleFinder;
@ -36,13 +42,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; 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 jdk.test.lib.util.ModuleInfoWriter;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -51,9 +50,7 @@ import static org.testng.Assert.*;
/** /**
* @test * @test
* @enablePreview * @enablePreview
* @modules java.base/jdk.internal.org.objectweb.asm * @modules java.base/jdk.internal.module
* java.base/jdk.internal.org.objectweb.asm.commons
* java.base/jdk.internal.module
* @library /test/lib * @library /test/lib
* @build jdk.test.lib.util.ModuleInfoWriter * @build jdk.test.lib.util.ModuleInfoWriter
* @run testng AnnotationsTest * @run testng AnnotationsTest
@ -149,23 +146,39 @@ public class AnnotationsTest {
* Adds the Deprecated annotation to the given module-info class file. * Adds the Deprecated annotation to the given module-info class file.
*/ */
static byte[] addDeprecated(byte[] bytes, boolean forRemoval, String since) { static byte[] addDeprecated(byte[] bytes, boolean forRemoval, String since) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS var cf = ClassFile.of();
+ ClassWriter.COMPUTE_FRAMES); 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<java.lang.classfile.Annotation>(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); @Override
List<Attribute> attrs = new ArrayList<>(); public void atEnd(ClassBuilder builder) {
attrs.add(new ModuleTargetAttribute()); if (!rvaaFound) {
cr.accept(cv, attrs.toArray(new Attribute[0]), 0); builder.accept(RuntimeVisibleAnnotationsAttribute.of(List.of(createDeprecated())));
}
}
AnnotationVisitor annotationVisitor private java.lang.classfile.Annotation createDeprecated() {
= cv.visitAnnotation("Ljava/lang/Deprecated;", true); return java.lang.classfile.Annotation.of(
annotationVisitor.visit("forRemoval", forRemoval); Deprecated.class.describeConstable().orElseThrow(),
annotationVisitor.visit("since", since); AnnotationElement.of("forRemoval", AnnotationValue.ofBoolean(forRemoval)),
annotationVisitor.visitEnd(); AnnotationElement.of("since", AnnotationValue.ofString(since))
);
return cw.toByteArray(); }
});
} }
/** /**

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,18 +26,21 @@
* @bug 8228988 8266598 * @bug 8228988 8266598
* @summary An annotation-typed property of an annotation that is represented as an * @summary An annotation-typed property of an annotation that is represented as an
* incompatible property of another type should yield an AnnotationTypeMismatchException. * incompatible property of another type should yield an AnnotationTypeMismatchException.
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @run main AnnotationTypeMismatchTest * @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.AnnotationTypeMismatchException;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; 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 { public class AnnotationTypeMismatchTest {
@ -46,12 +49,15 @@ public class AnnotationTypeMismatchTest {
* @AnAnnotation(value = AnEnum.VALUE) // would now be: value = @Value * @AnAnnotation(value = AnEnum.VALUE) // would now be: value = @Value
* class Carrier { } * class Carrier { }
*/ */
ClassWriter writer = new ClassWriter(0); byte[] b = ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> {
writer.visit(Opcodes.V1_8, 0, "sample/Carrier", null, Type.getInternalName(Object.class), null); clb.withSuperclass(CD_Object);
AnnotationVisitor v = writer.visitAnnotation(Type.getDescriptor(AnAnnotation.class), true); clb.with(RuntimeVisibleAnnotationsAttribute.of(
v.visitEnum("value", Type.getDescriptor(AnEnum.class), "VALUE"); Annotation.of(
writer.visitEnd(); AnAnnotation.class.describeConstable().orElseThrow(),
byte[] b = writer.toByteArray(); AnnotationElement.of("value", AnnotationValue.of(AnEnum.VALUE))
)
));
});
ByteArrayClassLoader cl = new ByteArrayClassLoader(AnnotationTypeMismatchTest.class.getClassLoader()); ByteArrayClassLoader cl = new ByteArrayClassLoader(AnnotationTypeMismatchTest.class.getClassLoader());
cl.init(b); cl.init(b);
AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class); AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class);

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 * @summary Annotation property which is compiled as an array property but
* changed observed as a singular element should throw an * changed observed as a singular element should throw an
* AnnotationTypeMismatchException * AnnotationTypeMismatchException
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @run main ArityTypeMismatchTest * @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.AnnotationTypeMismatchException;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; 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 { public class ArityTypeMismatchTest {
@ -54,15 +57,15 @@ public class ArityTypeMismatchTest {
* *
* where @AnAnnotation expects a singular value. * where @AnAnnotation expects a singular value.
*/ */
ClassWriter writer = new ClassWriter(0); byte[] b = ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> {
writer.visit(Opcodes.V1_8, 0, "sample/Carrier", null, Type.getInternalName(Object.class), null); clb.withSuperclass(CD_Object);
AnnotationVisitor v = writer.visitAnnotation(Type.getDescriptor(AnAnnotation.class), true); clb.with(RuntimeVisibleAnnotationsAttribute.of(
AnnotationVisitor v2 = v.visitArray("value"); Annotation.of(
v2.visit(null, "v"); AnAnnotation.class.describeConstable().orElseThrow(),
v2.visitEnd(); AnnotationElement.of("value", AnnotationValue.of(new String[] {"v"}))
v.visitEnd(); )
writer.visitEnd(); ));
byte[] b = writer.toByteArray(); });
ByteArrayClassLoader cl = new ByteArrayClassLoader(ArityTypeMismatchTest.class.getClassLoader()); ByteArrayClassLoader cl = new ByteArrayClassLoader(ArityTypeMismatchTest.class.getClassLoader());
cl.init(b); cl.init(b);
AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class); AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class);

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,21 +26,27 @@
* @bug 8266766 * @bug 8266766
* @summary An array property of a type that is no longer of a type that is a legal member of an * @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. * annotation should throw an AnnotationTypeMismatchException.
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @run main ArrayTypeMismatchTest * @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.Annotation;
import java.lang.annotation.AnnotationTypeMismatchException; import java.lang.annotation.AnnotationTypeMismatchException;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; 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 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 class ArrayTypeMismatchTest {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
@ -67,8 +73,7 @@ public class ArrayTypeMismatchTest {
throw new IllegalStateException("Found value: " + value); throw new IllegalStateException("Found value: " + value);
} catch (InvocationTargetException ite) { } catch (InvocationTargetException ite) {
Throwable cause = ite.getCause(); Throwable cause = ite.getCause();
if (cause instanceof AnnotationTypeMismatchException) { if (cause instanceof AnnotationTypeMismatchException e) {
AnnotationTypeMismatchException e = ((AnnotationTypeMismatchException) cause);
if (!e.element().getName().equals("value")) { if (!e.element().getName().equals("value")) {
throw new IllegalStateException("Unexpected element: " + e.element()); throw new IllegalStateException("Unexpected element: " + e.element());
} else if (!e.foundType().equals("Array with component tag: @")) { } else if (!e.foundType().equals("Array with component tag: @")) {
@ -81,34 +86,35 @@ public class ArrayTypeMismatchTest {
} }
private static byte[] carrierType() { private static byte[] carrierType() {
ClassWriter writer = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> {
writer.visit(Opcodes.V1_8, 0, "sample/Carrier", null, Type.getInternalName(Object.class), null); clb.withSuperclass(CD_Object);
AnnotationVisitor v = writer.visitAnnotation("Lsample/Host;", true); var badAnnotationArray = AnnotationValue.ofArray(AnnotationValue.ofAnnotation(
AnnotationVisitor a = v.visitArray("value"); java.lang.classfile.Annotation.of(
a.visitAnnotation(null, Type.getDescriptor(NoAnnotation.class)).visitEnd(); NoAnnotation.class.describeConstable().orElseThrow()
a.visitEnd(); )));
v.visitEnd(); clb.with(RuntimeVisibleAnnotationsAttribute.of(
writer.visitEnd(); java.lang.classfile.Annotation.of(ClassDesc.of("sample", "Host"),
return writer.toByteArray(); AnnotationElement.of("value", badAnnotationArray)
)
));
});
} }
private static byte[] annotationType() { private static byte[] annotationType() {
ClassWriter writer = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of("sample", "Host"), clb -> {
writer.visit(Opcodes.V1_8, clb.withSuperclass(CD_Object);
Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE | Opcodes.ACC_ANNOTATION, clb.withInterfaceSymbols(Annotation.class.describeConstable().orElseThrow());
"sample/Host", clb.withFlags(AccessFlag.PUBLIC, AccessFlag.ABSTRACT, AccessFlag.INTERFACE,
null, AccessFlag.ANNOTATION);
Type.getInternalName(Object.class), clb.with(RuntimeVisibleAnnotationsAttribute.of(
new String[]{Type.getInternalName(Annotation.class)}); java.lang.classfile.Annotation.of(
AnnotationVisitor a = writer.visitAnnotation(Type.getDescriptor(Retention.class), true); Retention.class.describeConstable().orElseThrow(),
a.visitEnum("value", Type.getDescriptor(RetentionPolicy.class), RetentionPolicy.RUNTIME.name()); AnnotationElement.of("value", AnnotationValue.of(RetentionPolicy.RUNTIME))
writer.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT, )
"value", ));
Type.getMethodDescriptor(Type.getType(NoAnnotation[].class)), clb.withMethod("value", MethodTypeDesc.of(NoAnnotation[].class.describeConstable()
null, .orElseThrow()), ACC_PUBLIC | ACC_ABSTRACT, mb -> {});
null).visitEnd(); });
writer.visitEnd();
return writer.toByteArray();
} }
public interface NoAnnotation { } public interface NoAnnotation { }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,18 +26,21 @@
* @bug 8228988 8266598 * @bug 8228988 8266598
* @summary An enumeration-typed property of an annotation that is represented as an * @summary An enumeration-typed property of an annotation that is represented as an
* incompatible property of another type should yield an AnnotationTypeMismatchException. * incompatible property of another type should yield an AnnotationTypeMismatchException.
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @run main EnumTypeMismatchTest * @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.AnnotationTypeMismatchException;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; 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 { public class EnumTypeMismatchTest {
@ -46,12 +49,14 @@ public class EnumTypeMismatchTest {
* @AnAnnotation(value = @AnAnnotation) // would now be: value = AnEnum.VALUE * @AnAnnotation(value = @AnAnnotation) // would now be: value = AnEnum.VALUE
* class Carrier { } * class Carrier { }
*/ */
ClassWriter writer = new ClassWriter(0); ClassDesc anAnnotationDesc = AnAnnotation.class.describeConstable().orElseThrow();
writer.visit(Opcodes.V1_8, 0, "sample/Carrier", null, Type.getInternalName(Object.class), null); byte[] b = ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> {
AnnotationVisitor v = writer.visitAnnotation(Type.getDescriptor(AnAnnotation.class), true); clb.withSuperclass(CD_Object);
v.visitAnnotation("value", Type.getDescriptor(AnAnnotation.class)).visitEnd(); clb.with(RuntimeVisibleAnnotationsAttribute.of(
writer.visitEnd(); Annotation.of(anAnnotationDesc, AnnotationElement.of("value",
byte[] b = writer.toByteArray(); AnnotationValue.ofAnnotation(Annotation.of(anAnnotationDesc))))
));
});
ByteArrayClassLoader cl = new ByteArrayClassLoader(EnumTypeMismatchTest.class.getClassLoader()); ByteArrayClassLoader cl = new ByteArrayClassLoader(EnumTypeMismatchTest.class.getClassLoader());
cl.init(b); cl.init(b);
AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class); AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class);

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -39,8 +39,8 @@ import java.util.stream.Stream;
* @test * @test
* @bug 8158510 * @bug 8158510
* @summary Verify valid annotation * @summary Verify valid annotation
* @modules java.base/jdk.internal.org.objectweb.asm
* @modules java.base/sun.reflect.annotation * @modules java.base/sun.reflect.annotation
* @enablePreview
* @clean AnnotationWithVoidReturn AnnotationWithParameter * @clean AnnotationWithVoidReturn AnnotationWithParameter
* AnnotationWithExtraInterface AnnotationWithException * AnnotationWithExtraInterface AnnotationWithException
* AnnotationWithHashCode AnnotationWithDefaultMember * AnnotationWithHashCode AnnotationWithDefaultMember

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; 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 { 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 { public static void main(String... args) throws Exception {
classFileWriter("AnnotationWithVoidReturn.class", AnnotationWithVoidReturnDump.dump()); classFileWriter("AnnotationWithVoidReturn.class", AnnotationWithVoidReturnDump.dump());
@ -63,35 +84,19 @@ public class ClassFileGenerator {
*/ */
private static class AnnotationWithVoidReturnDump implements Opcodes { private static class AnnotationWithVoidReturnDump {
public static byte[] dump() throws Exception { public static byte[] dump() {
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of("AnnotationWithVoidReturn"), clb -> {
MethodVisitor mv; clb.withSuperclass(CD_Object);
AnnotationVisitor av0; clb.withInterfaceSymbols(CD_Annotation);
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, clb.with(RuntimeVisibleAnnotationsAttribute.of(
"AnnotationWithVoidReturn", null, Annotation.of(CD_Retention, AnnotationElement.of("value",
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
{ clb.withMethod("m", MTD_void, ACC_PUBLIC | ACC_ABSTRACT,
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
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();
} }
} }
@ -104,38 +109,19 @@ public class ClassFileGenerator {
*/ */
private static class AnnotationWithParameterDump implements Opcodes { private static class AnnotationWithParameterDump {
public static byte[] dump() throws Exception { public static byte[] dump() {
return ClassFile.of().build(ClassDesc.of("AnnotationWithParameter"), clb -> {
ClassWriter cw = new ClassWriter(0); clb.withSuperclass(CD_Object);
MethodVisitor mv; clb.withInterfaceSymbols(CD_Annotation);
AnnotationVisitor av0; clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
clb.with(RuntimeVisibleAnnotationsAttribute.of(
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, Annotation.of(CD_Retention, AnnotationElement.of("value",
"AnnotationWithParameter", null, AnnotationValue.of(RetentionPolicy.RUNTIME)))
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); ));
clb.withMethod("m", MethodTypeDesc.of(CD_int, CD_int), ACC_PUBLIC | ACC_ABSTRACT,
{ mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(-1))));
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();
} }
} }
@ -148,35 +134,19 @@ public class ClassFileGenerator {
*/ */
private static class AnnotationWithExtraInterfaceDump implements Opcodes { private static class AnnotationWithExtraInterfaceDump {
public static byte[] dump() throws Exception { public static byte[] dump() {
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of("AnnotationWithExtraInterface"), clb -> {
MethodVisitor mv; clb.withSuperclass(CD_Object);
AnnotationVisitor av0; clb.withInterfaceSymbols(CD_Annotation, Serializable.class.describeConstable().orElseThrow());
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, clb.with(RuntimeVisibleAnnotationsAttribute.of(
"AnnotationWithExtraInterface", null, Annotation.of(CD_Retention, AnnotationElement.of("value",
"java/lang/Object", new String[]{"java/lang/annotation/Annotation", AnnotationValue.of(RetentionPolicy.RUNTIME)))
"java/io/Serializable"}); ));
clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
{ mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
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();
} }
} }
@ -189,35 +159,21 @@ public class ClassFileGenerator {
*/ */
private static class AnnotationWithExceptionDump implements Opcodes { private static class AnnotationWithExceptionDump {
public static byte[] dump() throws Exception { public static byte[] dump() {
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of("AnnotationWithException"), clb -> {
MethodVisitor mv; clb.withSuperclass(CD_Object);
AnnotationVisitor av0; clb.withInterfaceSymbols(CD_Annotation);
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, clb.with(RuntimeVisibleAnnotationsAttribute.of(
"AnnotationWithException", null, Annotation.of(CD_Retention, AnnotationElement.of("value",
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
{ clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT, mb -> {
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1)));
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", mb.with(ExceptionsAttribute.ofSymbols(CD_Exception));
"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();
} }
} }
@ -230,34 +186,19 @@ public class ClassFileGenerator {
*/ */
private static class AnnotationWithHashCodeDump implements Opcodes { private static class AnnotationWithHashCodeDump {
public static byte[] dump() throws Exception { public static byte[] dump() {
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of("AnnotationWithHashCode"), clb -> {
MethodVisitor mv; clb.withSuperclass(CD_Object);
AnnotationVisitor av0; clb.withInterfaceSymbols(CD_Annotation);
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, clb.with(RuntimeVisibleAnnotationsAttribute.of(
"AnnotationWithHashCode", null, Annotation.of(CD_Retention, AnnotationElement.of("value",
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
{ clb.withMethod("hashCode", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
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();
} }
} }
@ -271,47 +212,26 @@ public class ClassFileGenerator {
*/ */
private static class AnnotationWithDefaultMemberDump implements Opcodes { private static class AnnotationWithDefaultMemberDump {
public static byte[] dump() throws Exception { public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of("AnnotationWithDefaultMember"), clb -> {
MethodVisitor mv, dv; clb.withSuperclass(CD_Object);
AnnotationVisitor av0; clb.withInterfaceSymbols(CD_Annotation);
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE, clb.with(RuntimeVisibleAnnotationsAttribute.of(
"AnnotationWithDefaultMember", null, Annotation.of(CD_Retention, AnnotationElement.of("value",
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
{ clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", clb.withMethod("d", MethodTypeDesc.of(CD_int), ACC_PUBLIC, mb -> {
"RUNTIME"); mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(2)));
av0.visitEnd(); mb.withCode(cob -> {
} cob.iconst_2();
{ cob.ireturn();
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();
} }
} }
@ -324,34 +244,19 @@ public class ClassFileGenerator {
*/ */
private static class AnnotationWithoutAnnotationAccessModifierDump implements Opcodes { private static class AnnotationWithoutAnnotationAccessModifierDump {
public static byte[] dump() throws Exception { public static byte[] dump() {
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of("AnnotationWithoutAnnotationAccessModifier"), clb -> {
MethodVisitor mv; clb.withSuperclass(CD_Object);
AnnotationVisitor av0; clb.withInterfaceSymbols(CD_Annotation);
clb.withFlags(PUBLIC, /*AccessFlag.ANNOTATION,*/ ABSTRACT, AccessFlag.INTERFACE);
cw.visit(52, ACC_PUBLIC + /* ACC_ANNOTATION +*/ ACC_ABSTRACT + ACC_INTERFACE, clb.with(RuntimeVisibleAnnotationsAttribute.of(
"AnnotationWithoutAnnotationAccessModifier", null, Annotation.of(CD_Retention, AnnotationElement.of("value",
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"}); AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
{ clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
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();
} }
} }
@ -365,24 +270,16 @@ public class ClassFileGenerator {
*/ */
private static class HolderXDump implements Opcodes { private static class HolderXDump {
public static byte[] dump() throws Exception { public static byte[] dump() {
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of("HolderX"), clb -> {
clb.withSuperclass(CD_Object);
cw.visit(52, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, clb.withFlags(PUBLIC, ABSTRACT, INTERFACE);
"HolderX", null, clb.with(RuntimeVisibleAnnotationsAttribute.of(
"java/lang/Object", new String[0]); Annotation.of(ClassDesc.of("GoodAnnotation")),
Annotation.of(ClassDesc.of("ClassFileGenerator$AnnotationWithoutAnnotationAccessModifier"))
{ ));
AnnotationVisitor av0; });
av0 = cw.visitAnnotation("LGoodAnnotation;", true);
av0.visitEnd();
av0 = cw.visitAnnotation("LAnnotationWithoutAnnotationAccessModifier;", true);
av0.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
} }
} }
} }

View file

@ -1,7 +1,7 @@
#!/bin/sh #!/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. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -87,7 +87,8 @@ ${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} bootreporter/*.java
cd .. cd ..
${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ ${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 ${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -classpath .${PATHSEP}bootpath ${APP}.java
echo "Manifest-Version: 1.0" > ${AGENT}.mf echo "Manifest-Version: 1.0" > ${AGENT}.mf

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -21,25 +21,29 @@
* questions. * questions.
*/ */
/** /*
* @test * @test
* @bug 6263319 * @bug 6263319
* @requires ((vm.opt.StartFlightRecording == null) | (vm.opt.StartFlightRecording == false)) & ((vm.opt.FlightRecorder == null) | (vm.opt.FlightRecorder == false)) * @requires ((vm.opt.StartFlightRecording == null) | (vm.opt.StartFlightRecording == false)) & ((vm.opt.FlightRecorder == null) | (vm.opt.FlightRecorder == false))
* @summary test setNativeMethodPrefix * @summary test setNativeMethodPrefix
* @author Robert Field, Sun Microsystems * @author Robert Field, Sun Microsystems
* *
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* java.management * @modules java.management
* java.instrument * java.instrument
* @run shell/timeout=240 MakeJAR2.sh NativeMethodPrefixAgent NativeMethodPrefixApp 'Can-Retransform-Classes: true' 'Can-Set-Native-Method-Prefix: true' * @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 * @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.lang.instrument.*;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.io.*; import java.io.*;
import asmlib.*; import static java.lang.constant.ConstantDescs.*;
class NativeMethodPrefixAgent { class NativeMethodPrefixAgent {
@ -54,6 +58,8 @@ class NativeMethodPrefixAgent {
} }
static class Tr implements ClassFileTransformer { 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 String trname;
final int transformId; final int transformId;
@ -76,11 +82,13 @@ class NativeMethodPrefixAgent {
try { try {
byte[] newcf = Instrumentor.instrFor(classfileBuffer) byte[] newcf = Instrumentor.instrFor(classfileBuffer)
.addNativeMethodTrackingInjection( .addNativeMethodTrackingInjection(
"wrapped_" + trname + "_", "wrapped_" + trname + "_", (name, h) -> {
(h)->{ h.constantInstruction(name);
h.push(h.getName()); h.constantInstruction(transformId);
h.push(transformId); h.invokestatic(
h.invokeStatic("bootreporter/StringIdCallbackReporter", "tracker", "(Ljava/lang/String;I)V", false); CD_StringIdCallbackReporter,
"tracker",
MTD_void_String_int);
}) })
.apply(); .apply();
/*** debugging ... /*** debugging ...

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -21,23 +21,28 @@
* questions. * questions.
*/ */
/** /*
* @test * @test
* @bug 6274264 6274241 5070281 * @bug 6274264 6274241 5070281
* @summary test retransformClasses * @summary test retransformClasses
* @author Robert Field, Sun Microsystems * @author Robert Field, Sun Microsystems
* *
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* java.instrument * @modules java.instrument
* @run shell/timeout=240 MakeJAR2.sh RetransformAgent RetransformApp 'Can-Retransform-Classes: true' * @run shell/timeout=240 MakeJAR2.sh RetransformAgent RetransformApp 'Can-Retransform-Classes: true'
* @run main/othervm -javaagent:RetransformAgent.jar RetransformApp * @run main/othervm -javaagent:RetransformAgent.jar RetransformApp
*/ */
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.lang.instrument.*; import java.lang.instrument.*;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.io.*; import java.io.*;
import asmlib.*; import asmlib.*;
import static java.lang.constant.ConstantDescs.CD_int;
import static java.lang.constant.ConstantDescs.CD_void;
class RetransformAgent { class RetransformAgent {
static ClassFileTransformer t1, t2, t3, t4; static ClassFileTransformer t1, t2, t3, t4;
@ -48,6 +53,8 @@ class RetransformAgent {
11, 40, 20, 11, 40, 20, 11, 40, 20, 11, 40, 20}; 11, 40, 20, 11, 40, 20, 11, 40, 20, 11, 40, 20};
static class Tr implements ClassFileTransformer { 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 String trname;
final boolean onLoad; final boolean onLoad;
final int loadIndex; final int loadIndex;
@ -83,9 +90,11 @@ class RetransformAgent {
byte[] newcf = Instrumentor.instrFor(classfileBuffer) byte[] newcf = Instrumentor.instrFor(classfileBuffer)
.addMethodEntryInjection( .addMethodEntryInjection(
nname, nname,
(h)->{ cb -> {
h.push(fixedIndex); cb.constantInstruction(fixedIndex);
h.invokeStatic("RetransformAgent", "callTracker", "(I)V", false); cb.invokestatic(
CD_RetransformAgent,
"callTracker", MTD_void_int);
}) })
.apply(); .apply();
/*** debugging ... /*** debugging ...

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,171 +23,133 @@
package asmlib; 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.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicBoolean;
import jdk.internal.org.objectweb.asm.ClassReader; import java.util.function.BiConsumer;
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.function.Consumer; import java.util.function.Consumer;
import jdk.internal.org.objectweb.asm.Type;
import static java.lang.classfile.ClassFile.ACC_NATIVE;
public class Instrumentor { 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) { public static Instrumentor instrFor(byte[] classData) {
return new Instrumentor(classData); return new Instrumentor(classData);
} }
private final ClassModel model;
private final ClassReader cr; private ClassTransform transform = ClassTransform.ACCEPT_ALL;
private final ClassWriter output; private final AtomicBoolean dirty = new AtomicBoolean(false);
private ClassVisitor instrumentingVisitor = null;
private final AtomicInteger matches = new AtomicInteger(0);
private Instrumentor(byte[] classData) { private Instrumentor(byte[] classData) {
cr = new ClassReader(classData); model = ClassFile.of().parse(classData);
output = new ClassWriter(ClassWriter.COMPUTE_MAXS);
instrumentingVisitor = output;
} }
public synchronized Instrumentor addMethodEntryInjection(String methodName, Consumer<InstrHelper> injector) { public synchronized Instrumentor addMethodEntryInjection(String methodName, Consumer<CodeBuilder> injector) {
instrumentingVisitor = new ClassVisitor(Opcodes.ASM7, instrumentingVisitor) { transform = transform.andThen(ClassTransform.transformingMethodBodies(mm -> {
@Override if (mm.methodName().equalsString(methodName)) {
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { dirty.set(true);
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); return true;
if (name.equals(methodName)) {
matches.getAndIncrement();
mv = new MethodVisitor(Opcodes.ASM7, mv) {
@Override
public void visitCode() {
injector.accept(new InstrHelper(mv, name));
}
};
}
return mv;
} }
}; 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; return this;
} }
public synchronized Instrumentor addNativeMethodTrackingInjection(String prefix, Consumer<InstrHelper> injector) { public synchronized Instrumentor addNativeMethodTrackingInjection(String prefix, BiConsumer<String, CodeBuilder> injector) {
instrumentingVisitor = new ClassVisitor(Opcodes.ASM9, instrumentingVisitor) { transform = transform.andThen(ClassTransform.ofStateful(() -> new ClassTransform() {
private final Set<Consumer<ClassVisitor>> wmGenerators = new HashSet<>(); private final Set<Consumer<ClassBuilder>> wmGenerators = new HashSet<>();
private String className;
@Override @Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { public void accept(ClassBuilder builder, ClassElement element) {
this.className = name; if (element instanceof MethodModel mm && mm.flags().has(AccessFlag.NATIVE)) {
super.visit(version, access, name, signature, superName, interfaces); dirty.set(true);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if ((access & Opcodes.ACC_NATIVE) != 0) {
matches.getAndIncrement();
String name = mm.methodName().stringValue();
String newName = prefix + name; String newName = prefix + name;
wmGenerators.add((v)->{ MethodTypeDesc mt = mm.methodTypeSymbol();
MethodVisitor mv = v.visitMethod(access & ~Opcodes.ACC_NATIVE, name, desc, signature, exceptions); wmGenerators.add(clb -> clb.transformMethod(mm, new MethodTransform() {
mv.visitCode(); @Override
injector.accept(new InstrHelper(mv, name)); public void accept(MethodBuilder mb, MethodElement me) {
Type[] argTypes = Type.getArgumentTypes(desc); if (me instanceof AccessFlags flags) {
Type retType = Type.getReturnType(desc); mb.withFlags(flags.flagsMask() & ~ACC_NATIVE);
} else if (!(me instanceof CodeModel)) {
boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; mb.with(me);
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();
} }
} }
mv.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKESPECIAL, className, newName, desc, false); @Override
mv.visitInsn(retType.getOpcode(Opcodes.IRETURN)); public void atEnd(MethodBuilder mb) {
Consumer<CodeBuilder> 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 // load method parameters
mv.visitEnd(); for (int i = 0; i < mt.parameterCount(); i++) {
}); TypeKind kind = TypeKind.from(mt.parameterType(i));
return super.visitMethod(access, newName, desc, signature, exceptions); 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 @Override
public void visitEnd() { public void atEnd(ClassBuilder builder) {
wmGenerators.stream().forEach((e) -> { wmGenerators.forEach(e -> e.accept(builder));
e.accept(cv);
});
super.visitEnd();
} }
}; }));
return this; return this;
} }
public synchronized byte[] apply() { 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;
} }
} }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,18 +24,14 @@
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.classfile.ClassTransform;
import java.lang.classfile.ClassFile;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Vector; import java.util.Vector;
import jdk.internal.org.objectweb.asm.*;
public class BogoLoader extends ClassLoader { public class BogoLoader extends ClassLoader {
static interface VisitorMaker {
ClassVisitor make(ClassVisitor visitor);
}
/** /**
* Use this property to verify that the desired classloading is happening. * 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. * Map from class names to a bytecode transformer factory.
*/ */
private Map<String, VisitorMaker> replaced; private Map<String, ClassTransform> replaced;
/** /**
* Keep track (not terribly efficiently) of which classes have already * 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); return ! nonSystem.contains(name) && ! replaced.containsKey(name);
} }
public BogoLoader(Set<String> non_system, Map<String, VisitorMaker> replaced) { public BogoLoader(Set<String> non_system, Map<String, ClassTransform> replaced) {
super(Thread.currentThread().getContextClassLoader()); super(Thread.currentThread().getContextClassLoader());
this.nonSystem = non_system; this.nonSystem = non_system;
this.replaced = replaced; this.replaced = replaced;
@ -126,11 +122,8 @@ public class BogoLoader extends ClassLoader {
if (verbose) { if (verbose) {
System.err.println("Replacing class " + name); System.err.println("Replacing class " + name);
} }
ClassReader cr = new ClassReader(classData); var cf = ClassFile.of();
ClassWriter cw = new ClassWriter(0); classData = cf.transform(cf.parse(classData), replaced.get(name));
VisitorMaker vm = replaced.get(name);
cr.accept(vm.make(cw), 0);
classData = cw.toByteArray();
} }
clazz = defineClass(name, classData, 0, classData.length); clazz = defineClass(name, classData, 0, classData.length);
} catch (java.io.EOFException ioe) { } catch (java.io.EOFException ioe) {

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -21,60 +21,53 @@
* questions. * questions.
*/ */
/** /*
* @test * @test
* @bug 8022701 * @bug 8022701
* @summary Illegal access exceptions via methodhandle invocations threw wrong error. * @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 * @compile -XDignore.symbol.file BogoLoader.java InvokeSeveralWays.java MHIllegalAccess.java MethodSupplier.java
* @run main/othervm MHIllegalAccess * @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.lang.reflect.InvocationTargetException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; 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("Classpath is " + System.getProperty("java.class.path"));
System.out.println(); System.out.println();
/** /**
* Make method m be private to provoke an IllegalAccessError. * Make method m be private to provoke an IllegalAccessError.
*/ */
BogoLoader.VisitorMaker privatize = new BogoLoader.VisitorMaker() { var privatize = ClassTransform.transformingMethods(m -> m.methodName().equalsString("m"), (mb, me) -> {
public ClassVisitor make(ClassVisitor cv) { if (me instanceof AccessFlags af) {
return new ClassVisitor(Opcodes.ASM5, cv) { mb.withFlags((af.flagsMask() | ACC_PRIVATE) & ~ (ACC_PUBLIC | ACC_PROTECTED));
public MethodVisitor visitMethod(int access, String name, String desc, } else {
String signature, String[] exceptions) { mb.accept(me);
if (name.equals("m")) }
access = (access | ACC_PRIVATE) & ~ (ACC_PUBLIC | ACC_PROTECTED); });
return super.visitMethod(access, name, desc, signature, exceptions);
}
};
}
};
/** /**
* Rename method m as nemo to provoke a NoSuchMethodError. * Rename method m as nemo to provoke a NoSuchMethodError.
*/ */
BogoLoader.VisitorMaker changeName = new BogoLoader.VisitorMaker() { ClassTransform changeName = (cb, ce) -> {
public ClassVisitor make(ClassVisitor cv) { if (ce instanceof MethodModel mm && mm.methodName().equalsString("m")) {
return new ClassVisitor(Opcodes.ASM5, cv) { cb.withMethod("nemo", mm.methodTypeSymbol(), mm.flags().flagsMask(), mm::forEachElement);
public MethodVisitor visitMethod(int access, String name, String desc, } else {
String signature, String[] exceptions) { cb.accept(ce);
if (name.equals("m")) }
name = "nemo"; };
return super.visitMethod(access, name, desc, signature, exceptions);
}
};
}
};
int failures = 0; int failures = 0;
failures += testOneError(privatize, args, IllegalAccessError.class); failures += testOneError(privatize, args, IllegalAccessError.class);
@ -94,8 +87,8 @@ public class MHIllegalAccess implements Opcodes {
* @throws ClassNotFoundException * @throws ClassNotFoundException
* @throws Throwable * @throws Throwable
*/ */
private static int testOneError(BogoLoader.VisitorMaker vm, String[] args, Class expected) throws ClassNotFoundException, Throwable { private static int testOneError(ClassTransform vm, String[] args, Class<?> expected) throws ClassNotFoundException, Throwable {
HashMap<String, BogoLoader.VisitorMaker> replace = new HashMap<String, BogoLoader.VisitorMaker>(); var replace = new HashMap<String, ClassTransform>();
replace.put("MethodSupplier", vm); replace.put("MethodSupplier", vm);
HashSet<String> in_bogus = new HashSet<String>(); HashSet<String> in_bogus = new HashSet<String>();

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,31 +23,38 @@
/* @test /* @test
* @modules java.base/java.lang:open * @modules java.base/java.lang:open
* java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @run testng/othervm test.DefineClassTest * @run testng/othervm test.DefineClassTest
* @summary Basic test for java.lang.invoke.MethodHandles.Lookup.defineClass * @summary Basic test for java.lang.invoke.MethodHandles.Lookup.defineClass
*/ */
package test; package test;
import java.lang.classfile.ClassFile;
import java.lang.constant.ClassDesc;
import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodHandles.Lookup;
import static java.lang.invoke.MethodHandles.*; import java.lang.reflect.AccessFlag;
import static java.lang.invoke.MethodHandles.Lookup.*;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; 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 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.*; import static org.testng.Assert.*;
public class DefineClassTest { public class DefineClassTest {
private static final String THIS_PACKAGE = DefineClassTest.class.getPackageName(); 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 * 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 * Generates a class file with the given class name
*/ */
byte[] generateClass(String className) { byte[] generateClass(String className) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS return ClassFile.of().build(ClassDesc.of(className), clb -> {
+ ClassWriter.COMPUTE_FRAMES); clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
cw.visit(V9, clb.withSuperclass(CD_Object);
ACC_PUBLIC + ACC_SUPER, clb.withMethodBody(INIT_NAME, MTD_void, PUBLIC, cob -> {
className.replace(".", "/"), cob.aload(0);
null, cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
"java/lang/Object", cob.return_();
null); });
});
// <init>
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
cw.visitEnd();
return cw.toByteArray();
} }
/** /**
@ -280,33 +277,19 @@ public class DefineClassTest {
String targetClass, String targetClass,
String targetMethod) throws Exception { String targetMethod) throws Exception {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS return ClassFile.of().build(ClassDesc.of(className), clb -> {
+ ClassWriter.COMPUTE_FRAMES); clb.withSuperclass(CD_Object);
cw.visit(V9, clb.withInterfaceSymbols(CD_Runnable);
ACC_PUBLIC + ACC_SUPER, clb.withMethodBody(INIT_NAME, MTD_void, PUBLIC, cob -> {
className.replace(".", "/"), cob.aload(0);
null, cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
"java/lang/Object", cob.return_();
new String[] { "java/lang/Runnable" }); });
clb.withMethodBody("run", MTD_void, PUBLIC, cob -> {
// <init> cob.invokestatic(ClassDesc.of(targetClass), targetMethod, MTD_void);
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); cob.return_();
mv.visitVarInsn(ALOAD, 0); });
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()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();
} }
/** /**
@ -317,75 +300,41 @@ public class DefineClassTest {
String targetClass, String targetClass,
String targetMethod) throws Exception { String targetMethod) throws Exception {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS return ClassFile.of().build(ClassDesc.of(className), clb -> {
+ ClassWriter.COMPUTE_FRAMES); clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
cw.visit(V9, clb.withSuperclass(CD_Object);
ACC_PUBLIC + ACC_SUPER, clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> {
className.replace(".", "/"), cob.aload(0);
null, cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
"java/lang/Object", cob.return_();
null); });
clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, cob -> {
// <init> cob.invokestatic(ClassDesc.of(targetClass), targetMethod, MTD_void);
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); cob.return_();
mv.visitVarInsn(ALOAD, 0); });
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); });
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
// <clinit>
String tc = targetClass.replace(".", "/");
mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
cw.visitEnd();
return cw.toByteArray();
} }
/** /**
* Generates a non-linkable class file with the given class name * Generates a non-linkable class file with the given class name
*/ */
byte[] generateNonLinkableClass(String className) { byte[] generateNonLinkableClass(String className) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS return ClassFile.of().build(ClassDesc.of(className), clb -> {
+ ClassWriter.COMPUTE_FRAMES); clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
cw.visit(V14, clb.withSuperclass(CD_MissingSuperClass);
ACC_PUBLIC + ACC_SUPER, clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> {
className.replace(".", "/"), cob.aload(0);
null, cob.invokespecial(CD_MissingSuperClass, INIT_NAME, MTD_void);
"MissingSuperClass", cob.return_();
null); });
});
// <init>
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "MissingSuperClass", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
cw.visitEnd();
return cw.toByteArray();
} }
/** /**
* Generates a class file with the given class name * Generates a class file with the given class name
*/ */
byte[] generateModuleInfo() { byte[] generateModuleInfo() {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS return ClassFile.of().build(ClassDesc.of("module-info"), cb -> cb.withFlags(AccessFlag.MODULE));
+ ClassWriter.COMPUTE_FRAMES);
cw.visit(V14,
ACC_MODULE,
"module-info",
null,
null,
null);
cw.visitEnd();
return cw.toByteArray();
} }
private int nextNumber() { private int nextNumber() {

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,17 +25,26 @@
* @test * @test
* @bug 8230501 * @bug 8230501
* @library /test/lib * @library /test/lib
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @run testng/othervm ClassDataTest * @run testng/othervm ClassDataTest
*/ */
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UncheckedIOException; 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.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.lang.reflect.AccessFlag;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -43,18 +52,20 @@ import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream; import java.util.stream.Stream;
import jdk.internal.org.objectweb.asm.*;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; 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 java.lang.invoke.MethodHandles.Lookup.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import static org.testng.Assert.*; import static org.testng.Assert.*;
public class ClassDataTest { public class ClassDataTest {
private static final Lookup LOOKUP = MethodHandles.lookup(); private static final Lookup LOOKUP = MethodHandles.lookup();
private static final ClassDesc CD_ClassDataTest = ClassDataTest.class.describeConstable().orElseThrow();
@Test @Test
public void testOriginalAccess() throws IllegalAccessException { public void testOriginalAccess() throws IllegalAccessException {
@ -294,15 +305,13 @@ public class ClassDataTest {
public void classDataMap() throws ReflectiveOperationException { public void classDataMap() throws ReflectiveOperationException {
ClassByteBuilder builder = new ClassByteBuilder("map"); ClassByteBuilder builder = new ClassByteBuilder("map");
// generate classData static method // generate classData static method
Handle bsm = new Handle(H_INVOKESTATIC, "ClassDataTest", "getClassDataEntry", DirectMethodHandleDesc bsm = ConstantDescs.ofConstantBootstrap(CD_ClassDataTest, "getClassDataEntry", CD_Object);
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;",
false);
// generate two accessor methods to get the entries from class data // generate two accessor methods to get the entries from class data
byte[] bytes = builder.classData(ACC_PUBLIC|ACC_STATIC, Map.class) byte[] bytes = builder.classData(ACC_PUBLIC|ACC_STATIC, Map.class)
.classData(ACC_PUBLIC|ACC_STATIC, "getClass", .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", .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(); .build();
// generate a hidden class // 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 MHS_CLS = "java/lang/invoke/MethodHandles";
private static final String CLASS_DATA_BSM_DESCR = private static final String CLASS_DATA_BSM_DESCR =
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;"; "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;";
private final ClassWriter cw; private Consumer<ClassBuilder> cw;
private final String classname; private final ClassDesc classname;
/** /**
* A builder to generate a class file to access class data * A builder to generate a class file to access class data
* @param classname * @param classname
*/ */
ClassByteBuilder(String classname) { ClassByteBuilder(String classname) {
this.classname = classname; this.classname = ClassDesc.ofInternalName(classname);
this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); this.cw = clb -> {
cw.visit(V14, ACC_FINAL, classname, null, OBJECT_CLS, null); clb.withSuperclass(CD_Object);
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); clb.withFlags(AccessFlag.FINAL);
mv.visitCode(); clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> {
mv.visitVarInsn(ALOAD, 0); cob.aload(0);
mv.visitMethodInsn(INVOKESPECIAL, OBJECT_CLS, "<init>", "()V", false); cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
mv.visitInsn(RETURN); cob.return_();
mv.visitMaxs(0, 0); });
mv.visitEnd(); };
} }
byte[] build() { byte[] build() {
cw.visitEnd(); byte[] bytes = ClassFile.of().build(classname, cw);
byte[] bytes = cw.toByteArray();
Path p = Paths.get(classname + ".class"); Path p = Paths.get(classname + ".class");
try (OutputStream os = Files.newOutputStream(p)) { try (OutputStream os = Files.newOutputStream(p)) {
os.write(bytes); os.write(bytes);
@ -378,20 +386,14 @@ public class ClassDataTest {
* Generate classData method to load class data via condy * Generate classData method to load class data via condy
*/ */
ClassByteBuilder classData(int accessFlags, Class<?> returnType) { ClassByteBuilder classData(int accessFlags, Class<?> returnType) {
MethodType mtype = MethodType.methodType(returnType); ClassDesc returnDesc = returnType.describeConstable().orElseThrow();
MethodVisitor mv = cw.visitMethod(accessFlags, MethodTypeDesc mt = MethodTypeDesc.of(returnDesc);
"classData", cw = cw.andThen(clb -> {
mtype.descriptorString(), null, null); clb.withMethodBody("classData", mt, accessFlags, cob -> {
mv.visitCode(); cob.constantInstruction(DynamicConstantDesc.ofNamed(BSM_CLASS_DATA, DEFAULT_NAME, returnDesc));
Handle bsm = new Handle(H_INVOKESTATIC, MHS_CLS, "classData", cob.returnInstruction(TypeKind.from(returnType));
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();
return this; return this;
} }
@ -399,32 +401,26 @@ public class ClassDataTest {
* Generate classDataAt method to load an element from class data via condy * Generate classDataAt method to load an element from class data via condy
*/ */
ClassByteBuilder classDataAt(int accessFlags, Class<?> returnType, int index) { ClassByteBuilder classDataAt(int accessFlags, Class<?> returnType, int index) {
MethodType mtype = MethodType.methodType(returnType); ClassDesc returnDesc = returnType.describeConstable().orElseThrow();
MethodVisitor mv = cw.visitMethod(accessFlags, MethodTypeDesc mt = MethodTypeDesc.of(returnDesc);
"classData", cw = cw.andThen(clb -> {
mtype.descriptorString(), null, null); clb.withMethodBody("classData", mt, accessFlags, cob -> {
mv.visitCode(); cob.constantInstruction(DynamicConstantDesc.ofNamed(BSM_CLASS_DATA_AT, DEFAULT_NAME, returnDesc, index));
Handle bsm = new Handle(H_INVOKESTATIC, "java/lang/invoke/MethodHandles", "classDataAt", cob.returnInstruction(TypeKind.from(returnType));
"(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();
return this; return this;
} }
ClassByteBuilder classData(int accessFlags, String name, Class<?> returnType, ConstantDynamic dynamic) { ClassByteBuilder classData(int accessFlags, String name, Class<?> returnType, DynamicConstantDesc<?> dynamic) {
MethodType mtype = MethodType.methodType(returnType); ClassDesc returnDesc = returnType.describeConstable().orElseThrow();
MethodVisitor mv = cw.visitMethod(accessFlags, MethodTypeDesc mt = MethodTypeDesc.of(returnDesc);
name, cw = cw.andThen(clb -> {
mtype.descriptorString(), null, null); clb.withMethodBody(name, mt, accessFlags, cob -> {
mv.visitCode(); cob.constantInstruction(dynamic);
mv.visitLdcInsn(dynamic); cob.returnInstruction(TypeKind.from(returnType));
mv.visitInsn(returnType == int.class? IRETURN : ARETURN); });
mv.visitMaxs(0, 0); });
mv.visitEnd();
return this; return this;
} }
} }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,19 +24,16 @@
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.classfile.ClassTransform;
import java.lang.classfile.ClassFile;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Vector; import java.util.Vector;
import jdk.internal.org.objectweb.asm.*;
// Compile with -XDignore.symbol.file=true // Compile with -XDignore.symbol.file=true
public class BogoLoader extends ClassLoader { public class BogoLoader extends ClassLoader {
static interface VisitorMaker {
ClassVisitor make(ClassVisitor visitor);
}
/** /**
* Use this property to verify that the desired classloading is happening. * 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. * Map from class names to a bytecode transformer factory.
*/ */
private Map<String, VisitorMaker> replaced; private Map<String, ClassTransform> replaced;
/** /**
* Keep track (not terribly efficiently) of which classes have already * 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); return ! nonSystem.contains(name) && ! replaced.containsKey(name);
} }
public BogoLoader(Set<String> non_system, Map<String, VisitorMaker> replaced) { public BogoLoader(Set<String> non_system, Map<String, ClassTransform> replaced) {
super(Thread.currentThread().getContextClassLoader()); super(Thread.currentThread().getContextClassLoader());
this.nonSystem = non_system; this.nonSystem = non_system;
this.replaced = replaced; this.replaced = replaced;
@ -127,11 +124,8 @@ public class BogoLoader extends ClassLoader {
if (verbose) { if (verbose) {
System.err.println("Replacing class " + name); System.err.println("Replacing class " + name);
} }
ClassReader cr = new ClassReader(classData); var cf = ClassFile.of();
ClassWriter cw = new ClassWriter(0); classData = cf.transform(cf.parse(classData), replaced.get(name));
VisitorMaker vm = replaced.get(name);
cr.accept(vm.make(cw), 0);
classData = cw.toByteArray();
} }
clazz = defineClass(name, classData, 0, classData.length); clazz = defineClass(name, classData, 0, classData.length);
} catch (java.io.EOFException ioe) { } catch (java.io.EOFException ioe) {

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -21,64 +21,53 @@
* questions. * questions.
*/ */
/** /*
* @test * @test
* @bug 8022718 * @bug 8022718
* @summary Runtime accessibility checking: protected class, if extended, should be accessible from another package * @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 * @compile -XDignore.symbol.file BogoLoader.java MethodInvoker.java Test.java anotherpkg/MethodSupplierOuter.java
* @run main/othervm Test * @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.lang.reflect.Method;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor; import static java.lang.classfile.ClassFile.ACC_PRIVATE;
import jdk.internal.org.objectweb.asm.ClassVisitor; import static java.lang.classfile.ClassFile.ACC_PROTECTED;
import jdk.internal.org.objectweb.asm.Opcodes; import static java.lang.classfile.ClassFile.ACC_PUBLIC;
interface MyFunctionalInterface { interface MyFunctionalInterface {
void invokeMethodReference(); 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 class Test {
public static void main(String argv[]) throws Exception, Throwable { public static void main(String[] argv) throws Throwable {
BogoLoader.VisitorMaker makeProtectedNop = new MakeProtected(false); ClassTransform makeProtectedNop = ClassTransform.ACCEPT_ALL;
BogoLoader.VisitorMaker makeProtectedMod = new MakeProtected(true); 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; int errors = 0;
errors += tryModifiedInvocation(makeProtectedNop); errors += tryModifiedInvocation(makeProtectedNop);
@ -89,12 +78,11 @@ public class Test {
} }
} }
private static int tryModifiedInvocation(BogoLoader.VisitorMaker makeProtected) private static int tryModifiedInvocation(ClassTransform makeProtected)
throws Throwable, ClassNotFoundException { throws Throwable {
HashMap<String, BogoLoader.VisitorMaker> replace var replace = new HashMap<String, ClassTransform>();
= new HashMap<String, BogoLoader.VisitorMaker>();
replace.put("anotherpkg.MethodSupplierOuter$MethodSupplier", makeProtected); replace.put("anotherpkg.MethodSupplierOuter$MethodSupplier", makeProtected);
HashSet<String> in_bogus = new HashSet<String>(); var in_bogus = new HashSet<String>();
in_bogus.add("MethodInvoker"); in_bogus.add("MethodInvoker");
in_bogus.add("MyFunctionalInterface"); in_bogus.add("MyFunctionalInterface");
in_bogus.add("anotherpkg.MethodSupplierOuter"); // seems to be never loaded in_bogus.add("anotherpkg.MethodSupplierOuter"); // seems to be never loaded

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,9 +23,10 @@
/* /*
* @test * @test
* @modules java.base/jdk.internal.org.objectweb.asm * @modules jdk.compiler
* jdk.compiler
* @library /test/lib * @library /test/lib
* @enablePreview
* @comment Change enablePreview with the flag in setup's compileSources
* @compile BadClassFile.jcod * @compile BadClassFile.jcod
* BadClassFile2.jcod * BadClassFile2.jcod
* BadClassFileVersion.jcod * BadClassFileVersion.jcod
@ -36,11 +37,9 @@
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.classfile.ClassFile;
import java.lang.constant.ClassDesc;
import java.lang.invoke.MethodHandles.Lookup; 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.Array;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -51,8 +50,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Stream; 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.compiler.CompilerUtils;
import jdk.test.lib.Utils; import jdk.test.lib.Utils;
@ -60,7 +57,11 @@ import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; 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.*; import static org.testng.Assert.*;
interface HiddenTest { interface HiddenTest {
@ -77,7 +78,7 @@ public class BasicTest {
@BeforeTest @BeforeTest
static void setup() throws IOException { 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")); hiddenClassBytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenClass.class"));
// compile with --release 10 with no NestHost and NestMembers attribute // compile with --release 10 with no NestHost and NestMembers attribute
@ -264,8 +265,8 @@ public class BasicTest {
*/ */
@Test(dataProvider = "emptyClasses") @Test(dataProvider = "emptyClasses")
public void emptyHiddenClass(String name, int accessFlags) throws Exception { public void emptyHiddenClass(String name, int accessFlags) throws Exception {
byte[] bytes = (accessFlags == ACC_ENUM) ? classBytes(name, Enum.class, accessFlags) byte[] bytes = (accessFlags == ACC_ENUM) ? classBytes(name, CD_Enum, accessFlags)
: classBytes(name, accessFlags); : classBytes(name, accessFlags);
Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass(); Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
switch (accessFlags) { switch (accessFlags) {
case ACC_SYNTHETIC: case ACC_SYNTHETIC:
@ -514,14 +515,13 @@ public class BasicTest {
} }
private static byte[] classBytes(String classname, int accessFlags) { 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) { private static byte[] classBytes(String classname, ClassDesc superType, int accessFlags) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); return ClassFile.of().build(ClassDesc.ofInternalName(classname), clb -> clb
cw.visit(V14, ACC_PUBLIC|accessFlags, classname, null, Type.getInternalName(supertType), null); .withVersion(JAVA_14_VERSION, 0)
cw.visitEnd(); .withFlags(accessFlags | ACC_PUBLIC)
.withSuperclass(superType));
return cw.toByteArray();
} }
} }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,28 +24,35 @@
/* /*
* @test * @test
* @library /test/lib * @library /test/lib
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @build HiddenNestmateTest * @build HiddenNestmateTest
* @run testng/othervm 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.*;
import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.AccessFlag;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.Arrays; import java.util.Arrays;
import jdk.internal.org.objectweb.asm.*;
import org.testng.annotations.Test; 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.ClassOption.*;
import static java.lang.invoke.MethodHandles.Lookup.*; import static java.lang.invoke.MethodHandles.Lookup.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import static org.testng.Assert.*; import static org.testng.Assert.*;
public class HiddenNestmateTest { public class HiddenNestmateTest {
private static final ClassDesc CD_HiddenNestmateTest = HiddenNestmateTest.class.describeConstable().orElseThrow();
private static final byte[] bytes = classBytes("HiddenInjected"); private static final byte[] bytes = classBytes("HiddenInjected");
private static void assertNestmate(Lookup lookup) { private static void assertNestmate(Lookup lookup) {
@ -165,34 +172,20 @@ public class HiddenNestmateTest {
} }
private static byte[] classBytes(String classname) { private static byte[] classBytes(String classname) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); return ClassFile.of().build(ClassDesc.ofInternalName(classname), clb -> {
MethodVisitor mv; clb.withSuperclass(CD_Object);
clb.withFlags(AccessFlag.FINAL);
cw.visit(V12, ACC_FINAL, classname, null, "java/lang/Object", null); clb.withMethodBody(INIT_NAME, MTD_void, PUBLIC, cob -> {
cob.aload(0);
{ cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); cob.return_();
mv.visitCode(); });
mv.visitVarInsn(ALOAD, 0); clb.withMethodBody("test", MethodTypeDesc.of(CD_int, CD_HiddenNestmateTest), PUBLIC, cob -> {
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); cob.aload(1);
mv.visitInsn(RETURN); cob.invokevirtual(CD_HiddenNestmateTest, "privMethod", MethodTypeDesc.of(CD_int));
mv.visitMaxs(0, 0); cob.ireturn();
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();
} }
private int privMethod() { return 1234; } private int privMethod() { return 1234; }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,22 +24,24 @@
/* /*
* @test * @test
* @bug 8245432 * @bug 8245432
* @modules java.base/jdk.internal.org.objectweb.asm * @modules jdk.compiler
* jdk.compiler
* @library /test/lib * @library /test/lib
* @build jdk.test.lib.Utils * @build jdk.test.lib.Utils
* jdk.test.lib.compiler.CompilerUtils * jdk.test.lib.compiler.CompilerUtils
* @run testng PreviewHiddenClass * @run testng PreviewHiddenClass
* @summary verify UnsupportedClassVersionError thrown when defining a hidden class * @summary verify UnsupportedClassVersionError thrown when defining a hidden class
* with preview minor version but --enable-preview is not set * 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.lang.invoke.MethodHandles;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.compiler.CompilerUtils;
import jdk.test.lib.Utils; import jdk.test.lib.Utils;
@ -62,9 +64,9 @@ public class PreviewHiddenClass {
} }
byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenInterface.class")); byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve("HiddenInterface.class"));
ClassReader reader = new ClassReader(bytes); var dis = new DataInputStream(new ByteArrayInputStream(bytes));
int minor = reader.readUnsignedShort(4); dis.skipBytes(4); // 0xCAFEBABE
assertTrue(minor == 65535); assertEquals(dis.readUnsignedShort(), 65535); // Minor version
MethodHandles.lookup().defineHiddenClass(bytes, false); MethodHandles.lookup().defineHiddenClass(bytes, false);
} }
} }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,19 +25,28 @@
* @test * @test
* @bug 8266925 * @bug 8266925
* @summary hidden class members can't be statically invocable * @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/* * @build java.base/*
* @run testng StaticInvocableTest * @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.MethodHandle;
import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.lang.invoke.LookupHelper; import java.lang.invoke.LookupHelper;
import jdk.internal.org.objectweb.asm.*; import java.lang.reflect.AccessFlag;
import org.testng.annotations.Test; 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 class StaticInvocableTest {
public static void main(String[] args) throws Throwable { public static void main(String[] args) throws Throwable {
@ -106,28 +115,19 @@ public class StaticInvocableTest {
* } * }
*/ */
public static byte[] dumpClass(String pkg) { public static byte[] dumpClass(String pkg) {
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of(pkg.replace('/', '.'), "MyClass"), clb -> {
MethodVisitor mv; clb.withSuperclass(CD_Object);
clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
cw.visit(52, ACC_SUPER | ACC_PUBLIC, pkg+"/MyClass", null, "java/lang/Object", null); clb.withMethodBody(INIT_NAME, MTD_void, 0, cob -> {
{ cob.aload(0);
mv = cw.visitMethod(0, "<init>", "()V", null, null); cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
mv.visitCode(); cob.return_();
mv.visitVarInsn(ALOAD, 0); });
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); clb.withMethodBody("get", MethodTypeDesc.of(CD_Object, CD_int),
mv.visitInsn(RETURN); ACC_PUBLIC | ACC_STATIC, cob -> {
mv.visitMaxs(1, 1); cob.aconst_null();
mv.visitEnd(); cob.areturn();
} });
{ });
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();
} }
} }

View file

@ -25,35 +25,35 @@
* @test * @test
* @bug 8027232 * @bug 8027232
* @library /test/lib/ * @library /test/lib/
* @modules java.base/jdk.internal.org.objectweb.asm * @modules jdk.zipfs
* jdk.jdeps/com.sun.tools.classfile * @enablePreview
* jdk.zipfs
* @compile LambdaAsm.java * @compile LambdaAsm.java
* @run main/othervm LambdaAsm * @run main/othervm LambdaAsm
* @summary ensures that j.l.i.InvokerByteCodeGenerator and ASM visitMethodInsn * @summary ensures that j.l.i.InvokerByteCodeGenerator and Class-File API
* generate bytecodes with correct constant pool references * 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.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.charset.Charset;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.ArrayList; import java.util.ArrayList;
import java.nio.file.DirectoryStream; import java.nio.file.DirectoryStream;
import java.nio.file.Path; 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.compiler.CompilerUtils;
import jdk.test.lib.process.OutputAnalyzer; 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 java.nio.file.Files.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import static jdk.test.lib.process.ProcessTools.*; import static jdk.test.lib.process.ProcessTools.*;
public class LambdaAsm { public class LambdaAsm {
@ -99,16 +99,14 @@ public class LambdaAsm {
} }
static void checkMethod(String cname, String mname, ConstantPool cp, static void checkMethod(String cname, String mname, ConstantPool cp,
Code_attribute code) throws ConstantPool.InvalidIndex { CodeAttribute code) throws IllegalArgumentException {
for (Instruction i : code.getInstructions()) { for (var inst : code.elements()) {
String iname = i.getMnemonic(); if (inst instanceof InvokeInstruction inv && (inv.opcode() == Opcode.INVOKESPECIAL
if ("invokespecial".equals(iname) || inv.opcode() == Opcode.INVOKEINTERFACE)) {
|| "invokestatic".equals(iname)) { var ref = inv.method();
int idx = i.getByte(2);
System.out.println("Verifying " + cname + ":" + mname + System.out.println("Verifying " + cname + ":" + mname +
" instruction:" + iname + " index @" + idx); " instruction:" + inv.opcode() + " index @" + ref.index());
CPInfo cpinfo = cp.get(idx); if (ref instanceof MethodRefEntry) {
if (cpinfo instanceof ConstantPool.CONSTANT_Methodref_info) {
throw new RuntimeException("unexpected CP type expected " throw new RuntimeException("unexpected CP type expected "
+ "InterfaceMethodRef, got MethodRef, " + cname + "InterfaceMethodRef, got MethodRef, " + cname
+ ", " + mname); + ", " + mname);
@ -117,21 +115,20 @@ public class LambdaAsm {
} }
} }
static int checkMethod(ClassFile cf, String mthd) throws Exception { static int checkMethod(ClassModel cf, String mthd) throws Exception {
if (cf.major_version < 52) { if (cf.majorVersion() < 52) {
throw new RuntimeException("unexpected class file version, in " 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; int count = 0;
for (Method m : cf.methods) { for (var m : cf.methods()) {
String mname = m.getName(cf.constant_pool); String mname = m.methodName().stringValue();
if (mname.equals(mthd)) { if (mname.equals(mthd)) {
for (Attribute a : m.attributes) { for (var a : m.findAttributes(Attributes.CODE)) {
if ("Code".equals(a.getName(cf.constant_pool))) { count++;
count++; checkMethod(cf.thisClass().asInternalName(), mname,
checkMethod(cf.getName(), mname, cf.constant_pool, cf.constantPool(), a);
(Code_attribute) a);
}
} }
} }
} }
@ -146,9 +143,9 @@ public class LambdaAsm {
"A$I$$Lambda.*.class")) { "A$I$$Lambda.*.class")) {
for (Path p : ds) { for (Path p : ds) {
System.out.println(p.toFile()); System.out.println(p.toFile());
ClassFile cf = ClassFile.read(p.toFile()); ClassModel cm = ClassFile.of().parse(p);
// Check those methods implementing Supplier.get // Check those methods implementing Supplier.get
mcount += checkMethod(cf, "get"); mcount += checkMethod(cm, "get");
count++; count++;
} }
} }
@ -163,23 +160,21 @@ public class LambdaAsm {
} }
static void verifyASM() throws Exception { static void verifyASM() throws Exception {
ClassWriter cw = new ClassWriter(0); var functionDesc = ClassDesc.ofInternalName("java/util/function/Function");
cw.visit(V1_8, ACC_PUBLIC, "X", null, "java/lang/Object", null); byte[] carray = ClassFile.of().build(ClassDesc.of("X"), clb -> clb
MethodVisitor mv = cw.visitMethod(ACC_STATIC, "foo", .withVersion(JAVA_8_VERSION, 0)
"()V", null, null); .withFlags(ACC_PUBLIC)
mv.visitMaxs(2, 1); .withSuperclass(CD_Object)
mv.visitMethodInsn(INVOKESTATIC, .withMethodBody("foo", MTD_void, ACC_STATIC, cob -> cob
"java/util/function/Function.class", .invokestatic(functionDesc, "identity", MethodTypeDesc.of(functionDesc), true)
"identity", "()Ljava/util/function/Function;", true); )
mv.visitInsn(RETURN); );
cw.visitEnd();
byte[] carray = cw.toByteArray();
// for debugging // for debugging
// write((new File("X.class")).toPath(), carray, CREATE, TRUNCATE_EXISTING); // write((new File("X.class")).toPath(), carray, CREATE, TRUNCATE_EXISTING);
// verify using javap/classfile reader // verify using javap/classfile reader
ClassFile cf = ClassFile.read(new ByteArrayInputStream(carray)); ClassModel cm = ClassFile.of().parse(carray);
int mcount = checkMethod(cf, "foo"); int mcount = checkMethod(cm, "foo");
if (mcount < 1) { if (mcount < 1) {
throw new RuntimeException("unexpected method count, expected 1" + throw new RuntimeException("unexpected method count, expected 1" +
"but got " + mcount); "but got " + mcount);

View file

@ -25,17 +25,19 @@
* @test * @test
* @bug 8025636 * @bug 8025636
* @library /test/lib/ * @library /test/lib/
* @modules java.base/jdk.internal.org.objectweb.asm * @modules jdk.compiler
* jdk.compiler * @enablePreview
* @compile LambdaStackTrace.java * @compile LambdaStackTrace.java
* @run main LambdaStackTrace * @run main LambdaStackTrace
* @summary Synthetic frames should be hidden in exceptions * @summary Synthetic frames should be hidden in exceptions
*/ */
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.compiler.CompilerUtils;
import java.io.IOException; 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.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -43,10 +45,10 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT; import static java.lang.constant.ConstantDescs.CD_Object;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_INTERFACE; import static java.lang.constant.ConstantDescs.CD_String;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; import static java.lang.classfile.ClassFile.*;
import static jdk.internal.org.objectweb.asm.Opcodes.V1_7;
public class LambdaStackTrace { public class LambdaStackTrace {
@ -132,24 +134,27 @@ public class LambdaStackTrace {
// interface Maker { // interface Maker {
// Object make(); // Object make();
// } // }
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of("Maker"), clb -> clb
cw.visit(V1_7, ACC_INTERFACE | ACC_ABSTRACT, "Maker", null, "java/lang/Object", null); .withVersion(JAVA_7_VERSION, 0)
cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "make", .withFlags(ACC_INTERFACE | ACC_ABSTRACT)
"()Ljava/lang/Object;", null, null); .withSuperclass(CD_Object)
cw.visitEnd(); .withMethod("make", MethodTypeDesc.of(CD_Object),
return cw.toByteArray(); ACC_PUBLIC | ACC_ABSTRACT, mb -> {})
);
} }
private static byte[] generateStringMaker() { private static byte[] generateStringMaker() {
// interface StringMaker extends Maker { // interface StringMaker extends Maker {
// String make(); // String make();
// } // }
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(ClassDesc.of("StringMaker"), clb -> clb
cw.visit(V1_7, ACC_INTERFACE | ACC_ABSTRACT, "StringMaker", null, "java/lang/Object", new String[]{"Maker"}); .withVersion(JAVA_7_VERSION, 0)
cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "make", .withFlags(ACC_INTERFACE | ACC_ABSTRACT)
"()Ljava/lang/String;", null, null); .withSuperclass(CD_Object)
cw.visitEnd(); .withInterfaceSymbols(ClassDesc.of("Maker"))
return cw.toByteArray(); .withMethod("make", MethodTypeDesc.of(CD_String),
ACC_PUBLIC | ACC_ABSTRACT, mb -> {})
);
} }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,18 +24,27 @@
/* @test /* @test
* @bug 8032400 * @bug 8032400
* @summary JSR292: invokeSpecial: InternalError attempting to lookup a method * @summary JSR292: invokeSpecial: InternalError attempting to lookup a method
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @compile -XDignore.symbol.file SpecialStatic.java * @compile -XDignore.symbol.file SpecialStatic.java
* @run testng test.java.lang.invoke.lookup.SpecialStatic * @run testng test.java.lang.invoke.lookup.SpecialStatic
*/ */
package test.java.lang.invoke.lookup; 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.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import jdk.internal.org.objectweb.asm.*; import java.lang.reflect.AccessFlag;
import org.testng.annotations.*; 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.*; import static org.testng.Assert.*;
/** /**
@ -72,6 +81,12 @@ public class SpecialStatic {
private static ClassLoader cl = new CustomClassLoader(); private static ClassLoader cl = new CustomClassLoader();
private static Class t1, t3; 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 { static {
try { try {
t1 = cl.loadClass("T1"); t1 = cl.loadClass("T1");
@ -103,93 +118,60 @@ public class SpecialStatic {
} }
public static byte[] dumpT1() { public static byte[] dumpT1() {
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(CD_T1, clb -> {
MethodVisitor mv; clb.withSuperclass(CD_Object);
clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
cw.visit(52, ACC_PUBLIC + ACC_SUPER, "T1", null, "java/lang/Object", null); clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> {
cob.aload(0);
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
mv.visitCode(); cob.return_();
mv.visitVarInsn(ALOAD, 0); });
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); clb.withMethodBody(METHOD_NAME, MTD_int, ACC_PUBLIC, cob -> {
mv.visitInsn(RETURN); cob.bipush(1);
mv.visitMaxs(1, 1); cob.ireturn();
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();
} }
public static byte[] dumpT2() { public static byte[] dumpT2() {
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(CD_T2, clb -> {
MethodVisitor mv; clb.withSuperclass(CD_T1);
clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
cw.visit(52, ACC_PUBLIC + ACC_SUPER, "T2", null, "T1", null); clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> {
cob.aload(0);
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); cob.invokespecial(CD_T1, INIT_NAME, MTD_void);
mv.visitCode(); cob.return_();
mv.visitVarInsn(ALOAD, 0); });
mv.visitMethodInsn(INVOKESPECIAL, "T1", "<init>", "()V", false); clb.withMethodBody(METHOD_NAME, MTD_int, ACC_PUBLIC | ACC_STATIC, cob -> {
mv.visitInsn(RETURN); cob.bipush(2);
mv.visitMaxs(1, 1); cob.ireturn();
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();
} }
public static byte[] dumpT3() { public static byte[] dumpT3() {
ClassWriter cw = new ClassWriter(0); return ClassFile.of().build(CD_T3, clb -> {
MethodVisitor mv; clb.withSuperclass(CD_T2);
clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
cw.visit(52, ACC_PUBLIC + ACC_SUPER, "T3", null, "T2", null); clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> {
cob.aload(0);
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); cob.invokespecial(CD_T2, INIT_NAME, MTD_void);
mv.visitCode(); cob.return_();
mv.visitVarInsn(ALOAD, 0); });
mv.visitMethodInsn(INVOKESPECIAL, "T2", "<init>", "()V", false); clb.withMethodBody(METHOD_NAME, MTD_int, ACC_PUBLIC, cob -> {
mv.visitInsn(RETURN); cob.bipush(3);
mv.visitMaxs(1, 1); cob.ireturn();
mv.visitEnd(); });
clb.withMethodBody("getMethodHandle", MethodTypeDesc.of(CD_MethodHandle),
mv = cw.visitMethod(ACC_PUBLIC, "m", "()I", null, null); ACC_PUBLIC | ACC_STATIC, cob -> {
mv.visitCode(); cob.constantInstruction(MethodHandleDesc.ofMethod(SPECIAL, CD_T1, METHOD_NAME, MTD_int));
mv.visitIntInsn(BIPUSH, 3); cob.areturn();
mv.visitInsn(IRETURN); });
mv.visitMaxs(1, 1); clb.withMethodBody("getLookup", MTD_Lookup,
mv.visitEnd(); ACC_PUBLIC | ACC_STATIC, cob -> {
cob.invokestatic(CD_MethodHandles, "lookup", MTD_Lookup);
// getMethodHandle cob.areturn();
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();
} }
} }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,15 +26,21 @@
* @bug 8026213 * @bug 8026213
* @summary Reflection support for private methods in interfaces * @summary Reflection support for private methods in interfaces
* @author Robert Field * @author Robert Field
* @modules java.base/jdk.internal.org.objectweb.asm * @enablePreview
* @run main TestPrivateInterfaceMethodReflect * @run main TestPrivateInterfaceMethodReflect
*/ */
import java.lang.classfile.ClassFile;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.lang.reflect.*; import java.lang.reflect.*;
import jdk.internal.org.objectweb.asm.ClassWriter; import static java.lang.classfile.ClassFile.ACC_PRIVATE;
import jdk.internal.org.objectweb.asm.MethodVisitor; import static java.lang.classfile.ClassFile.ACC_PUBLIC;
import jdk.internal.org.objectweb.asm.Opcodes; 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 { public class TestPrivateInterfaceMethodReflect {
@ -42,10 +48,10 @@ public class TestPrivateInterfaceMethodReflect {
static final String CLASS_NAME = "PrivateInterfaceMethodReflectTest_Class"; static final String CLASS_NAME = "PrivateInterfaceMethodReflectTest_Class";
static final int EXPECTED = 1234; static final int EXPECTED = 1234;
static class TestClassLoader extends ClassLoader implements Opcodes { static class TestClassLoader extends ClassLoader {
@Override @Override
public Class findClass(String name) throws ClassNotFoundException { public Class<?> findClass(String name) throws ClassNotFoundException {
byte[] b; byte[] b;
try { try {
b = loadClassData(name); b = loadClassData(name);
@ -56,39 +62,28 @@ public class TestPrivateInterfaceMethodReflect {
return defineClass(name, b, 0, b.length); return defineClass(name, b, 0, b.length);
} }
private byte[] loadClassData(String name) throws Exception { private byte[] loadClassData(String name) {
ClassWriter cw = new ClassWriter(0); return switch (name) {
MethodVisitor mv; case INTERFACE_NAME -> ClassFile.of().build(ClassDesc.ofInternalName(INTERFACE_NAME), clb -> {
switch (name) { clb.withFlags(AccessFlag.ABSTRACT, AccessFlag.INTERFACE, AccessFlag.PUBLIC);
case INTERFACE_NAME: clb.withSuperclass(CD_Object);
cw.visit(V1_8, ACC_ABSTRACT | ACC_INTERFACE | ACC_PUBLIC, INTERFACE_NAME, null, "java/lang/Object", null); clb.withMethodBody("privInstance", MethodTypeDesc.of(CD_int), ACC_PRIVATE, cob -> {
{ cob.constantInstruction(EXPECTED);
mv = cw.visitMethod(ACC_PRIVATE, "privInstance", "()I", null, null); cob.ireturn();
mv.visitCode(); });
mv.visitLdcInsn(EXPECTED); });
mv.visitInsn(IRETURN); case CLASS_NAME -> ClassFile.of().build(ClassDesc.of(CLASS_NAME), clb -> {
mv.visitMaxs(1, 1); clb.withFlags(AccessFlag.PUBLIC);
mv.visitEnd(); clb.withSuperclass(CD_Object);
} clb.withInterfaceSymbols(ClassDesc.ofInternalName(INTERFACE_NAME));
break; clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> {
case CLASS_NAME: cob.aload(0);
cw.visit(52, ACC_SUPER | ACC_PUBLIC, CLASS_NAME, null, "java/lang/Object", new String[]{INTERFACE_NAME}); cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
{ cob.return_();
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); });
mv.visitCode(); });
mv.visitVarInsn(ALOAD, 0); default -> throw new IllegalArgumentException();
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); };
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
break;
default:
break;
}
cw.visitEnd();
return cw.toByteArray();
} }
} }
@ -96,7 +91,7 @@ public class TestPrivateInterfaceMethodReflect {
TestClassLoader tcl = new TestClassLoader(); TestClassLoader tcl = new TestClassLoader();
Class<?> itf = tcl.loadClass(INTERFACE_NAME); Class<?> itf = tcl.loadClass(INTERFACE_NAME);
Class<?> k = tcl.loadClass(CLASS_NAME); Class<?> k = tcl.loadClass(CLASS_NAME);
Object inst = k.newInstance(); Object inst = k.getDeclaredConstructor().newInstance();
Method[] meths = itf.getDeclaredMethods(); Method[] meths = itf.getDeclaredMethods();
if (meths.length != 1) { if (meths.length != 1) {
throw new Exception("Expected one method in " + INTERFACE_NAME + " instead " + meths.length); throw new Exception("Expected one method in " + INTERFACE_NAME + " instead " + meths.length);

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,23 +25,27 @@
* @test * @test
* @bug 8255560 * @bug 8255560
* @summary Class::isRecord should check that the current class is final and not abstract * @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 * @library /test/lib
* @run testng/othervm IsRecordTest * @run testng/othervm IsRecordTest
* @run testng/othervm/java.security.policy=allPermissions.policy IsRecordTest * @run testng/othervm/java.security.policy=allPermissions.policy IsRecordTest
*/ */
import java.io.IOException; import java.lang.classfile.ClassFile;
import java.io.UncheckedIOException; import java.lang.constant.ClassDesc;
import java.lang.reflect.AccessFlag;
import java.util.List; import java.util.List;
import java.util.Map; 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 jdk.test.lib.ByteCodeLoader;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import static java.lang.System.out; 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.assertEquals;
import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue; 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 ---" out.println("\n--- testDirectSubClass isFinal=%s, isAbstract=%s, extendsJLR=%s, withRecordAttr=%s, expectIsRecord=%s ---"
.formatted(isFinal, isAbstract, extendsJLR, withRecordAttr, expectIsRecord)); .formatted(isFinal, isAbstract, extendsJLR, withRecordAttr, expectIsRecord));
List<RecordComponentEntry> rc = null; List<RecordComponentInfo> rc = null;
if (withRecordAttr) 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"; String superName = extendsJLR ? "java/lang/Record" : "java/lang/Object";
var classBytes = generateClassBytes("C", isFinal, isAbstract, superName, rc); var classBytes = generateClassBytes("C", isFinal, isAbstract, superName, rc);
Class<?> cls = ByteCodeLoader.load("C", classBytes); Class<?> cls = ByteCodeLoader.load("C", classBytes);
@ -109,9 +113,9 @@ public class IsRecordTest {
out.println("\n--- testIndirectSubClass isFinal=%s, isAbstract=%s withRecordAttr=%s ---" out.println("\n--- testIndirectSubClass isFinal=%s, isAbstract=%s withRecordAttr=%s ---"
.formatted(isFinal, isAbstract, withRecordAttr)); .formatted(isFinal, isAbstract, withRecordAttr));
List<RecordComponentEntry> rc = null; List<RecordComponentInfo> rc = null;
if (withRecordAttr) 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 supFooClassBytes = generateClassBytes("SupFoo", false, isAbstract, "java/lang/Record", rc);
var subFooClassBytes = generateClassBytes("SubFoo", isFinal, isAbstract, "SupFoo", rc); var subFooClassBytes = generateClassBytes("SubFoo", isFinal, isAbstract, "SupFoo", rc);
var allClassBytes = Map.of("SupFoo", supFooClassBytes, var allClassBytes = Map.of("SupFoo", supFooClassBytes,
@ -161,29 +165,18 @@ public class IsRecordTest {
boolean isFinal, boolean isFinal,
boolean isAbstract, boolean isAbstract,
String superName, String superName,
List<RecordComponentEntry> components) { List<RecordComponentInfo> components) {
ClassWriter cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES); return ClassFile.of().build(ClassDesc.ofInternalName(className), clb -> {
int access = 0;
int access = 0; if (isFinal)
if (isFinal) access = access | ACC_FINAL;
access = access | Opcodes.ACC_FINAL; if (isAbstract)
if (isAbstract) access = access | ACC_ABSTRACT;
access = access | Opcodes.ACC_ABSTRACT; clb.withFlags(access);
clb.withSuperclass(ClassDesc.ofInternalName(superName));
cw.visit(Opcodes.V16, if (components != null)
access, clb.accept(RecordAttribute.of(components));
className, });
null,
superName,
null);
if (components != null)
components.forEach(rc -> cw.visitRecordComponent(rc.name(), rc.descriptor(), null));
cw.visitEnd();
return cw.toByteArray();
} }
record RecordComponentEntry (String name, String descriptor) { }
} }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,16 +24,20 @@
/** /**
* @test * @test
* @library /test/lib * @library /test/lib
* @modules java.base/jdk.internal.org.objectweb.asm * @modules jdk.compiler
* jdk.compiler * @enablePreview
* @build jdk.test.lib.compiler.CompilerUtils * @build jdk.test.lib.compiler.CompilerUtils
* @run testng/othervm BadProvidersTest * @run testng/othervm BadProvidersTest
* @summary Basic test of ServiceLoader with bad provider and bad provider * @summary Basic test of ServiceLoader with bad provider and bad provider
* factories deployed on the module path * 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.Configuration;
import java.lang.module.ModuleFinder; import java.lang.module.ModuleFinder;
import java.lang.reflect.AccessFlag;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -45,14 +49,17 @@ import java.util.ServiceLoader.Provider;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; 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 jdk.test.lib.compiler.CompilerUtils;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import org.testng.annotations.DataProvider; 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.*; import static org.testng.Assert.*;
/** /**
@ -207,55 +214,36 @@ public class BadProvidersTest {
public void testWithTwoFactoryMethods() throws Exception { public void testWithTwoFactoryMethods() throws Exception {
Path mods = compileTest(TEST1_MODULE); Path mods = compileTest(TEST1_MODULE);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS var bytes = ClassFile.of().build(ClassDesc.of("p", "ProviderFactory"), clb -> {
+ ClassWriter.COMPUTE_FRAMES); clb.withSuperclass(CD_Object);
cw.visit(V9, clb.withFlags(AccessFlag.PUBLIC, AccessFlag.SUPER);
ACC_PUBLIC + ACC_SUPER,
"p/ProviderFactory",
null,
"java/lang/Object",
null);
// public static p.Service provider() var providerFactory$1 = ClassDesc.of("p", "ProviderFactory$1");
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",
"<init>", "()V",
false);
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
// public static p.ProviderFactory$1 provider() // public static p.Service provider()
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, clb.withMethodBody("provider", MethodTypeDesc.of(ClassDesc.of("p", "Service")),
"provider", ACC_PUBLIC | ACC_STATIC, cob -> {
"()Lp/ProviderFactory$1;", cob.new_(providerFactory$1);
null, cob.dup();
null); cob.invokespecial(providerFactory$1, INIT_NAME, MTD_void);
mv.visitTypeInsn(NEW, "p/ProviderFactory$1"); cob.areturn();
mv.visitInsn(DUP); });
mv.visitMethodInsn(INVOKESPECIAL,
"p/ProviderFactory$1",
"<init>",
"()V",
false);
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
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 // write the class bytes into the compiled module directory
Path classFile = mods.resolve(TEST1_MODULE) Path classFile = mods.resolve(TEST1_MODULE)
.resolve("p") .resolve("p")
.resolve("ProviderFactory.class"); .resolve("ProviderFactory.class");
Files.write(classFile, cw.toByteArray()); Files.write(classFile, bytes);
// load providers and instantiate each one // load providers and instantiate each one
loadProviders(mods, TEST1_MODULE).forEach(Provider::get); loadProviders(mods, TEST1_MODULE).forEach(Provider::get);