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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,7 @@
* @summary InvalidClassException is thrown when the canonical constructor
* cannot be found during deserialization.
* @library /test/lib
* @modules java.base/jdk.internal.org.objectweb.asm
* @enablePreview
* @run testng BadCanonicalCtrTest
*/
@ -38,19 +38,22 @@ import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import java.lang.classfile.ClassTransform;
import java.lang.classfile.ClassFile;
import java.lang.classfile.MethodModel;
import java.lang.constant.MethodTypeDesc;
import jdk.test.lib.compiler.InMemoryJavaCompiler;
import jdk.test.lib.ByteCodeLoader;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.lang.System.out;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_MAXS;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import static java.lang.classfile.ClassFile.ACC_PUBLIC;
import static java.lang.constant.ConstantDescs.CD_Object;
import static java.lang.constant.ConstantDescs.CD_void;
import static java.lang.constant.ConstantDescs.INIT_NAME;
import static java.lang.constant.ConstantDescs.MTD_void;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.expectThrows;
@ -203,33 +206,9 @@ public class BadCanonicalCtrTest {
* Assumes just a single, canonical, constructor.
*/
static byte[] removeConstructor(byte[] classBytes) {
ClassReader reader = new ClassReader(classBytes);
ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES);
reader.accept(new RemoveCanonicalCtrVisitor(writer), 0);
return writer.toByteArray();
}
/** Removes the <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);
}
}
var cf = ClassFile.of();
return cf.transform(cf.parse(classBytes), ClassTransform.dropping(ce ->
ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)));
}
/**
@ -237,55 +216,15 @@ public class BadCanonicalCtrTest {
* Assumes just a single, canonical, constructor.
*/
static byte[] modifyConstructor(byte[] classBytes) {
ClassReader reader = new ClassReader(classBytes);
ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES);
reader.accept(new ModifyCanonicalCtrVisitor(writer), 0);
return writer.toByteArray();
}
/** Replaces whatever <init> method it finds with <init>(Ljava/lang/Object;)V. */
static class ModifyCanonicalCtrVisitor extends ClassVisitor {
ModifyCanonicalCtrVisitor(ClassVisitor cv) {
super(ASM8, cv);
}
boolean foundCanonicalCtr;
String className;
@Override
public void visit(final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
this.className = name;
cv.visit(version, access, name, signature, superName, interfaces);
}
@Override
public MethodVisitor visitMethod(final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
if (name.equals("<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();
}
var cf = ClassFile.of();
return cf.transform(cf.parse(classBytes), ClassTransform.dropping(ce ->
ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME))
.andThen(ClassTransform.endHandler(clb -> clb.withMethodBody(INIT_NAME,
MethodTypeDesc.of(CD_void, CD_Object), ACC_PUBLIC, cob -> {
cob.aload(0);
cob.invokespecial(Record.class.describeConstable().orElseThrow(),
INIT_NAME, MTD_void);
cob.return_();
}))));
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,7 @@
* @bug 8246774
* @summary Basic tests for prohibited magic serialization methods
* @library /test/lib
* @modules java.base/jdk.internal.org.objectweb.asm
* @enablePreview
* @run testng ProhibitedMethods
*/
@ -41,23 +41,23 @@ import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.classfile.ClassTransform;
import java.lang.classfile.ClassFile;
import java.lang.constant.MethodTypeDesc;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.function.Function;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.test.lib.compiler.InMemoryJavaCompiler;
import jdk.test.lib.ByteCodeLoader;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.lang.System.out;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_MAXS;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import static java.lang.classfile.ClassFile.ACC_PRIVATE;
import static java.lang.constant.ConstantDescs.CD_String;
import static java.lang.constant.ConstantDescs.CD_void;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.expectThrows;
@ -219,103 +219,38 @@ public class ProhibitedMethods {
// -- machinery for augmenting record classes with prohibited serial methods --
static final String WRITE_OBJECT_NAME = "writeObject";
static final MethodTypeDesc WRITE_OBJECT_DESC = MethodTypeDesc.ofDescriptor("(Ljava/io/ObjectOutputStream;)V");
static byte[] addWriteObject(byte[] classBytes) {
return addMethod(classBytes, cv -> new WriteObjectVisitor(cv));
return addMethod(classBytes, WRITE_OBJECT_NAME, WRITE_OBJECT_DESC);
}
static final String READ_OBJECT_NAME = "readObject";
static final MethodTypeDesc READ_OBJECT_DESC = MethodTypeDesc.ofDescriptor("(Ljava/io/ObjectInputStream;)V");
static byte[] addReadObject(byte[] classBytes) {
return addMethod(classBytes, cv -> new ReadObjectVisitor(cv));
return addMethod(classBytes, READ_OBJECT_NAME, READ_OBJECT_DESC);
}
static final String READ_OBJECT_NO_DATA_NAME = "readObjectNoData";
static final MethodTypeDesc READ_OBJECT_NO_DATA_DESC = MethodTypeDesc.of(CD_void);
static byte[] addReadObjectNoData(byte[] classBytes) {
return addMethod(classBytes, cv -> new ReadObjectNoDataVisitor(cv));
return addMethod(classBytes, READ_OBJECT_NO_DATA_NAME, READ_OBJECT_NO_DATA_DESC);
}
static byte[] addMethod(byte[] classBytes,
Function<ClassVisitor,ClassVisitor> classVisitorCreator) {
ClassReader reader = new ClassReader(classBytes);
ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES);
reader.accept(classVisitorCreator.apply(writer), 0);
return writer.toByteArray();
}
static abstract class AbstractVisitor extends ClassVisitor {
final String nameOfMethodToAdd;
AbstractVisitor(ClassVisitor cv, String nameOfMethodToAdd) {
super(ASM8, cv);
this.nameOfMethodToAdd = nameOfMethodToAdd;
}
@Override
public MethodVisitor visitMethod(final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
// the method-to-be-added should not already exist
assert !name.equals(nameOfMethodToAdd) : "Unexpected " + name + " method";
return cv.visitMethod(access, name, descriptor, signature, exceptions);
}
@Override
public void visitEnd() {
throw new UnsupportedOperationException("implement me");
}
}
/** A visitor that generates and adds a writeObject method. */
static final class WriteObjectVisitor extends AbstractVisitor {
static final String WRITE_OBJECT_NAME = "writeObject";
static final String WRITE_OBJECT_DESC = "(Ljava/io/ObjectOutputStream;)V";
WriteObjectVisitor(ClassVisitor cv) { super(cv, WRITE_OBJECT_NAME); }
@Override
public void visitEnd() {
MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, WRITE_OBJECT_NAME, WRITE_OBJECT_DESC, null, null);
mv.visitCode();
mv.visitLdcInsn(WRITE_OBJECT_NAME + " should not be invoked");
mv.visitMethodInsn(INVOKESTATIC, "org/testng/Assert", "fail", "(Ljava/lang/String;)V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
cv.visitEnd();
}
}
/** A visitor that generates and adds a readObject method. */
static final class ReadObjectVisitor extends AbstractVisitor {
static final String READ_OBJECT_NAME = "readObject";
static final String READ_OBJECT_DESC = "(Ljava/io/ObjectInputStream;)V";
ReadObjectVisitor(ClassVisitor cv) { super(cv, READ_OBJECT_NAME); }
@Override
public void visitEnd() {
MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, READ_OBJECT_NAME, READ_OBJECT_DESC, null, null);
mv.visitCode();
mv.visitLdcInsn(READ_OBJECT_NAME + " should not be invoked");
mv.visitMethodInsn(INVOKESTATIC, "org/testng/Assert", "fail", "(Ljava/lang/String;)V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
cv.visitEnd();
}
}
/** A visitor that generates and adds a readObjectNoData method. */
static final class ReadObjectNoDataVisitor extends AbstractVisitor {
static final String READ_OBJECT_NO_DATA_NAME = "readObjectNoData";
static final String READ_OBJECT_NO_DATA_DESC = "()V";
ReadObjectNoDataVisitor(ClassVisitor cv) { super(cv, READ_OBJECT_NO_DATA_NAME); }
@Override
public void visitEnd() {
MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, READ_OBJECT_NO_DATA_NAME, READ_OBJECT_NO_DATA_DESC, null, null);
mv.visitCode();
mv.visitLdcInsn(READ_OBJECT_NO_DATA_NAME + " should not be invoked");
mv.visitMethodInsn(INVOKESTATIC, "org/testng/Assert", "fail", "(Ljava/lang/String;)V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
cv.visitEnd();
}
String name, MethodTypeDesc desc) {
var cf = ClassFile.of();
return cf.transform(cf.parse(classBytes), ClassTransform.endHandler(clb -> {
clb.withMethodBody(name, desc, ACC_PRIVATE, cob -> {
cob.constantInstruction(name + " should not be invoked");
cob.invokestatic(Assert.class.describeConstable().orElseThrow(), "fail",
MethodTypeDesc.of(CD_void, CD_String));
cob.return_();
});
}));
}
// -- infra sanity --

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,7 @@
* @bug 8246774
* @summary Basic tests for prohibited magic serialPersistentFields
* @library /test/lib
* @modules java.base/jdk.internal.org.objectweb.asm
* @enablePreview
* @run testng SerialPersistentFieldsTest
*/
@ -38,23 +38,34 @@ import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.ObjectStreamField;
import java.io.Serializable;
import java.lang.classfile.ClassBuilder;
import java.lang.classfile.ClassElement;
import java.lang.classfile.ClassTransform;
import java.lang.classfile.ClassFile;
import java.lang.classfile.FieldModel;
import java.lang.constant.ClassDesc;
import java.lang.constant.ConstantDescs;
import java.lang.constant.DynamicConstantDesc;
import java.lang.constant.MethodTypeDesc;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Type;
import jdk.test.lib.ByteCodeLoader;
import jdk.test.lib.compiler.InMemoryJavaCompiler;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.lang.System.out;
import static jdk.internal.org.objectweb.asm.ClassWriter.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import static java.lang.classfile.ClassFile.ACC_FINAL;
import static java.lang.classfile.ClassFile.ACC_PRIVATE;
import static java.lang.classfile.ClassFile.ACC_STATIC;
import static java.lang.constant.ConstantDescs.CD_Class;
import static java.lang.constant.ConstantDescs.CD_String;
import static java.lang.constant.ConstantDescs.CD_void;
import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME;
import static java.lang.constant.ConstantDescs.INIT_NAME;
import static java.lang.constant.ConstantDescs.MTD_void;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@ -218,105 +229,62 @@ public class SerialPersistentFieldsTest {
static byte[] addSerialPersistentFields(byte[] classBytes,
ObjectStreamField[] spf) {
ClassReader reader = new ClassReader(classBytes);
ClassWriter writer = new ClassWriter(reader, COMPUTE_MAXS | COMPUTE_FRAMES);
reader.accept(new SerialPersistentFieldsVisitor(writer, spf), 0);
return writer.toByteArray();
var cf = ClassFile.of();
var model = cf.parse(classBytes);
return cf.transform(model, new SerialPersistentFieldsVisitor(model.thisClass().asSymbol(), spf));
}
/** A visitor that adds a serialPersistentFields field, and assigns it in clinit. */
static final class SerialPersistentFieldsVisitor extends ClassVisitor {
static final class SerialPersistentFieldsVisitor implements ClassTransform {
static final String FIELD_NAME = "serialPersistentFields";
static final String FIELD_DESC = "[Ljava/io/ObjectStreamField;";
static final ClassDesc CD_ObjectStreamField = ObjectStreamField.class.describeConstable().orElseThrow();
static final ClassDesc FIELD_DESC = CD_ObjectStreamField.arrayType();
final ObjectStreamField[] spf;
String className;
SerialPersistentFieldsVisitor(ClassVisitor cv, ObjectStreamField[] spf) {
super(ASM8, cv);
final ClassDesc className;
SerialPersistentFieldsVisitor(ClassDesc className, ObjectStreamField[] spf) {
this.className = className;
this.spf = spf;
}
@Override
public void visit(final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
this.className = name;
cv.visit(version, access, name, signature, superName, interfaces);
}
@Override
public FieldVisitor visitField(final int access,
final String name,
final String descriptor,
final String signature,
final Object value) {
// the field-to-be-added should not already exist
assert !name.equals("serialPersistentFields") : "Unexpected " + name + " field";
return cv.visitField(access, name, descriptor, signature, value);
}
@Override
public void visitEnd() {
{
FieldVisitor fv = cv.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL,
FIELD_NAME,
FIELD_DESC,
null,
null);
fv.visitEnd();
public void accept(ClassBuilder builder, ClassElement element) {
if (element instanceof FieldModel fieldModel) {
var name = fieldModel.fieldName().stringValue();
assert !name.equals(FIELD_NAME) : "Unexpected " + FIELD_NAME + " field";
builder.accept(fieldModel);
} else {
builder.accept(element);
}
{
MethodVisitor mv = cv.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
mv.visitCode();
mv.visitIntInsn(BIPUSH, spf.length);
mv.visitTypeInsn(ANEWARRAY, "java/io/ObjectStreamField");
}
@Override
public void atEnd(ClassBuilder builder) {
builder.withField(FIELD_NAME, FIELD_DESC, ACC_PRIVATE | ACC_STATIC | ACC_FINAL);
builder.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, cob -> {
cob.bipush(spf.length);
cob.anewarray(CD_ObjectStreamField);
for (int i = 0; i < spf.length; i++) {
ObjectStreamField osf = spf[i];
mv.visitInsn(DUP);
mv.visitIntInsn(BIPUSH, i);
mv.visitTypeInsn(NEW, "java/io/ObjectStreamField");
mv.visitInsn(DUP);
mv.visitLdcInsn(osf.getName());
if (osf.getType().isPrimitive()) {
mv.visitFieldInsn(GETSTATIC, getPrimitiveBoxClass(osf.getType()), "TYPE", "Ljava/lang/Class;");
cob.dup();
cob.bipush(i);
cob.new_(CD_ObjectStreamField);
cob.dup();
cob.constantInstruction(osf.getName());
if (osf.isPrimitive()) {
cob.constantInstruction(DynamicConstantDesc.ofNamed(
ConstantDescs.BSM_PRIMITIVE_CLASS, String.valueOf(osf.getTypeCode()), CD_Class));
} else {
mv.visitLdcInsn(Type.getType(osf.getType()));
// Currently Classfile API cannot encode primitive classdescs as condy
cob.constantInstruction(osf.getType().describeConstable().orElseThrow());
}
mv.visitMethodInsn(INVOKESPECIAL, "java/io/ObjectStreamField", "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V", false);
mv.visitInsn(AASTORE);
cob.invokespecial(CD_ObjectStreamField, INIT_NAME, MethodTypeDesc.of(CD_void, CD_String, CD_Class));
cob.aastore();
}
mv.visitFieldInsn(PUTSTATIC, className, "serialPersistentFields", "[Ljava/io/ObjectStreamField;");
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
cv.visitEnd();
}
static String getPrimitiveBoxClass(final Class<?> clazz) {
if (!clazz.isPrimitive())
throw new AssertionError("unexpected non-primitive:" + clazz);
if (clazz == Integer.TYPE) {
return "java/lang/Integer";
} else if (clazz == Boolean.TYPE) {
return "java/lang/Boolean";
} else if (clazz == Byte.TYPE) {
return "java/lang/Byte";
} else if (clazz == Character.TYPE) {
return "java/lang/Character";
} else if (clazz == Short.TYPE) {
return "java/lang/Short";
} else if (clazz == Double.TYPE) {
return "java/lang/Double";
} else if (clazz == Float.TYPE) {
return "java/lang/Float";
} else if (clazz == Long.TYPE) {
return "java/lang/Long";
} else {
throw new AssertionError("unknown:" + clazz);
}
cob.putstatic(className, FIELD_NAME, FIELD_DESC);
cob.return_();
});
}
}

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

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

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

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

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

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -39,8 +39,8 @@ import java.util.stream.Stream;
* @test
* @bug 8158510
* @summary Verify valid annotation
* @modules java.base/jdk.internal.org.objectweb.asm
* @modules java.base/sun.reflect.annotation
* @enablePreview
* @clean AnnotationWithVoidReturn AnnotationWithParameter
* AnnotationWithExtraInterface AnnotationWithException
* AnnotationWithHashCode AnnotationWithDefaultMember

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,18 +22,39 @@
*/
/*
* Create class file using ASM, slightly modified the ASMifier output
* Create class file using Class-File API, slightly modified the ASMifier output
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import jdk.internal.org.objectweb.asm.*;
import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.classfile.Annotation;
import java.lang.classfile.AnnotationElement;
import java.lang.classfile.AnnotationValue;
import java.lang.classfile.ClassFile;
import java.lang.classfile.attribute.AnnotationDefaultAttribute;
import java.lang.classfile.attribute.ExceptionsAttribute;
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.lang.reflect.AccessFlag;
import static java.lang.classfile.ClassFile.ACC_ABSTRACT;
import static java.lang.classfile.ClassFile.ACC_PUBLIC;
import static java.lang.constant.ConstantDescs.CD_Exception;
import static java.lang.constant.ConstantDescs.CD_Object;
import static java.lang.constant.ConstantDescs.CD_int;
import static java.lang.constant.ConstantDescs.MTD_void;
import static java.lang.reflect.AccessFlag.ABSTRACT;
import static java.lang.reflect.AccessFlag.INTERFACE;
import static java.lang.reflect.AccessFlag.PUBLIC;
public class ClassFileGenerator {
private static final ClassDesc CD_Annotation = java.lang.annotation.Annotation.class.describeConstable().orElseThrow();
private static final ClassDesc CD_Retention = Retention.class.describeConstable().orElseThrow();
public static void main(String... args) throws Exception {
classFileWriter("AnnotationWithVoidReturn.class", AnnotationWithVoidReturnDump.dump());
@ -63,35 +84,19 @@ public class ClassFileGenerator {
*/
private static class AnnotationWithVoidReturnDump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
"AnnotationWithVoidReturn", null,
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
{
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
"RUNTIME");
av0.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()V", null, null);
mv.visitEnd();
}
{
av0 = mv.visitAnnotationDefault();
av0.visit(null, new Integer(1));
av0.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
private static class AnnotationWithVoidReturnDump {
public static byte[] dump() {
return ClassFile.of().build(ClassDesc.of("AnnotationWithVoidReturn"), clb -> {
clb.withSuperclass(CD_Object);
clb.withInterfaceSymbols(CD_Annotation);
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
clb.with(RuntimeVisibleAnnotationsAttribute.of(
Annotation.of(CD_Retention, AnnotationElement.of("value",
AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
clb.withMethod("m", MTD_void, ACC_PUBLIC | ACC_ABSTRACT,
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
});
}
}
@ -104,38 +109,19 @@ public class ClassFileGenerator {
*/
private static class AnnotationWithParameterDump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
"AnnotationWithParameter", null,
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
{
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
"RUNTIME");
av0.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT,
"badValue",
"(I)I", // Bad method with a parameter
null, null);
mv.visitEnd();
}
{
av0 = mv.visitAnnotationDefault();
av0.visit(null, new Integer(-1));
av0.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
private static class AnnotationWithParameterDump {
public static byte[] dump() {
return ClassFile.of().build(ClassDesc.of("AnnotationWithParameter"), clb -> {
clb.withSuperclass(CD_Object);
clb.withInterfaceSymbols(CD_Annotation);
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
clb.with(RuntimeVisibleAnnotationsAttribute.of(
Annotation.of(CD_Retention, AnnotationElement.of("value",
AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
clb.withMethod("m", MethodTypeDesc.of(CD_int, CD_int), ACC_PUBLIC | ACC_ABSTRACT,
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(-1))));
});
}
}
@ -148,35 +134,19 @@ public class ClassFileGenerator {
*/
private static class AnnotationWithExtraInterfaceDump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
"AnnotationWithExtraInterface", null,
"java/lang/Object", new String[]{"java/lang/annotation/Annotation",
"java/io/Serializable"});
{
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
"RUNTIME");
av0.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
mv.visitEnd();
}
{
av0 = mv.visitAnnotationDefault();
av0.visit(null, new Integer(1));
av0.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
private static class AnnotationWithExtraInterfaceDump {
public static byte[] dump() {
return ClassFile.of().build(ClassDesc.of("AnnotationWithExtraInterface"), clb -> {
clb.withSuperclass(CD_Object);
clb.withInterfaceSymbols(CD_Annotation, Serializable.class.describeConstable().orElseThrow());
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
clb.with(RuntimeVisibleAnnotationsAttribute.of(
Annotation.of(CD_Retention, AnnotationElement.of("value",
AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
});
}
}
@ -189,35 +159,21 @@ public class ClassFileGenerator {
*/
private static class AnnotationWithExceptionDump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
"AnnotationWithException", null,
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
{
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
"RUNTIME");
av0.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null,
new String[] {"java/lang/Exception"});
mv.visitEnd();
}
{
av0 = mv.visitAnnotationDefault();
av0.visit(null, new Integer(1));
av0.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
private static class AnnotationWithExceptionDump {
public static byte[] dump() {
return ClassFile.of().build(ClassDesc.of("AnnotationWithException"), clb -> {
clb.withSuperclass(CD_Object);
clb.withInterfaceSymbols(CD_Annotation);
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
clb.with(RuntimeVisibleAnnotationsAttribute.of(
Annotation.of(CD_Retention, AnnotationElement.of("value",
AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT, mb -> {
mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1)));
mb.with(ExceptionsAttribute.ofSymbols(CD_Exception));
});
});
}
}
@ -230,34 +186,19 @@ public class ClassFileGenerator {
*/
private static class AnnotationWithHashCodeDump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
"AnnotationWithHashCode", null,
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
{
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
"RUNTIME");
av0.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "hashCode", "()I", null, null);
mv.visitEnd();
}
{
av0 = mv.visitAnnotationDefault();
av0.visit(null, new Integer(1));
av0.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
private static class AnnotationWithHashCodeDump {
public static byte[] dump() {
return ClassFile.of().build(ClassDesc.of("AnnotationWithHashCode"), clb -> {
clb.withSuperclass(CD_Object);
clb.withInterfaceSymbols(CD_Annotation);
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
clb.with(RuntimeVisibleAnnotationsAttribute.of(
Annotation.of(CD_Retention, AnnotationElement.of("value",
AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
clb.withMethod("hashCode", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
});
}
}
@ -271,47 +212,26 @@ public class ClassFileGenerator {
*/
private static class AnnotationWithDefaultMemberDump implements Opcodes {
private static class AnnotationWithDefaultMemberDump {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv, dv;
AnnotationVisitor av0;
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
"AnnotationWithDefaultMember", null,
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
{
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
"RUNTIME");
av0.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
mv.visitEnd();
}
{
av0 = mv.visitAnnotationDefault();
av0.visit(null, new Integer(1));
av0.visitEnd();
}
{
dv = cw.visitMethod(ACC_PUBLIC, "d", "()I", null, null);
dv.visitMaxs(1, 1);
dv.visitCode();
dv.visitInsn(Opcodes.ICONST_2);
dv.visitInsn(Opcodes.IRETURN);
dv.visitEnd();
}
{
av0 = dv.visitAnnotationDefault();
av0.visit(null, new Integer(2));
av0.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
return ClassFile.of().build(ClassDesc.of("AnnotationWithDefaultMember"), clb -> {
clb.withSuperclass(CD_Object);
clb.withInterfaceSymbols(CD_Annotation);
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
clb.with(RuntimeVisibleAnnotationsAttribute.of(
Annotation.of(CD_Retention, AnnotationElement.of("value",
AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
clb.withMethod("d", MethodTypeDesc.of(CD_int), ACC_PUBLIC, mb -> {
mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(2)));
mb.withCode(cob -> {
cob.iconst_2();
cob.ireturn();
});
});
});
}
}
@ -324,34 +244,19 @@ public class ClassFileGenerator {
*/
private static class AnnotationWithoutAnnotationAccessModifierDump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(52, ACC_PUBLIC + /* ACC_ANNOTATION +*/ ACC_ABSTRACT + ACC_INTERFACE,
"AnnotationWithoutAnnotationAccessModifier", null,
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
{
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
"RUNTIME");
av0.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
mv.visitEnd();
}
{
av0 = mv.visitAnnotationDefault();
av0.visit(null, new Integer(1));
av0.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
private static class AnnotationWithoutAnnotationAccessModifierDump {
public static byte[] dump() {
return ClassFile.of().build(ClassDesc.of("AnnotationWithoutAnnotationAccessModifier"), clb -> {
clb.withSuperclass(CD_Object);
clb.withInterfaceSymbols(CD_Annotation);
clb.withFlags(PUBLIC, /*AccessFlag.ANNOTATION,*/ ABSTRACT, AccessFlag.INTERFACE);
clb.with(RuntimeVisibleAnnotationsAttribute.of(
Annotation.of(CD_Retention, AnnotationElement.of("value",
AnnotationValue.of(RetentionPolicy.RUNTIME)))
));
clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
});
}
}
@ -365,24 +270,16 @@ public class ClassFileGenerator {
*/
private static class HolderXDump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
cw.visit(52, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
"HolderX", null,
"java/lang/Object", new String[0]);
{
AnnotationVisitor av0;
av0 = cw.visitAnnotation("LGoodAnnotation;", true);
av0.visitEnd();
av0 = cw.visitAnnotation("LAnnotationWithoutAnnotationAccessModifier;", true);
av0.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
private static class HolderXDump {
public static byte[] dump() {
return ClassFile.of().build(ClassDesc.of("HolderX"), clb -> {
clb.withSuperclass(CD_Object);
clb.withFlags(PUBLIC, ABSTRACT, INTERFACE);
clb.with(RuntimeVisibleAnnotationsAttribute.of(
Annotation.of(ClassDesc.of("GoodAnnotation")),
Annotation.of(ClassDesc.of("ClassFileGenerator$AnnotationWithoutAnnotationAccessModifier"))
));
});
}
}
}

@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -87,7 +87,8 @@ ${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} bootreporter/*.java
cd ..
${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \
--add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED ${AGENT}.java asmlib/*.java
--enable-preview --release 23 \
${AGENT}.java asmlib/*.java
${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -classpath .${PATHSEP}bootpath ${APP}.java
echo "Manifest-Version: 1.0" > ${AGENT}.mf

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

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,171 +23,133 @@
package asmlib;
import java.io.PrintStream;
import java.lang.classfile.AccessFlags;
import java.lang.classfile.ClassBuilder;
import java.lang.classfile.ClassElement;
import java.lang.classfile.ClassModel;
import java.lang.classfile.ClassTransform;
import java.lang.classfile.ClassFile;
import java.lang.classfile.CodeBuilder;
import java.lang.classfile.CodeElement;
import java.lang.classfile.CodeModel;
import java.lang.classfile.CodeTransform;
import java.lang.classfile.MethodBuilder;
import java.lang.classfile.MethodElement;
import java.lang.classfile.MethodModel;
import java.lang.classfile.MethodTransform;
import java.lang.classfile.Opcode;
import java.lang.classfile.TypeKind;
import java.lang.constant.MethodTypeDesc;
import java.lang.reflect.AccessFlag;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import jdk.internal.org.objectweb.asm.Type;
import static java.lang.classfile.ClassFile.ACC_NATIVE;
public class Instrumentor {
public static class InstrHelper {
private final MethodVisitor mv;
private final String name;
InstrHelper(MethodVisitor mv, String name) {
this.mv = mv;
this.name = name;
}
public String getName() {
return this.name;
}
public void invokeStatic(String owner, String name, String desc, boolean itf) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf);
}
public void invokeSpecial(String owner, String name, String desc) {
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false);
}
public void invokeVirtual(String owner, String name, String desc) {
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false);
}
public void push(int val) {
if (val >= -1 && val <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + val);
} else if (val >= Byte.MIN_VALUE && val <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, val);
} else if (val >= Short.MIN_VALUE && val <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, val);
} else {
mv.visitLdcInsn(val);
}
}
public void push(Object val) {
mv.visitLdcInsn(val);
}
public void println(String s) {
mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(System.class), "out", Type.getDescriptor(PrintStream.class));
mv.visitLdcInsn(s);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(PrintStream.class), "println", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)), false);
}
}
public static Instrumentor instrFor(byte[] classData) {
return new Instrumentor(classData);
}
private final ClassReader cr;
private final ClassWriter output;
private ClassVisitor instrumentingVisitor = null;
private final AtomicInteger matches = new AtomicInteger(0);
private final ClassModel model;
private ClassTransform transform = ClassTransform.ACCEPT_ALL;
private final AtomicBoolean dirty = new AtomicBoolean(false);
private Instrumentor(byte[] classData) {
cr = new ClassReader(classData);
output = new ClassWriter(ClassWriter.COMPUTE_MAXS);
instrumentingVisitor = output;
model = ClassFile.of().parse(classData);
}
public synchronized Instrumentor addMethodEntryInjection(String methodName, Consumer<InstrHelper> injector) {
instrumentingVisitor = new ClassVisitor(Opcodes.ASM7, instrumentingVisitor) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if (name.equals(methodName)) {
matches.getAndIncrement();
mv = new MethodVisitor(Opcodes.ASM7, mv) {
@Override
public void visitCode() {
injector.accept(new InstrHelper(mv, name));
}
};
}
return mv;
public synchronized Instrumentor addMethodEntryInjection(String methodName, Consumer<CodeBuilder> injector) {
transform = transform.andThen(ClassTransform.transformingMethodBodies(mm -> {
if (mm.methodName().equalsString(methodName)) {
dirty.set(true);
return true;
}
};
return false;
}, new CodeTransform() {
@Override
public void atStart(CodeBuilder builder) {
injector.accept(builder);
}
@Override
public void accept(CodeBuilder builder, CodeElement element) {
builder.accept(element);
}
}));
return this;
}
public synchronized Instrumentor addNativeMethodTrackingInjection(String prefix, Consumer<InstrHelper> injector) {
instrumentingVisitor = new ClassVisitor(Opcodes.ASM9, instrumentingVisitor) {
private final Set<Consumer<ClassVisitor>> wmGenerators = new HashSet<>();
private String className;
public synchronized Instrumentor addNativeMethodTrackingInjection(String prefix, BiConsumer<String, CodeBuilder> injector) {
transform = transform.andThen(ClassTransform.ofStateful(() -> new ClassTransform() {
private final Set<Consumer<ClassBuilder>> wmGenerators = new HashSet<>();
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
this.className = name;
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if ((access & Opcodes.ACC_NATIVE) != 0) {
matches.getAndIncrement();
public void accept(ClassBuilder builder, ClassElement element) {
if (element instanceof MethodModel mm && mm.flags().has(AccessFlag.NATIVE)) {
dirty.set(true);
String name = mm.methodName().stringValue();
String newName = prefix + name;
wmGenerators.add((v)->{
MethodVisitor mv = v.visitMethod(access & ~Opcodes.ACC_NATIVE, name, desc, signature, exceptions);
mv.visitCode();
injector.accept(new InstrHelper(mv, name));
Type[] argTypes = Type.getArgumentTypes(desc);
Type retType = Type.getReturnType(desc);
boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
if (!isStatic) {
mv.visitIntInsn(Opcodes.ALOAD, 0); // load "this"
}
// load the method parameters
if (argTypes.length > 0) {
int ptr = isStatic ? 0 : 1;
for(Type argType : argTypes) {
mv.visitIntInsn(argType.getOpcode(Opcodes.ILOAD), ptr);
ptr += argType.getSize();
MethodTypeDesc mt = mm.methodTypeSymbol();
wmGenerators.add(clb -> clb.transformMethod(mm, new MethodTransform() {
@Override
public void accept(MethodBuilder mb, MethodElement me) {
if (me instanceof AccessFlags flags) {
mb.withFlags(flags.flagsMask() & ~ACC_NATIVE);
} else if (!(me instanceof CodeModel)) {
mb.with(me);
}
}
mv.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKESPECIAL, className, newName, desc, false);
mv.visitInsn(retType.getOpcode(Opcodes.IRETURN));
@Override
public void atEnd(MethodBuilder mb) {
Consumer<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
mv.visitEnd();
});
return super.visitMethod(access, newName, desc, signature, exceptions);
// load method parameters
for (int i = 0; i < mt.parameterCount(); i++) {
TypeKind kind = TypeKind.from(mt.parameterType(i));
cb.loadInstruction(kind, ptr);
ptr += kind.slotSize();
}
cb.invokeInstruction(isStatic ? Opcode.INVOKESTATIC : Opcode.INVOKESPECIAL,
model.thisClass().asSymbol(), newName, mt, false);
cb.returnInstruction(TypeKind.from(mt.returnType()));
}));
}
}));
builder.withMethod(newName, mt, mm.flags().flagsMask(), mm::forEachElement);
} else {
builder.accept(element);
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
@Override
public void visitEnd() {
wmGenerators.stream().forEach((e) -> {
e.accept(cv);
});
super.visitEnd();
public void atEnd(ClassBuilder builder) {
wmGenerators.forEach(e -> e.accept(builder));
}
};
}));
return this;
}
public synchronized byte[] apply() {
cr.accept(instrumentingVisitor, ClassReader.SKIP_DEBUG + ClassReader.EXPAND_FRAMES);
var bytes = ClassFile.of().transform(model, transform);
return matches.get() == 0 ? null : output.toByteArray();
return dirty.get() ? bytes : null;
}
}

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

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

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

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

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -21,64 +21,53 @@
* questions.
*/
/**
/*
* @test
* @bug 8022718
* @summary Runtime accessibility checking: protected class, if extended, should be accessible from another package
* @modules java.base/jdk.internal.org.objectweb.asm
* @enablePreview
* @compile -XDignore.symbol.file BogoLoader.java MethodInvoker.java Test.java anotherpkg/MethodSupplierOuter.java
* @run main/othervm Test
*/
import java.lang.reflect.InvocationTargetException;
import java.lang.classfile.ClassTransform;
import java.lang.classfile.attribute.InnerClassInfo;
import java.lang.classfile.attribute.InnerClassesAttribute;
import java.lang.classfile.constantpool.ClassEntry;
import java.lang.classfile.constantpool.Utf8Entry;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import static java.lang.classfile.ClassFile.ACC_PRIVATE;
import static java.lang.classfile.ClassFile.ACC_PROTECTED;
import static java.lang.classfile.ClassFile.ACC_PUBLIC;
interface MyFunctionalInterface {
void invokeMethodReference();
}
class MakeProtected implements BogoLoader.VisitorMaker, Opcodes {
final boolean whenVisitInner;
MakeProtected(boolean when_visit_inner) {
super();
whenVisitInner = when_visit_inner;
}
public ClassVisitor make(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM7, cv) {
@Override
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
if (whenVisitInner) {
int access_ = (ACC_PROTECTED | access) & ~(ACC_PRIVATE | ACC_PUBLIC);
System.out.println("visitInnerClass: name = " + name
+ ", outerName = " + outerName
+ ", innerName = " + innerName
+ ", access original = 0x" + Integer.toHexString(access)
+ ", access modified to 0x" + Integer.toHexString(access_));
access = access_;
}
super.visitInnerClass(name, outerName, innerName, access);
}
};
}
};
public class Test {
public static void main(String argv[]) throws Exception, Throwable {
BogoLoader.VisitorMaker makeProtectedNop = new MakeProtected(false);
BogoLoader.VisitorMaker makeProtectedMod = new MakeProtected(true);
public static void main(String[] argv) throws Throwable {
ClassTransform makeProtectedNop = ClassTransform.ACCEPT_ALL;
ClassTransform makeProtectedMod = (cb, ce) -> {
if (ce instanceof InnerClassesAttribute ica) {
cb.accept(InnerClassesAttribute.of(ica.classes().stream().map(ici -> {
// AccessFlags doesn't support inner class flags yet
var flags = (ACC_PROTECTED | ici.flagsMask()) & ~(ACC_PRIVATE | ACC_PUBLIC);
System.out.println("visitInnerClass: name = " + ici.innerClass().asInternalName()
+ ", outerName = " + ici.outerClass().map(ClassEntry::asInternalName).orElse("null")
+ ", innerName = " + ici.innerName().map(Utf8Entry::stringValue).orElse("null")
+ ", access original = 0x" + Integer.toHexString(ici.flagsMask())
+ ", access modified to 0x" + Integer.toHexString(flags));
return InnerClassInfo.of(ici.innerClass(), ici.outerClass(), ici.innerName(), flags);
}).toList()));
} else {
cb.accept(ce);
}
};
int errors = 0;
errors += tryModifiedInvocation(makeProtectedNop);
@ -89,12 +78,11 @@ public class Test {
}
}
private static int tryModifiedInvocation(BogoLoader.VisitorMaker makeProtected)
throws Throwable, ClassNotFoundException {
HashMap<String, BogoLoader.VisitorMaker> replace
= new HashMap<String, BogoLoader.VisitorMaker>();
private static int tryModifiedInvocation(ClassTransform makeProtected)
throws Throwable {
var replace = new HashMap<String, ClassTransform>();
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("MyFunctionalInterface");
in_bogus.add("anotherpkg.MethodSupplierOuter"); // seems to be never loaded

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

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

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

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

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

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

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

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

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

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