mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8332109: Convert remaining tests using com.sun.tools.classfile to ClassFile API
Reviewed-by: asotona
This commit is contained in:
parent
e0d1c4b38c
commit
beeffd4671
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2024, 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,22 +25,18 @@
|
||||
* @test
|
||||
* @bug 8140450
|
||||
* @summary Basic test for the StackWalker::getByteCodeIndex method
|
||||
* @modules jdk.jdeps/com.sun.tools.classfile
|
||||
* @enablePreview
|
||||
* @run main TestBCI
|
||||
*/
|
||||
|
||||
import com.sun.tools.classfile.Attribute;
|
||||
import com.sun.tools.classfile.ClassFile;
|
||||
import com.sun.tools.classfile.Code_attribute;
|
||||
import com.sun.tools.classfile.ConstantPoolException;
|
||||
import com.sun.tools.classfile.Descriptor;
|
||||
import com.sun.tools.classfile.LineNumberTable_attribute;
|
||||
import com.sun.tools.classfile.Method;
|
||||
|
||||
import java.lang.StackWalker.StackFrame;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.lang.classfile.Attributes;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.MethodModel;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -66,12 +62,12 @@ public class TestBCI {
|
||||
|
||||
private final Map<String, MethodInfo> methods;
|
||||
private final Class<?> clazz;
|
||||
TestBCI(Class<?> c) throws ConstantPoolException, IOException {
|
||||
TestBCI(Class<?> c) throws IllegalArgumentException, IOException {
|
||||
Map<String, MethodInfo> methods;
|
||||
String filename = c.getName().replace('.', '/') + ".class";
|
||||
try (InputStream in = c.getResourceAsStream(filename)) {
|
||||
ClassFile cf = ClassFile.read(in);
|
||||
methods = Arrays.stream(cf.methods)
|
||||
var cf = ClassFile.of().parse(in.readAllBytes());
|
||||
methods = cf.methods().stream()
|
||||
.map(m -> new MethodInfo(cf, m))
|
||||
.collect(Collectors.toMap(MethodInfo::name, Function.identity()));
|
||||
}
|
||||
@ -129,37 +125,20 @@ public class TestBCI {
|
||||
}
|
||||
|
||||
static class MethodInfo {
|
||||
final Method method;
|
||||
final MethodModel method;
|
||||
final String name;
|
||||
final String paramTypes;
|
||||
final String returnType;
|
||||
final MethodTypeDesc desc;
|
||||
final Map<Integer, SortedSet<Integer>> bciToLineNumbers = new HashMap<>();
|
||||
MethodInfo(ClassFile cf, Method m) {
|
||||
MethodInfo(ClassModel cf, MethodModel m) {
|
||||
this.method = m;
|
||||
|
||||
String name;
|
||||
String paramTypes;
|
||||
String returnType;
|
||||
LineNumberTable_attribute.Entry[] lineNumberTable;
|
||||
try {
|
||||
// method name
|
||||
name = m.getName(cf.constant_pool);
|
||||
// signature
|
||||
paramTypes = m.descriptor.getParameterTypes(cf.constant_pool);
|
||||
returnType = m.descriptor.getReturnType(cf.constant_pool);
|
||||
Code_attribute codeAttr = (Code_attribute)
|
||||
m.attributes.get(Attribute.Code);
|
||||
lineNumberTable = ((LineNumberTable_attribute)
|
||||
codeAttr.attributes.get(Attribute.LineNumberTable)).line_number_table;
|
||||
} catch (ConstantPoolException|Descriptor.InvalidDescriptor e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.name = name;
|
||||
this.paramTypes = paramTypes;
|
||||
this.returnType = returnType;
|
||||
Arrays.stream(lineNumberTable).forEach(entry ->
|
||||
bciToLineNumbers.computeIfAbsent(entry.start_pc, _n -> new TreeSet<>())
|
||||
.add(entry.line_number));
|
||||
this.name = m.methodName().stringValue();
|
||||
this.desc = m.methodTypeSymbol();
|
||||
m.code().orElseThrow(() -> new IllegalArgumentException("Missing Code in " + m))
|
||||
.findAttribute(Attributes.LINE_NUMBER_TABLE)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Missing LineNumberTable in " + m))
|
||||
.lineNumbers().forEach(entry ->
|
||||
bciToLineNumbers.computeIfAbsent(entry.startPc(), _ -> new TreeSet<>())
|
||||
.add(entry.lineNumber()));
|
||||
}
|
||||
|
||||
String name() {
|
||||
@ -178,7 +157,7 @@ public class TestBCI {
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name);
|
||||
sb.append(paramTypes).append(returnType).append(" ");
|
||||
sb.append(desc.displayDescriptor()).append(" ");
|
||||
bciToLineNumbers.entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
.forEach(entry -> sb.append("bci:").append(entry.getKey()).append(" ")
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2024, 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,12 +21,16 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import com.sun.tools.classfile.*;
|
||||
import static com.sun.tools.classfile.ConstantPool.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.classfile.Attributes;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.MethodModel;
|
||||
import java.lang.classfile.Opcode;
|
||||
import java.lang.classfile.constantpool.MethodRefEntry;
|
||||
import java.lang.classfile.instruction.InvokeInstruction;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
@ -47,7 +51,7 @@ import java.util.stream.Stream;
|
||||
* @bug 8010117
|
||||
* @summary Verify if CallerSensitive methods are annotated with
|
||||
* CallerSensitive annotation
|
||||
* @modules jdk.jdeps/com.sun.tools.classfile jdk.jdeps/com.sun.tools.jdeps
|
||||
* @enablePreview
|
||||
* @build CallerSensitiveFinder
|
||||
* @run main/othervm/timeout=900 CallerSensitiveFinder
|
||||
*/
|
||||
@ -87,58 +91,71 @@ public class CallerSensitiveFinder {
|
||||
}
|
||||
|
||||
private final List<String> csMethodsMissingAnnotation = new CopyOnWriteArrayList<>();
|
||||
private final ReferenceFinder finder;
|
||||
public CallerSensitiveFinder() {
|
||||
this.finder = new ReferenceFinder(getFilter(), getVisitor());
|
||||
pool = Executors.newFixedThreadPool(numThreads);
|
||||
|
||||
}
|
||||
|
||||
private ReferenceFinder.Filter getFilter() {
|
||||
final String classname = "jdk/internal/reflect/Reflection";
|
||||
final String method = "getCallerClass";
|
||||
return new ReferenceFinder.Filter() {
|
||||
public boolean accept(ConstantPool cpool, CPRefInfo cpref) {
|
||||
try {
|
||||
CONSTANT_NameAndType_info nat = cpref.getNameAndTypeInfo();
|
||||
return cpref.getClassName().equals(classname) && nat.getName().equals(method);
|
||||
} catch (ConstantPoolException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
private void check(ClassModel clazz) {
|
||||
final String className = "jdk/internal/reflect/Reflection";
|
||||
final String methodName = "getCallerClass";
|
||||
boolean checkMethods = false;
|
||||
for (var pe : clazz.constantPool()) {
|
||||
if (pe instanceof MethodRefEntry ref
|
||||
&& ref.owner().name().equalsString(className)
|
||||
&& ref.name().equalsString(methodName)) {
|
||||
checkMethods = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!checkMethods)
|
||||
return;
|
||||
|
||||
for (var method : clazz.methods()) {
|
||||
var code = method.code().orElse(null);
|
||||
if (code == null)
|
||||
continue;
|
||||
|
||||
boolean needsCsm = false;
|
||||
for (var element : code) {
|
||||
if (element instanceof InvokeInstruction invoke
|
||||
&& invoke.opcode() == Opcode.INVOKESTATIC
|
||||
&& invoke.method() instanceof MethodRefEntry ref
|
||||
&& ref.owner().name().equalsString(className)
|
||||
&& ref.name().equalsString(methodName)) {
|
||||
needsCsm = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (needsCsm) {
|
||||
process(clazz, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ReferenceFinder.Visitor getVisitor() {
|
||||
return new ReferenceFinder.Visitor() {
|
||||
public void visit(ClassFile cf, Method m, List<CPRefInfo> refs) {
|
||||
try {
|
||||
// ignore jdk.unsupported/sun.reflect.Reflection.getCallerClass
|
||||
// which is a "special" delegate to the internal getCallerClass
|
||||
if (cf.getName().equals("sun/reflect/Reflection") &&
|
||||
m.getName(cf.constant_pool).equals("getCallerClass"))
|
||||
return;
|
||||
private void process(ClassModel cf, MethodModel m) {
|
||||
// ignore jdk.unsupported/sun.reflect.Reflection.getCallerClass
|
||||
// which is a "special" delegate to the internal getCallerClass
|
||||
if (cf.thisClass().name().equalsString("sun/reflect/Reflection") &&
|
||||
m.methodName().equalsString("getCallerClass"))
|
||||
return;
|
||||
|
||||
String name = String.format("%s#%s %s", cf.getName(),
|
||||
m.getName(cf.constant_pool),
|
||||
m.descriptor.getValue(cf.constant_pool));
|
||||
if (!CallerSensitiveFinder.isCallerSensitive(m, cf.constant_pool)) {
|
||||
csMethodsMissingAnnotation.add(name);
|
||||
System.err.println("Missing @CallerSensitive: " + name);
|
||||
} else {
|
||||
if (verbose) {
|
||||
System.out.format("@CS %s%n", name);
|
||||
}
|
||||
}
|
||||
} catch (ConstantPoolException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
String name = cf.thisClass().asInternalName() + '#'
|
||||
+ m.methodName().stringValue() + ' '
|
||||
+ m.methodType().stringValue();
|
||||
if (!CallerSensitiveFinder.isCallerSensitive(m)) {
|
||||
csMethodsMissingAnnotation.add(name);
|
||||
System.err.println("Missing @CallerSensitive: " + name);
|
||||
} else {
|
||||
if (verbose) {
|
||||
System.out.format("@CS %s%n", name);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> run(Stream<Path> classes)throws IOException, InterruptedException,
|
||||
ExecutionException, ConstantPoolException
|
||||
ExecutionException, IllegalArgumentException
|
||||
{
|
||||
classes.forEach(p -> pool.submit(getTask(p)));
|
||||
waitForCompletion();
|
||||
@ -146,16 +163,11 @@ public class CallerSensitiveFinder {
|
||||
}
|
||||
|
||||
private static final String CALLER_SENSITIVE_ANNOTATION = "Ljdk/internal/reflect/CallerSensitive;";
|
||||
private static boolean isCallerSensitive(Method m, ConstantPool cp)
|
||||
throws ConstantPoolException
|
||||
{
|
||||
RuntimeAnnotations_attribute attr =
|
||||
(RuntimeAnnotations_attribute)m.attributes.get(Attribute.RuntimeVisibleAnnotations);
|
||||
private static boolean isCallerSensitive(MethodModel m) {
|
||||
var attr = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null);
|
||||
if (attr != null) {
|
||||
for (int i = 0; i < attr.annotations.length; i++) {
|
||||
Annotation ann = attr.annotations[i];
|
||||
String annType = cp.getUTF8Value(ann.type_index);
|
||||
if (CALLER_SENSITIVE_ANNOTATION.equals(annType)) {
|
||||
for (var ann : attr.annotations()) {
|
||||
if (ann.className().equalsString(CALLER_SENSITIVE_ANNOTATION)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -174,12 +186,11 @@ public class CallerSensitiveFinder {
|
||||
private FutureTask<Void> getTask(Path p) {
|
||||
FutureTask<Void> task = new FutureTask<>(new Callable<>() {
|
||||
public Void call() throws Exception {
|
||||
try (InputStream is = Files.newInputStream(p)) {
|
||||
finder.parse(ClassFile.read(is));
|
||||
try {
|
||||
var clz = ClassFile.of().parse(p); // propagate IllegalArgumentException
|
||||
check(clz);
|
||||
} catch (IOException x) {
|
||||
throw new UncheckedIOException(x);
|
||||
} catch (ConstantPoolException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2024, 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,21 +21,23 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import com.sun.tools.classfile.*;
|
||||
|
||||
import static com.sun.tools.classfile.AccessFlags.ACC_PRIVATE;
|
||||
import static com.sun.tools.classfile.ConstantPool.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.classfile.Attributes;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.MethodModel;
|
||||
import java.lang.classfile.Opcode;
|
||||
import java.lang.classfile.constantpool.MethodRefEntry;
|
||||
import java.lang.classfile.instruction.InvokeInstruction;
|
||||
import java.lang.reflect.AccessFlag;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -50,12 +52,13 @@ import java.util.concurrent.FutureTask;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.CD_Class;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary CallerSensitive methods should be static or final instance
|
||||
* methods except the known list of non-final instance methods
|
||||
* @modules jdk.jdeps/com.sun.tools.classfile
|
||||
* jdk.jdeps/com.sun.tools.jdeps
|
||||
* @enablePreview
|
||||
* @build CheckCSMs
|
||||
* @run main/othervm/timeout=900 CheckCSMs
|
||||
*/
|
||||
@ -66,7 +69,7 @@ public class CheckCSMs {
|
||||
|
||||
// The goal is to remove this list of Non-final instance @CS methods
|
||||
// over time. Do not add any new one to this list.
|
||||
private static Set<String> KNOWN_NON_FINAL_CSMS =
|
||||
private static final Set<String> KNOWN_NON_FINAL_CSMS =
|
||||
Set.of("java/io/ObjectStreamField#getType ()Ljava/lang/Class;",
|
||||
"java/lang/Runtime#load (Ljava/lang/String;)V",
|
||||
"java/lang/Runtime#loadLibrary (Ljava/lang/String;)V",
|
||||
@ -111,119 +114,120 @@ public class CheckCSMs {
|
||||
private final Set<String> nonFinalCSMs = new ConcurrentSkipListSet<>();
|
||||
private final Map<String, Set<String>> csmWithCallerParameter = new ConcurrentHashMap<>();
|
||||
|
||||
private final ReferenceFinder finder;
|
||||
public CheckCSMs() {
|
||||
this.finder = new ReferenceFinder(getFilter(), getVisitor());
|
||||
pool = Executors.newFixedThreadPool(numThreads);
|
||||
|
||||
}
|
||||
|
||||
public Set<String> run(Stream<Path> classes)
|
||||
throws IOException, InterruptedException, ExecutionException,
|
||||
ConstantPoolException
|
||||
IllegalArgumentException
|
||||
{
|
||||
classes.forEach(p -> pool.submit(getTask(p)));
|
||||
waitForCompletion();
|
||||
return nonFinalCSMs;
|
||||
}
|
||||
|
||||
private void check(ClassModel clazz) {
|
||||
final String className = "jdk/internal/reflect/Reflection";
|
||||
final String methodName = "getCallerClass";
|
||||
boolean checkMethods = false;
|
||||
for (var pe : clazz.constantPool()) {
|
||||
if (pe instanceof MethodRefEntry ref
|
||||
&& ref.owner().name().equalsString(className)
|
||||
&& ref.name().equalsString(methodName)) {
|
||||
checkMethods = true;
|
||||
}
|
||||
}
|
||||
|
||||
private ReferenceFinder.Filter getFilter() {
|
||||
final String classname = "jdk/internal/reflect/Reflection";
|
||||
final String method = "getCallerClass";
|
||||
return new ReferenceFinder.Filter() {
|
||||
public boolean accept(ConstantPool cpool, CPRefInfo cpref) {
|
||||
try {
|
||||
CONSTANT_NameAndType_info nat = cpref.getNameAndTypeInfo();
|
||||
return cpref.getClassName().equals(classname) && nat.getName().equals(method);
|
||||
} catch (ConstantPoolException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
if (!checkMethods)
|
||||
return;
|
||||
|
||||
for (var method : clazz.methods()) {
|
||||
var code = method.code().orElse(null);
|
||||
if (code == null)
|
||||
continue;
|
||||
|
||||
boolean needsCsm = false;
|
||||
for (var element : code) {
|
||||
if (element instanceof InvokeInstruction invoke
|
||||
&& invoke.opcode() == Opcode.INVOKESTATIC
|
||||
&& invoke.method() instanceof MethodRefEntry ref
|
||||
&& ref.owner().name().equalsString(className)
|
||||
&& ref.name().equalsString(methodName)) {
|
||||
needsCsm = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ReferenceFinder.Visitor getVisitor() {
|
||||
return new ReferenceFinder.Visitor() {
|
||||
public void visit(ClassFile cf, Method m, List<CPRefInfo> refs) {
|
||||
try {
|
||||
// ignore jdk.unsupported/sun.reflect.Reflection.getCallerClass
|
||||
// which is a "special" delegate to the internal getCallerClass
|
||||
if (cf.getName().equals("sun/reflect/Reflection") &&
|
||||
m.getName(cf.constant_pool).equals("getCallerClass"))
|
||||
return;
|
||||
|
||||
String name = methodSignature(cf, m);
|
||||
if (!CheckCSMs.isStaticOrFinal(cf, m, cf.constant_pool)) {
|
||||
System.err.println("Unsupported @CallerSensitive: " + name);
|
||||
nonFinalCSMs.add(name);
|
||||
} else {
|
||||
if (listCSMs) {
|
||||
System.out.format("@CS %s%n", name);
|
||||
}
|
||||
}
|
||||
|
||||
// find the adapter implementation for CSM with the caller parameter
|
||||
if (!csmWithCallerParameter.containsKey(cf.getName())) {
|
||||
Set<String> methods = Arrays.stream(cf.methods)
|
||||
.filter(m0 -> csmWithCallerParameter(cf, m, m0))
|
||||
.map(m0 -> methodSignature(cf, m0))
|
||||
.collect(Collectors.toSet());
|
||||
csmWithCallerParameter.put(cf.getName(), methods);
|
||||
}
|
||||
} catch (ConstantPoolException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
if (needsCsm) {
|
||||
process(clazz, method);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static String methodSignature(ClassFile cf, Method m) {
|
||||
try {
|
||||
return String.format("%s#%s %s", cf.getName(),
|
||||
m.getName(cf.constant_pool),
|
||||
m.descriptor.getValue(cf.constant_pool));
|
||||
} catch (ConstantPoolException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean csmWithCallerParameter(ClassFile cf, Method csm, Method m) {
|
||||
ConstantPool cp = cf.constant_pool;
|
||||
try {
|
||||
int csmParamCount = csm.descriptor.getParameterCount(cp);
|
||||
int paramCount = m.descriptor.getParameterCount(cp);
|
||||
// an adapter method must have the same name and return type and a trailing Class parameter
|
||||
if (!(csm.getName(cp).equals(m.getName(cp)) &&
|
||||
paramCount == (csmParamCount+1) &&
|
||||
m.descriptor.getReturnType(cp).equals(csm.descriptor.getReturnType(cp)))) {
|
||||
private void process(ClassModel cf, MethodModel m) {
|
||||
// ignore jdk.unsupported/sun.reflect.Reflection.getCallerClass
|
||||
// which is a "special" delegate to the internal getCallerClass
|
||||
if (cf.thisClass().name().equalsString("sun/reflect/Reflection")
|
||||
&& m.methodName().equalsString("getCallerClass"))
|
||||
return;
|
||||
|
||||
String name = methodSignature(cf, m);
|
||||
if (!CheckCSMs.isStaticOrFinal(cf, m)) {
|
||||
System.err.println("Unsupported @CallerSensitive: " + name);
|
||||
nonFinalCSMs.add(name);
|
||||
} else {
|
||||
if (listCSMs) {
|
||||
System.out.format("@CS %s%n", name);
|
||||
}
|
||||
}
|
||||
|
||||
// find the adapter implementation for CSM with the caller parameter
|
||||
if (!csmWithCallerParameter.containsKey(cf.thisClass().asInternalName())) {
|
||||
Set<String> methods = cf.methods().stream()
|
||||
.filter(m0 -> csmWithCallerParameter(cf, m, m0))
|
||||
.map(m0 -> methodSignature(cf, m0))
|
||||
.collect(Collectors.toSet());
|
||||
csmWithCallerParameter.put(cf.thisClass().asInternalName(), methods);
|
||||
}
|
||||
}
|
||||
|
||||
private static String methodSignature(ClassModel cf, MethodModel m) {
|
||||
return cf.thisClass().asInternalName() + '#'
|
||||
+ m.methodName().stringValue() + ' '
|
||||
+ m.methodType().stringValue();
|
||||
}
|
||||
|
||||
private static boolean csmWithCallerParameter(ClassModel cf, MethodModel csm, MethodModel m) {
|
||||
var csmType = csm.methodTypeSymbol();
|
||||
var mType = m.methodTypeSymbol();
|
||||
// an adapter method must have the same name and return type and a trailing Class parameter
|
||||
if (!(csm.methodName().equals(m.methodName()) &&
|
||||
mType.parameterCount() == (csmType.parameterCount() + 1) &&
|
||||
mType.returnType().equals(csmType.returnType()))) {
|
||||
return false;
|
||||
}
|
||||
// the descriptor of the adapter method must have the parameters
|
||||
// of the caller-sensitive method and an additional Class parameter
|
||||
for (int i = 0; i < csmType.parameterCount(); i++) {
|
||||
if (mType.parameterType(i) != csmType.parameterType(i)) {
|
||||
return false;
|
||||
}
|
||||
// the descriptor of the adapter method must have the parameters
|
||||
// of the caller-sensitive method and an additional Class parameter
|
||||
String csmDesc = csm.descriptor.getParameterTypes(cp);
|
||||
String desc = m.descriptor.getParameterTypes(cp);
|
||||
int index = desc.indexOf(", java.lang.Class)");
|
||||
if (index == -1) {
|
||||
index = desc.indexOf("java.lang.Class)");
|
||||
if (index == -1) return false;
|
||||
}
|
||||
String s = desc.substring(0, index) + ")";
|
||||
if (s.equals(csmDesc)) {
|
||||
if (!m.access_flags.is(ACC_PRIVATE)) {
|
||||
throw new RuntimeException(methodSignature(cf, m) + " adapter method for " +
|
||||
methodSignature(cf, csm) + " must be private");
|
||||
}
|
||||
if (!isCallerSensitiveAdapter(m, cp)) {
|
||||
throw new RuntimeException(methodSignature(cf, m) + " adapter method for " +
|
||||
methodSignature(cf, csm) + " must be annotated with @CallerSensitiveAdapter");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (ConstantPoolException|Descriptor.InvalidDescriptor e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return false;
|
||||
|
||||
if (!mType.parameterType(mType.parameterCount() - 1).equals(CD_Class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m.flags().has(AccessFlag.PRIVATE)) {
|
||||
throw new RuntimeException(methodSignature(cf, m) + " adapter method for " +
|
||||
methodSignature(cf, csm) + " must be private");
|
||||
}
|
||||
if (!isCallerSensitiveAdapter(m)) {
|
||||
throw new RuntimeException(methodSignature(cf, m) + " adapter method for " +
|
||||
methodSignature(cf, csm) + " must be annotated with @CallerSensitiveAdapter");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final String CALLER_SENSITIVE_ANNOTATION
|
||||
@ -231,16 +235,13 @@ public class CheckCSMs {
|
||||
private static final String CALLER_SENSITIVE_ADAPTER_ANNOTATION
|
||||
= "Ljdk/internal/reflect/CallerSensitiveAdapter;";
|
||||
|
||||
private static boolean isCallerSensitive(Method m, ConstantPool cp)
|
||||
throws ConstantPoolException
|
||||
private static boolean isCallerSensitive(MethodModel m)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
RuntimeAnnotations_attribute attr =
|
||||
(RuntimeAnnotations_attribute)m.attributes.get(Attribute.RuntimeVisibleAnnotations);
|
||||
var attr = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null);
|
||||
if (attr != null) {
|
||||
for (int i = 0; i < attr.annotations.length; i++) {
|
||||
Annotation ann = attr.annotations[i];
|
||||
String annType = cp.getUTF8Value(ann.type_index);
|
||||
if (CALLER_SENSITIVE_ANNOTATION.equals(annType)) {
|
||||
for (var ann : attr.annotations()) {
|
||||
if (ann.className().equalsString(CALLER_SENSITIVE_ANNOTATION)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -248,16 +249,12 @@ public class CheckCSMs {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isCallerSensitiveAdapter(Method m, ConstantPool cp)
|
||||
throws ConstantPoolException
|
||||
{
|
||||
RuntimeAnnotations_attribute attr =
|
||||
(RuntimeAnnotations_attribute)m.attributes.get(Attribute.RuntimeInvisibleAnnotations);
|
||||
private static boolean isCallerSensitiveAdapter(MethodModel m) {
|
||||
var attr = m.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null);
|
||||
|
||||
if (attr != null) {
|
||||
for (int i = 0; i < attr.annotations.length; i++) {
|
||||
Annotation ann = attr.annotations[i];
|
||||
String annType = cp.getUTF8Value(ann.type_index);
|
||||
if (CALLER_SENSITIVE_ADAPTER_ANNOTATION.equals(annType)) {
|
||||
for (var ann : attr.annotations()) {
|
||||
if (ann.className().equalsString(CALLER_SENSITIVE_ADAPTER_ANNOTATION)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -265,16 +262,14 @@ public class CheckCSMs {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isStaticOrFinal(ClassFile cf, Method m, ConstantPool cp)
|
||||
throws ConstantPoolException
|
||||
{
|
||||
if (!isCallerSensitive(m, cp))
|
||||
private static boolean isStaticOrFinal(ClassModel cf, MethodModel m) {
|
||||
if (!isCallerSensitive(m))
|
||||
return false;
|
||||
|
||||
// either a static method or a final instance method
|
||||
return m.access_flags.is(AccessFlags.ACC_STATIC) ||
|
||||
m.access_flags.is(AccessFlags.ACC_FINAL) ||
|
||||
cf.access_flags.is(AccessFlags.ACC_FINAL);
|
||||
return m.flags().has(AccessFlag.STATIC) ||
|
||||
m.flags().has(AccessFlag.FINAL) ||
|
||||
cf.flags().has(AccessFlag.FINAL);
|
||||
}
|
||||
|
||||
private final List<FutureTask<Void>> tasks = new ArrayList<>();
|
||||
@ -288,12 +283,11 @@ public class CheckCSMs {
|
||||
private FutureTask<Void> getTask(Path p) {
|
||||
FutureTask<Void> task = new FutureTask<>(new Callable<>() {
|
||||
public Void call() throws Exception {
|
||||
try (InputStream is = Files.newInputStream(p)) {
|
||||
finder.parse(ClassFile.read(is));
|
||||
try {
|
||||
var clz = ClassFile.of().parse(p); // propagate IllegalArgumentException
|
||||
check(clz);
|
||||
} catch (IOException x) {
|
||||
throw new UncheckedIOException(x);
|
||||
} catch (ConstantPoolException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2024, 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,8 +27,7 @@
|
||||
* @bug 8010117
|
||||
* @summary Test CallerSensitiveFinder to find missing annotation
|
||||
* @modules java.base/jdk.internal.reflect
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* jdk.jdeps/com.sun.tools.jdeps
|
||||
* @enablePreview
|
||||
* @compile -XDignore.symbol.file MissingCallerSensitive.java
|
||||
* @build CallerSensitiveFinder
|
||||
* @run main MissingCallerSensitive
|
||||
|
||||
@ -29,15 +29,17 @@
|
||||
* jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.resources:open
|
||||
* jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.resources:open
|
||||
* jdk.javadoc/jdk.javadoc.internal.tool.resources:open
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* @enablePreview
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.constantpool.Utf8Entry;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.tools.*;
|
||||
import com.sun.tools.classfile.*;
|
||||
|
||||
/**
|
||||
* Compare string constants in javadoc classes against keys in javadoc resource bundles.
|
||||
@ -268,15 +270,15 @@ public class CheckResourceKeys {
|
||||
//System.err.println("scan " + fo.getName());
|
||||
InputStream in = fo.openInputStream();
|
||||
try {
|
||||
ClassFile cf = ClassFile.read(in);
|
||||
for (ConstantPool.CPInfo cpinfo: cf.constant_pool.entries()) {
|
||||
if (cpinfo.getTag() == ConstantPool.CONSTANT_Utf8) {
|
||||
String v = ((ConstantPool.CONSTANT_Utf8_info) cpinfo).value;
|
||||
ClassModel cf = ClassFile.of().parse(in.readAllBytes());
|
||||
for (var cpinfo : cf.constantPool()) {
|
||||
if (cpinfo instanceof Utf8Entry utf8Entry) {
|
||||
String v = utf8Entry.stringValue();
|
||||
if (v.matches("(doclet|main|javadoc|tag)\\.[A-Za-z0-9-_.]+"))
|
||||
results.add(v);
|
||||
}
|
||||
}
|
||||
} catch (ConstantPoolException ignore) {
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2024, 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,60 +25,66 @@
|
||||
* @test
|
||||
* @bug 7166455
|
||||
* @summary javac doesn't set ACC_STRICT bit on <clinit> for strictfp class
|
||||
* @modules jdk.jdeps/com.sun.tools.classfile
|
||||
* @compile -source 16 -target 16 CheckACC_STRICTFlagOnclinitTest.java
|
||||
* @run main CheckACC_STRICTFlagOnclinitTest
|
||||
* @library /tools/lib /test/lib
|
||||
* @enablePreview
|
||||
*/
|
||||
|
||||
import jdk.test.lib.compiler.CompilerUtils;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.MethodModel;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import com.sun.tools.classfile.ClassFile;
|
||||
import com.sun.tools.classfile.ConstantPoolException;
|
||||
import com.sun.tools.classfile.Descriptor;
|
||||
import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
|
||||
import com.sun.tools.classfile.Method;
|
||||
|
||||
import static com.sun.tools.classfile.AccessFlags.ACC_STRICT;
|
||||
|
||||
public strictfp class CheckACC_STRICTFlagOnclinitTest {
|
||||
public class CheckACC_STRICTFlagOnclinitTest {
|
||||
private static final String AssertionErrorMessage =
|
||||
"All methods should have the ACC_STRICT access flag " +
|
||||
"please check output";
|
||||
private static final String offendingMethodErrorMessage =
|
||||
"Method %s of class %s doesn't have the ACC_STRICT access flag";
|
||||
|
||||
static {
|
||||
class Foo {
|
||||
class Bar {
|
||||
void m11() {}
|
||||
private static final String SOURCE = """
|
||||
public strictfp class Test {
|
||||
static {
|
||||
class Foo {
|
||||
class Bar {
|
||||
void m11() {}
|
||||
}
|
||||
void m1() {}
|
||||
}
|
||||
}
|
||||
void m2() {
|
||||
class Any {
|
||||
void m21() {}
|
||||
}
|
||||
}
|
||||
}
|
||||
void m1() {}
|
||||
}
|
||||
}
|
||||
void m2() {
|
||||
class Any {
|
||||
void m21() {}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
private List<String> errors = new ArrayList<>();
|
||||
private final List<String> errors = new ArrayList<>();
|
||||
|
||||
public static void main(String[] args)
|
||||
throws IOException, ConstantPoolException, InvalidDescriptor {
|
||||
throws IOException {
|
||||
new CheckACC_STRICTFlagOnclinitTest().run();
|
||||
}
|
||||
|
||||
private void run()
|
||||
throws IOException, ConstantPoolException, InvalidDescriptor {
|
||||
String testClasses = System.getProperty("test.classes");
|
||||
check(testClasses,
|
||||
"CheckACC_STRICTFlagOnclinitTest.class",
|
||||
"CheckACC_STRICTFlagOnclinitTest$1Foo.class",
|
||||
"CheckACC_STRICTFlagOnclinitTest$1Foo$Bar.class",
|
||||
"CheckACC_STRICTFlagOnclinitTest$1Any.class");
|
||||
if (errors.size() > 0) {
|
||||
throws IOException {
|
||||
Path in = Path.of("in");
|
||||
Path out = Path.of("out");
|
||||
ToolBox toolBox = new ToolBox();
|
||||
toolBox.writeJavaFiles(in, SOURCE);
|
||||
CompilerUtils.compile(in, out, "--release", "16");
|
||||
check(out,
|
||||
"Test.class",
|
||||
"Test$1Foo.class",
|
||||
"Test$1Foo$Bar.class",
|
||||
"Test$1Any.class");
|
||||
if (!errors.isEmpty()) {
|
||||
for (String error: errors) {
|
||||
System.err.println(error);
|
||||
}
|
||||
@ -86,37 +92,17 @@ public strictfp class CheckACC_STRICTFlagOnclinitTest {
|
||||
}
|
||||
}
|
||||
|
||||
void check(String dir, String... fileNames)
|
||||
throws
|
||||
IOException,
|
||||
ConstantPoolException,
|
||||
Descriptor.InvalidDescriptor {
|
||||
void check(Path dir, String... fileNames) throws IOException {
|
||||
for (String fileName : fileNames) {
|
||||
ClassFile classFileToCheck = ClassFile.read(new File(dir, fileName));
|
||||
ClassModel classFileToCheck = ClassFile.of().parse(dir.resolve(fileName));
|
||||
|
||||
for (Method method : classFileToCheck.methods) {
|
||||
if ((method.access_flags.flags & ACC_STRICT) == 0) {
|
||||
for (MethodModel method : classFileToCheck.methods()) {
|
||||
if ((method.flags().flagsMask() & ClassFile.ACC_STRICT) == 0) {
|
||||
errors.add(String.format(offendingMethodErrorMessage,
|
||||
method.getName(classFileToCheck.constant_pool),
|
||||
classFileToCheck.getName()));
|
||||
method.methodName().stringValue(),
|
||||
classFileToCheck.thisClass().asInternalName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this version of the code can be used when ClassFile API in not in a preview
|
||||
// void check(String dir, String... fileNames) throws IOException{
|
||||
// for (String fileName : fileNames) {
|
||||
// ClassModel classFileToCheck = ClassFile.of().parse(new File(dir, fileName).toPath());
|
||||
//
|
||||
// for (MethodModel method : classFileToCheck.methods()) {
|
||||
// if ((method.flags().flagsMask() & ClassFile.ACC_STRICT) == 0) {
|
||||
// errors.add(String.format(offendingMethodErrorMessage,
|
||||
// method.methodName().stringValue(),
|
||||
// classFileToCheck.thisClass().asInternalName()));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2024, 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,76 +21,78 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import com.sun.tools.classfile.*;
|
||||
import com.sun.tools.classfile.BootstrapMethods_attribute.BootstrapMethodSpecifier;
|
||||
import com.sun.tools.classfile.ConstantPool.CONSTANT_InvokeDynamic_info;
|
||||
import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodHandle_info;
|
||||
import jdk.test.lib.compiler.CompilerUtils;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.classfile.Attributes;
|
||||
import java.lang.classfile.BootstrapMethodEntry;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.CodeElement;
|
||||
import java.lang.classfile.MethodModel;
|
||||
import java.lang.classfile.attribute.CodeAttribute;
|
||||
import java.lang.classfile.constantpool.MethodHandleEntry;
|
||||
import java.lang.classfile.instruction.InvokeDynamicInstruction;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8148483 8151516 8151223
|
||||
* @summary Test that StringConcat is working for JDK >= 9
|
||||
* @modules jdk.jdeps/com.sun.tools.classfile
|
||||
*
|
||||
* @clean *
|
||||
* @compile -source 8 -target 8 TestIndyStringConcat.java
|
||||
* @run main TestIndyStringConcat false
|
||||
*
|
||||
* @clean *
|
||||
* @compile -XDstringConcat=inline TestIndyStringConcat.java
|
||||
* @run main TestIndyStringConcat false
|
||||
*
|
||||
* @clean *
|
||||
* @compile -XDstringConcat=indy TestIndyStringConcat.java
|
||||
* @run main TestIndyStringConcat true
|
||||
*
|
||||
* @clean *
|
||||
* @compile -XDstringConcat=indyWithConstants TestIndyStringConcat.java
|
||||
* @run main TestIndyStringConcat true
|
||||
* @library /tools/lib /test/lib
|
||||
* @enablePreview
|
||||
* @run main TestIndyStringConcat
|
||||
*/
|
||||
public class TestIndyStringConcat {
|
||||
|
||||
static String other;
|
||||
private static final String SOURCE = """
|
||||
public class IndyStringConcat {
|
||||
static String other;
|
||||
|
||||
public static String test() {
|
||||
return "Foo" + other;
|
||||
}
|
||||
public static String test() {
|
||||
return "Foo" + other;
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
boolean expected = Boolean.valueOf(args[0]);
|
||||
boolean actual = hasStringConcatFactoryCall("test");
|
||||
if (expected != actual) {
|
||||
throw new AssertionError("expected = " + expected + ", actual = " + actual);
|
||||
Path src = Path.of("src");
|
||||
ToolBox toolBox = new ToolBox();
|
||||
toolBox.writeJavaFiles(src, SOURCE);
|
||||
|
||||
int errors = 0;
|
||||
errors += test(false, "java8", "-source", "8", "-target", "8");
|
||||
errors += test(false, "inline", "-XDstringConcat=inline");
|
||||
errors += test(true, "indy", "-XDstringConcat=indy");
|
||||
errors += test(true, "indyWithConstants", "-XDstringConcat=indyWithConstants");
|
||||
|
||||
if (errors > 0) {
|
||||
throw new AssertionError(errors + " cases failed");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasStringConcatFactoryCall(String methodName) throws Exception {
|
||||
ClassFile classFile = ClassFile.read(new File(System.getProperty("test.classes", "."),
|
||||
TestIndyStringConcat.class.getName() + ".class"));
|
||||
ConstantPool constantPool = classFile.constant_pool;
|
||||
public static int test(boolean expected, String label, String... args) throws Exception {
|
||||
Path src = Path.of("src");
|
||||
Path out = Path.of(label);
|
||||
CompilerUtils.compile(src, out, args);
|
||||
if (hasStringConcatFactoryCall(out.resolve("IndyStringConcat.class"), "test") != expected) {
|
||||
System.err.println("Expected " + expected + " failed for case " + label);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BootstrapMethods_attribute bsm_attr =
|
||||
(BootstrapMethods_attribute)classFile
|
||||
.getAttribute(Attribute.BootstrapMethods);
|
||||
public static boolean hasStringConcatFactoryCall(Path file, String methodName) throws Exception {
|
||||
ClassModel classFile = ClassFile.of().parse(file);
|
||||
|
||||
for (Method method : classFile.methods) {
|
||||
if (method.getName(constantPool).equals(methodName)) {
|
||||
Code_attribute code = (Code_attribute) method.attributes
|
||||
.get(Attribute.Code);
|
||||
for (Instruction i : code.getInstructions()) {
|
||||
if (i.getOpcode() == Opcode.INVOKEDYNAMIC) {
|
||||
CONSTANT_InvokeDynamic_info indyInfo =
|
||||
(CONSTANT_InvokeDynamic_info) constantPool.get(i.getUnsignedShort(1));
|
||||
|
||||
BootstrapMethodSpecifier bsmSpec =
|
||||
bsm_attr.bootstrap_method_specifiers[indyInfo.bootstrap_method_attr_index];
|
||||
|
||||
CONSTANT_MethodHandle_info bsmInfo =
|
||||
(CONSTANT_MethodHandle_info) constantPool.get(bsmSpec.bootstrap_method_ref);
|
||||
|
||||
if (bsmInfo.getCPRefInfo().getClassName().equals("java/lang/invoke/StringConcatFactory")) {
|
||||
for (MethodModel method : classFile.methods()) {
|
||||
if (method.methodName().equalsString(methodName)) {
|
||||
CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow();
|
||||
for (CodeElement i : code.elementList()) {
|
||||
if (i instanceof InvokeDynamicInstruction indy) {
|
||||
BootstrapMethodEntry bsmSpec = indy.invokedynamic().bootstrap();
|
||||
MethodHandleEntry bsmInfo = bsmSpec.bootstrapMethod();
|
||||
if (bsmInfo.reference().owner().asInternalName().equals("java/lang/invoke/StringConcatFactory")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -100,27 +102,4 @@ public class TestIndyStringConcat {
|
||||
return false;
|
||||
}
|
||||
|
||||
// this version of the code can be used when ClassFile API in not in a preview
|
||||
// public static boolean hasStringConcatFactoryCall(String methodName) throws Exception {
|
||||
// ClassModel classFile = ClassFile.of().parse(new File(System.getProperty("test.classes", "."),
|
||||
// TestIndyStringConcat.class.getName() + ".class").toPath());
|
||||
//
|
||||
// for (MethodModel method : classFile.methods()) {
|
||||
// if (method.methodName().equalsString(methodName)) {
|
||||
// CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow();
|
||||
// for (CodeElement i : code.elementList()) {
|
||||
// if (i instanceof InvokeDynamicInstruction) {
|
||||
// InvokeDynamicInstruction indy = (InvokeDynamicInstruction) i;
|
||||
// BootstrapMethodEntry bsmSpec = indy.invokedynamic().bootstrap();
|
||||
// MethodHandleEntry bsmInfo = bsmSpec.bootstrapMethod();
|
||||
// if (bsmInfo.reference().owner().asInternalName().equals("java/lang/invoke/StringConcatFactory")) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import com.sun.tools.classfile.Attribute;
|
||||
import com.sun.tools.classfile.ClassFile;
|
||||
import com.sun.tools.classfile.SourceFile_attribute;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import toolbox.ToolBox;
|
||||
|
||||
/**
|
||||
* Base class for Source file attribute tests. Checks expected file name for specified classes in the SourceFile attribute.
|
||||
* To add new tests you should extend the SourceFileTestBase class and invoke {@link #test} for static sources
|
||||
* or {@link #compileAndTest} for generated sources. For more information see corresponding methods.
|
||||
*
|
||||
* @see #test
|
||||
* @see #compileAndTest
|
||||
*/
|
||||
public class SourceFileTestBase_legacy extends TestBase {
|
||||
/**
|
||||
* Checks expected fileName for the specified class in the SourceFile attribute.
|
||||
*
|
||||
* @param classToTest class to check its SourceFile attribute
|
||||
* @param fileName expected name of the file from which the test file is compiled.
|
||||
*/
|
||||
protected void test(Class<?> classToTest, String fileName) throws Exception {
|
||||
assertAttributePresent(ClassFile.read(getClassFile(classToTest)), fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks expected fileName for the specified class in the SourceFile attribute.
|
||||
*
|
||||
* @param classToTest class name to check its SourceFile attribute
|
||||
* @param fileName expected name of the file from which the test file is compiled.
|
||||
*/
|
||||
protected void test(String classToTest, String fileName) throws Exception {
|
||||
assertAttributePresent(ClassFile.read(getClassFile(classToTest + ".class")), fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks expected fileName for the specified class in the SourceFile attribute.
|
||||
*
|
||||
* @param classToTest path of class to check its SourceFile attribute
|
||||
* @param fileName expected name of the file from which the test file is compiled.
|
||||
*/
|
||||
protected void test(Path classToTest, String fileName) throws Exception {
|
||||
assertAttributePresent(ClassFile.read(classToTest), fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles sourceCode and for each specified class name checks the SourceFile attribute.
|
||||
* The file name is extracted from source code.
|
||||
*
|
||||
* @param sourceCode source code to compile
|
||||
* @param classesToTest class names to check their SourceFile attribute.
|
||||
*/
|
||||
protected void compileAndTest(String sourceCode, String... classesToTest) throws Exception {
|
||||
|
||||
Map<String, ? extends JavaFileObject> classes = compile(sourceCode).getClasses();
|
||||
String fileName = ToolBox.getJavaFileNameFromSource(sourceCode);
|
||||
for (String className : classesToTest) {
|
||||
ClassFile classFile;
|
||||
try (InputStream input = classes.get(className).openInputStream()) {
|
||||
classFile = ClassFile.read(input);
|
||||
}
|
||||
assertAttributePresent(classFile, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAttributePresent(ClassFile classFile, String fileName) throws Exception {
|
||||
|
||||
//We need to count attributes with the same names because there is no appropriate API in the ClassFile.
|
||||
|
||||
List<SourceFile_attribute> sourceFileAttributes = new ArrayList<>();
|
||||
for (Attribute a : classFile.attributes.attrs) {
|
||||
if (Attribute.SourceFile.equals(a.getName(classFile.constant_pool))) {
|
||||
sourceFileAttributes.add((SourceFile_attribute) a);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(sourceFileAttributes.size(), 1, "Should be the only SourceFile attribute");
|
||||
|
||||
SourceFile_attribute attribute = sourceFileAttributes.get(0);
|
||||
|
||||
assertEquals(classFile.constant_pool.getUTF8Info(attribute.attribute_name_index).value,
|
||||
Attribute.SourceFile, "Incorrect attribute name");
|
||||
assertEquals(classFile.constant_pool.getUTF8Info(attribute.sourcefile_index).value, fileName,
|
||||
"Incorrect source file name");
|
||||
assertEquals(attribute.attribute_length, 2, "Incorrect attribute length");
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2024, 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,27 +25,49 @@
|
||||
* @test
|
||||
* @summary sourcefile attribute test for synthetic class.
|
||||
* @bug 8040129
|
||||
* @library /tools/lib /tools/javac/lib ../lib_legacy
|
||||
* @library /tools/lib /tools/javac/lib /test/lib ../lib
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* @build toolbox.ToolBox InMemoryFileManager TestBase SourceFileTestBase_legacy
|
||||
* @compile -source 10 -target 10 SyntheticClassTest.java
|
||||
* @run main SyntheticClassTest true
|
||||
* @clean SyntheticClassTest$1
|
||||
* @compile SyntheticClassTest.java
|
||||
* @run main SyntheticClassTest false
|
||||
* java.base/jdk.internal.classfile.impl
|
||||
* @build toolbox.ToolBox InMemoryFileManager TestBase SourceFileTestBase
|
||||
* @enablePreview
|
||||
* @run main SyntheticClassTest
|
||||
*/
|
||||
|
||||
import jdk.test.lib.compiler.CompilerUtils;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class SyntheticClassTest extends SourceFileTestBase_legacy {
|
||||
public class SyntheticClassTest extends SourceFileTestBase {
|
||||
public static void main(String[] args) throws Exception {
|
||||
boolean expectSynthetic = Boolean.parseBoolean(args[0]);
|
||||
new Inner();
|
||||
String sourceCode = """
|
||||
public class SyntheticClass {
|
||||
static class Inner {
|
||||
private Inner() {
|
||||
}
|
||||
}
|
||||
|
||||
public SyntheticClass() {
|
||||
new Inner();
|
||||
}
|
||||
}
|
||||
""";
|
||||
Path srcDir = Path.of("src");
|
||||
Path v10Dir = Path.of("out10");
|
||||
Path modernDir = Path.of("out");
|
||||
ToolBox toolBox = new ToolBox();
|
||||
toolBox.writeJavaFiles(srcDir, sourceCode);
|
||||
CompilerUtils.compile(srcDir, v10Dir, "--release", "10");
|
||||
CompilerUtils.compile(srcDir, modernDir);
|
||||
test(v10Dir, true);
|
||||
test(modernDir, false);
|
||||
}
|
||||
|
||||
private static void test(Path path, boolean expectSynthetic) throws Exception {
|
||||
try {
|
||||
new SyntheticClassTest().test("SyntheticClassTest$1", "SyntheticClassTest.java");
|
||||
new SyntheticClassTest().test(path.resolve("SyntheticClass$1.class"), "SyntheticClass.java");
|
||||
if (!expectSynthetic) {
|
||||
throw new AssertionError("Synthetic class should not have been emitted!");
|
||||
}
|
||||
@ -55,9 +77,4 @@ public class SyntheticClassTest extends SourceFileTestBase_legacy {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Inner {
|
||||
private Inner() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2024, 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
|
||||
@ -29,12 +29,14 @@
|
||||
* compiling with --release 14.
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* @library /tools/lib /tools/javac/lib ../lib_legacy
|
||||
* @build toolbox.ToolBox InMemoryFileManager TestResult TestBase
|
||||
* @build SyntheticTestDriver_legacy ExpectedClass ExpectedClasses
|
||||
* @library /tools/lib /tools/javac/lib ../lib
|
||||
* @build toolbox.ToolBox InMemoryFileManager
|
||||
* ExpectedClass ExpectedClasses
|
||||
* @compile --enable-preview --source ${jdk.version} --target ${jdk.version}
|
||||
* SyntheticTestDriver.java
|
||||
* ../lib/TestResult.java ../lib/TestBase.java
|
||||
* @compile --source 14 -target 14 -XDdeduplicateLambdas=false BridgeMethodsForLambdaTargetRelease14Test.java
|
||||
* @run main SyntheticTestDriver_legacy BridgeMethodsForLambdaTargetRelease14Test
|
||||
* @run main/othervm --enable-preview SyntheticTestDriver BridgeMethodsForLambdaTargetRelease14Test
|
||||
*/
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
@ -1,212 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.sun.tools.classfile.*;
|
||||
|
||||
/**
|
||||
* The tests work as follows. Firstly, it looks through the test cases
|
||||
* and extracts the appropriate compiled classes. Each test case contains
|
||||
* a set of expected classes, methods and fields. Those class members must not have
|
||||
* the Synthetic attribute, while other found classes, methods and fields must have
|
||||
* the Synthetic attribute if they are not in the set of expected class members.
|
||||
*
|
||||
* Each test executes SyntheticTestDriver specifying the name of test cases and
|
||||
* the number of expected synthetic classes. Each test class is annotated by
|
||||
* annotations which contains non-synthetic class members.
|
||||
*
|
||||
* See the appropriate class for more information about a test case.
|
||||
*/
|
||||
public class SyntheticTestDriver_legacy extends TestResult {
|
||||
|
||||
private static final String ACC_SYNTHETIC = "ACC_SYNTHETIC";
|
||||
|
||||
private final String testCaseName;
|
||||
private final Map<String, ClassFile> classes;
|
||||
private final Map<String, ExpectedClass> expectedClasses;
|
||||
|
||||
public static void main(String[] args)
|
||||
throws TestFailedException, ConstantPoolException, IOException, ClassNotFoundException {
|
||||
if (args.length != 1 && args.length != 2) {
|
||||
throw new IllegalArgumentException("Usage: SyntheticTestDriver <class-name> [<number-of-synthetic-classes>]");
|
||||
}
|
||||
int numberOfSyntheticClasses = args.length == 1 ? 0 : Integer.parseInt(args[1]);
|
||||
new SyntheticTestDriver_legacy(args[0]).test(numberOfSyntheticClasses);
|
||||
}
|
||||
|
||||
public SyntheticTestDriver_legacy(String testCaseName) throws IOException, ConstantPoolException, ClassNotFoundException {
|
||||
Class<?> clazz = Class.forName(testCaseName);
|
||||
this.testCaseName = testCaseName;
|
||||
this.expectedClasses = Stream.of(clazz.getAnnotationsByType(ExpectedClass.class))
|
||||
.collect(Collectors.toMap(ExpectedClass::className, Function.identity()));
|
||||
this.classes = new HashMap<>();
|
||||
Path classDir = getClassDir().toPath();
|
||||
Pattern filePattern = Pattern.compile(Pattern.quote(testCaseName.replace('.', File.separatorChar)) + ".*\\.class");
|
||||
List<Path> paths = Files.walk(classDir)
|
||||
.map(p -> classDir.relativize(p.toAbsolutePath()))
|
||||
.filter(p -> filePattern.matcher(p.toString()).matches())
|
||||
.collect(Collectors.toList());
|
||||
for (Path path : paths) {
|
||||
String className = path.toString().replace(".class", "").replace(File.separatorChar, '.');
|
||||
classes.put(className, readClassFile(classDir.resolve(path).toFile()));
|
||||
}
|
||||
if (classes.isEmpty()) {
|
||||
throw new RuntimeException("Classes have not been found.");
|
||||
}
|
||||
boolean success = classes.entrySet().stream()
|
||||
.allMatch(e -> e.getKey().startsWith(testCaseName));
|
||||
if (!success) {
|
||||
classes.forEach((className, $) -> printf("Found class: %s\n", className));
|
||||
throw new RuntimeException("Found classes are not from the test case : " + testCaseName);
|
||||
}
|
||||
}
|
||||
|
||||
private String getMethodName(ClassFile classFile, Method method)
|
||||
throws ConstantPoolException, Descriptor.InvalidDescriptor {
|
||||
String methodName = method.getName(classFile.constant_pool);
|
||||
String parameters = method.descriptor.getParameterTypes(classFile.constant_pool);
|
||||
return methodName + parameters;
|
||||
}
|
||||
|
||||
public void test(int expectedNumberOfSyntheticClasses) throws TestFailedException {
|
||||
try {
|
||||
addTestCase(testCaseName);
|
||||
Set<String> foundClasses = new HashSet<>();
|
||||
|
||||
int numberOfSyntheticClasses = 0;
|
||||
for (Map.Entry<String, ClassFile> entry : classes.entrySet()) {
|
||||
String className = entry.getKey();
|
||||
ClassFile classFile = entry.getValue();
|
||||
foundClasses.add(className);
|
||||
if (testAttribute(
|
||||
classFile,
|
||||
() -> (Synthetic_attribute) classFile.getAttribute(Attribute.Synthetic),
|
||||
classFile.access_flags::getClassFlags,
|
||||
expectedClasses.keySet(),
|
||||
className,
|
||||
"Testing class " + className)) {
|
||||
++numberOfSyntheticClasses;
|
||||
}
|
||||
ExpectedClass expectedClass = expectedClasses.get(className);
|
||||
Set<String> expectedMethods = expectedClass != null
|
||||
? toSet(expectedClass.expectedMethods())
|
||||
: new HashSet<>();
|
||||
int numberOfSyntheticMethods = 0;
|
||||
Set<String> foundMethods = new HashSet<>();
|
||||
for (Method method : classFile.methods) {
|
||||
String methodName = getMethodName(classFile, method);
|
||||
foundMethods.add(methodName);
|
||||
if (testAttribute(
|
||||
classFile,
|
||||
() -> (Synthetic_attribute) method.attributes.get(Attribute.Synthetic),
|
||||
method.access_flags::getMethodFlags,
|
||||
expectedMethods,
|
||||
methodName,
|
||||
"Testing method " + methodName + " in class "
|
||||
+ className)) {
|
||||
++numberOfSyntheticMethods;
|
||||
}
|
||||
}
|
||||
checkContains(foundMethods, expectedMethods,
|
||||
"Checking that all methods of class " + className
|
||||
+ " without Synthetic attribute have been found");
|
||||
checkEquals(numberOfSyntheticMethods,
|
||||
expectedClass == null ? 0 : expectedClass.expectedNumberOfSyntheticMethods(),
|
||||
"Checking number of synthetic methods in class: " + className);
|
||||
|
||||
Set<String> expectedFields = expectedClass != null
|
||||
? toSet(expectedClass.expectedFields())
|
||||
: new HashSet<>();
|
||||
int numberOfSyntheticFields = 0;
|
||||
Set<String> foundFields = new HashSet<>();
|
||||
for (Field field : classFile.fields) {
|
||||
String fieldName = field.getName(classFile.constant_pool);
|
||||
foundFields.add(fieldName);
|
||||
if (testAttribute(
|
||||
classFile,
|
||||
() -> (Synthetic_attribute) field.attributes.get(Attribute.Synthetic),
|
||||
field.access_flags::getFieldFlags,
|
||||
expectedFields,
|
||||
fieldName,
|
||||
"Testing field " + fieldName + " in class "
|
||||
+ className)) {
|
||||
++numberOfSyntheticFields;
|
||||
}
|
||||
}
|
||||
checkContains(foundFields, expectedFields,
|
||||
"Checking that all fields of class " + className
|
||||
+ " without Synthetic attribute have been found");
|
||||
checkEquals(numberOfSyntheticFields,
|
||||
expectedClass == null ? 0 : expectedClass.expectedNumberOfSyntheticFields(),
|
||||
"Checking number of synthetic fields in class: " + className);
|
||||
}
|
||||
checkContains(foundClasses, expectedClasses.keySet(),
|
||||
"Checking that all classes have been found");
|
||||
checkEquals(numberOfSyntheticClasses, expectedNumberOfSyntheticClasses,
|
||||
"Checking number of synthetic classes");
|
||||
} catch (Exception e) {
|
||||
addFailure(e);
|
||||
} finally {
|
||||
checkStatus();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean testAttribute(ClassFile classFile,
|
||||
Supplier<Synthetic_attribute> getSyntheticAttribute,
|
||||
Supplier<Set<String>> getAccessFlags,
|
||||
Set<String> expectedMembers, String memberName,
|
||||
String info) throws ConstantPoolException {
|
||||
echo(info);
|
||||
String className = classFile.getName();
|
||||
Synthetic_attribute attr = getSyntheticAttribute.get();
|
||||
Set<String> flags = getAccessFlags.get();
|
||||
if (expectedMembers.contains(memberName)) {
|
||||
checkNull(attr, "Member must not have synthetic attribute : "
|
||||
+ memberName);
|
||||
checkFalse(flags.contains(ACC_SYNTHETIC),
|
||||
"Member must not have synthetic flag : " + memberName
|
||||
+ " in class : " + className);
|
||||
return false;
|
||||
} else {
|
||||
return checkNull(attr, "Synthetic attribute should not be generated")
|
||||
&& checkTrue(flags.contains(ACC_SYNTHETIC), "Member must have synthetic flag : "
|
||||
+ memberName + " in class : " + className);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> toSet(String[] strings) {
|
||||
HashSet<String> set = new HashSet<>();
|
||||
Collections.addAll(set, strings);
|
||||
return set;
|
||||
}
|
||||
}
|
||||
@ -1,284 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.tools.DiagnosticCollector;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
import com.sun.tools.classfile.ClassFile;
|
||||
import com.sun.tools.classfile.ConstantPoolException;
|
||||
|
||||
import toolbox.JavacTask;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
/**
|
||||
* Base class for class file attribute tests.
|
||||
* Contains methods for compiling generated sources in memory,
|
||||
* for reading files from disk and a lot of assert* methods.
|
||||
*/
|
||||
public class TestBase {
|
||||
|
||||
public static final String LINE_SEPARATOR = System.lineSeparator();
|
||||
public static final boolean isDumpOfSourceEnabled = Boolean.getBoolean("dump.src");
|
||||
|
||||
private <S> InMemoryFileManager compile(
|
||||
List<String> options,
|
||||
Function<S, ? extends JavaFileObject> src2JavaFileObject,
|
||||
List<S> sources)
|
||||
throws IOException, CompilationException {
|
||||
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
List<? extends JavaFileObject> src = sources.stream()
|
||||
.map(src2JavaFileObject)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
DiagnosticCollector<? super JavaFileObject> dc = new DiagnosticCollector<>();
|
||||
try (InMemoryFileManager fileManager
|
||||
= new InMemoryFileManager(compiler.getStandardFileManager(null, null, null))) {
|
||||
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, dc, options, null, src);
|
||||
boolean success = task.call();
|
||||
if (!success) {
|
||||
String errorMessage = dc.getDiagnostics().stream()
|
||||
.map(Object::toString)
|
||||
.collect(Collectors.joining("\n"));
|
||||
throw new CompilationException("Compilation Error\n\n" + errorMessage);
|
||||
}
|
||||
return fileManager;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles sources in memory.
|
||||
*
|
||||
* @param sources to compile
|
||||
* @return in-memory file manager which contains class files and class loader
|
||||
*/
|
||||
public InMemoryFileManager compile(String... sources)
|
||||
throws IOException, CompilationException {
|
||||
return compile(Collections.emptyList(), sources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles sources in memory.
|
||||
*
|
||||
* @param options compiler options.
|
||||
* @param sources sources to compile.
|
||||
* @return in-memory file manager which contains class files and class loader.
|
||||
*/
|
||||
public InMemoryFileManager compile(List<String> options, String... sources)
|
||||
throws IOException, CompilationException {
|
||||
return compile(options, ToolBox.JavaSource::new, Arrays.asList(sources));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles sources in memory.
|
||||
*
|
||||
* @param sources sources[i][0] - name of file, sources[i][1] - sources.
|
||||
* @return in-memory file manager which contains class files and class loader.
|
||||
*/
|
||||
public InMemoryFileManager compile(String[]... sources) throws IOException,
|
||||
CompilationException {
|
||||
return compile(Collections.emptyList(), sources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles sources in memory.
|
||||
*
|
||||
* @param options compiler options
|
||||
* @param sources sources[i][0] - name of file, sources[i][1] - sources.
|
||||
* @return in-memory file manager which contains class files and class loader.
|
||||
*/
|
||||
public InMemoryFileManager compile(List<String> options, String[]... sources)
|
||||
throws IOException, CompilationException {
|
||||
return compile(options, src -> new ToolBox.JavaSource(src[0], src[1]), Arrays.asList(sources));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class file that is read from {@code is}.
|
||||
*
|
||||
* @param is an input stream
|
||||
* @return class file that is read from {@code is}
|
||||
* @throws IOException if I/O error occurs
|
||||
* @throws ConstantPoolException if constant pool error occurs
|
||||
*/
|
||||
public ClassFile readClassFile(InputStream is) throws IOException, ConstantPoolException {
|
||||
return ClassFile.read(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class file that is read from {@code fileObject}.
|
||||
*
|
||||
* @param fileObject a file object
|
||||
* @return class file that is read from {@code fileObject}
|
||||
* @throws IOException if I/O error occurs
|
||||
* @throws ConstantPoolException if constant pool error occurs
|
||||
*/
|
||||
public ClassFile readClassFile(JavaFileObject fileObject) throws IOException, ConstantPoolException {
|
||||
try (InputStream is = fileObject.openInputStream()) {
|
||||
return readClassFile(is);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class file that corresponds to {@code clazz}.
|
||||
*
|
||||
* @param clazz a class
|
||||
* @return class file that is read from {@code clazz}
|
||||
* @throws IOException if I/O error occurs
|
||||
* @throws ConstantPoolException if constant pool error occurs
|
||||
*/
|
||||
public ClassFile readClassFile(Class<?> clazz) throws IOException, ConstantPoolException {
|
||||
return readClassFile(getClassFile(clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class file that corresponds to {@code className}.
|
||||
*
|
||||
* @param className a class name
|
||||
* @return class file that is read from {@code className}
|
||||
* @throws IOException if I/O error occurs
|
||||
* @throws ConstantPoolException if constant pool error occurs
|
||||
*/
|
||||
public ClassFile readClassFile(String className) throws IOException, ConstantPoolException {
|
||||
return readClassFile(getClassFile(className + ".class"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class file that is read from {@code file}.
|
||||
*
|
||||
* @param file a file
|
||||
* @return class file that is read from {@code file}
|
||||
* @throws IOException if I/O error occurs
|
||||
* @throws ConstantPoolException if constant pool error occurs
|
||||
*/
|
||||
public ClassFile readClassFile(File file) throws IOException, ConstantPoolException {
|
||||
try (InputStream is = new FileInputStream(file)) {
|
||||
return readClassFile(is);
|
||||
}
|
||||
}
|
||||
|
||||
public void assertEquals(Object actual, Object expected, String message) {
|
||||
if (!Objects.equals(actual, expected))
|
||||
throw new AssertionFailedException(String.format("%s%nGot: %s, Expected: %s",
|
||||
message, actual, expected));
|
||||
}
|
||||
|
||||
public void assertNull(Object actual, String message) {
|
||||
assertEquals(actual, null, message);
|
||||
}
|
||||
|
||||
public void assertNotNull(Object actual, String message) {
|
||||
if (Objects.isNull(actual)) {
|
||||
throw new AssertionFailedException(message + " : Expected not null value");
|
||||
}
|
||||
}
|
||||
|
||||
public void assertTrue(boolean actual, String message) {
|
||||
assertEquals(actual, true, message);
|
||||
}
|
||||
|
||||
public void assertFalse(boolean actual, String message) {
|
||||
assertEquals(actual, false, message);
|
||||
}
|
||||
|
||||
public void assertContains(Set<?> found, Set<?> expected, String message) {
|
||||
Set<?> copy = new HashSet<>(expected);
|
||||
copy.removeAll(found);
|
||||
assertTrue(found.containsAll(expected), message + " : " + copy);
|
||||
}
|
||||
|
||||
public void writeToFile(Path path, String source) throws IOException {
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(path)) {
|
||||
writer.write(source);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeToFileIfEnabled(Path path, String source) throws IOException {
|
||||
if (isDumpOfSourceEnabled) {
|
||||
writeToFile(path, source);
|
||||
} else {
|
||||
System.err.println("Source dumping disabled. To enable, run the test with '-Ddump.src=true'");
|
||||
}
|
||||
}
|
||||
|
||||
public File getSourceDir() {
|
||||
return new File(System.getProperty("test.src", "."));
|
||||
}
|
||||
|
||||
public File getClassDir() {
|
||||
return new File(System.getProperty("test.classes", TestBase.class.getResource(".").getPath()));
|
||||
}
|
||||
|
||||
public File getSourceFile(String fileName) {
|
||||
return new File(getSourceDir(), fileName);
|
||||
}
|
||||
|
||||
public File getClassFile(String fileName) {
|
||||
return new File(getClassDir(), fileName);
|
||||
}
|
||||
|
||||
public File getClassFile(Class clazz) {
|
||||
return getClassFile(clazz.getName().replace(".", "/") + ".class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints message to standard error. New lines are converted to system dependent NL.
|
||||
*
|
||||
* @param message string to print.
|
||||
*/
|
||||
public void echo(String message) {
|
||||
printf(message + "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes args in template and prints result to standard error.
|
||||
* New lines are converted to system dependent NL.
|
||||
*
|
||||
* @param template template in standard String.format(...) format.
|
||||
* @param args arguments to substitute in template.
|
||||
*/
|
||||
public void printf(String template, Object... args) {
|
||||
System.err.printf(String.format(template, args).replace("\n", LINE_SEPARATOR));
|
||||
}
|
||||
|
||||
public static class CompilationException extends Exception {
|
||||
|
||||
public CompilationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AssertionFailedException extends RuntimeException {
|
||||
public AssertionFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,191 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class accumulates test results. Test results can be checked with method {@code checkStatus}.
|
||||
*/
|
||||
public class TestResult extends TestBase {
|
||||
|
||||
private final List<Info> testCasesInfo;
|
||||
|
||||
public TestResult() {
|
||||
testCasesInfo = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new test case info.
|
||||
*
|
||||
* @param info the information about test case
|
||||
*/
|
||||
public void addTestCase(String info) {
|
||||
System.err.println("Test case: " + info);
|
||||
testCasesInfo.add(new Info(info));
|
||||
}
|
||||
|
||||
public boolean checkEquals(Object actual, Object expected, String message) {
|
||||
echo("Testing : " + message);
|
||||
if (!Objects.equals(actual, expected)) {
|
||||
getLastTestCase().addAssert(String.format("%s\n" +
|
||||
"Expected: %s,\n" +
|
||||
" Got: %s", message, expected, actual));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkNull(Object actual, String message) {
|
||||
return checkEquals(actual, null, message);
|
||||
}
|
||||
|
||||
public boolean checkNotNull(Object actual, String message) {
|
||||
echo("Testing : " + message);
|
||||
if (Objects.isNull(actual)) {
|
||||
getLastTestCase().addAssert(message + " : Expected not null value");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkFalse(boolean actual, String message) {
|
||||
return checkEquals(actual, false, message);
|
||||
}
|
||||
|
||||
public boolean checkTrue(boolean actual, String message) {
|
||||
return checkEquals(actual, true, message);
|
||||
}
|
||||
|
||||
public boolean checkContains(Collection<?> found, Collection<?> expected, String message) {
|
||||
Set<?> copy = new HashSet<>(expected);
|
||||
copy.removeAll(found);
|
||||
if (!found.containsAll(expected)) {
|
||||
return checkTrue(false, message + " FAIL : not found elements : " + copy + "\n" +
|
||||
"Actual: " + found);
|
||||
} else {
|
||||
return checkTrue(true, message + " PASS : all elements found");
|
||||
}
|
||||
}
|
||||
|
||||
public void addFailure(Throwable th) {
|
||||
if (testCasesInfo.isEmpty()) {
|
||||
testCasesInfo.add(new Info("Dummy info"));
|
||||
}
|
||||
getLastTestCase().addFailure(th);
|
||||
}
|
||||
|
||||
private Info getLastTestCase() {
|
||||
if (testCasesInfo.isEmpty()) {
|
||||
throw new IllegalStateException("Test case should be created");
|
||||
}
|
||||
return testCasesInfo.get(testCasesInfo.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws {@code TestFailedException} if one of the checks are failed
|
||||
* or an exception occurs. Prints error message of failed test cases.
|
||||
*
|
||||
* @throws TestFailedException if one of the checks are failed
|
||||
* or an exception occurs
|
||||
*/
|
||||
public void checkStatus() throws TestFailedException {
|
||||
int passed = 0;
|
||||
int failed = 0;
|
||||
for (Info testCaseInfo : testCasesInfo) {
|
||||
if (testCaseInfo.isFailed()) {
|
||||
String info = testCaseInfo.info().replace("\n", LINE_SEPARATOR);
|
||||
String errorMessage = testCaseInfo.getMessage().replace("\n", LINE_SEPARATOR);
|
||||
System.err.printf("Failure in test case:%n%s%n%s%n", info, errorMessage);
|
||||
++failed;
|
||||
} else {
|
||||
++passed;
|
||||
}
|
||||
}
|
||||
System.err.printf("Test cases: passed: %d, failed: %d, total: %d.%n", passed, failed, passed + failed);
|
||||
if (failed > 0) {
|
||||
throw new TestFailedException("Test failed");
|
||||
}
|
||||
if (passed + failed == 0) {
|
||||
throw new TestFailedException("Test cases were not found");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printf(String template, Object... args) {
|
||||
getLastTestCase().printf(template, args);
|
||||
}
|
||||
|
||||
private static class Info {
|
||||
|
||||
private final String info;
|
||||
private final StringWriter writer;
|
||||
private boolean isFailed;
|
||||
|
||||
private Info(String info) {
|
||||
this.info = info;
|
||||
writer = new StringWriter();
|
||||
}
|
||||
|
||||
public String info() {
|
||||
return info;
|
||||
}
|
||||
|
||||
public boolean isFailed() {
|
||||
return isFailed;
|
||||
}
|
||||
|
||||
public void printf(String template, Object... args) {
|
||||
writer.write(String.format(template, args));
|
||||
}
|
||||
|
||||
public void addFailure(Throwable th) {
|
||||
isFailed = true;
|
||||
printf("[ERROR] : %s\n", getStackTrace(th));
|
||||
}
|
||||
|
||||
public void addAssert(String e) {
|
||||
isFailed = true;
|
||||
printf("[ASSERT] : %s\n", e);
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
public String getStackTrace(Throwable throwable) {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
try (PrintWriter printWriter = new PrintWriter(stringWriter)) {
|
||||
throwable.printStackTrace(printWriter);
|
||||
}
|
||||
return stringWriter.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestFailedException extends Exception {
|
||||
public TestFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2024, 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,44 +25,51 @@
|
||||
* @test
|
||||
* @bug 8012723
|
||||
* @summary strictfp interface misses strictfp modifer on default method
|
||||
* @modules jdk.jdeps/com.sun.tools.classfile
|
||||
* @compile -source 16 -target 16 CheckACC_STRICTFlagOnDefaultMethodTest.java
|
||||
* @library /tools/lib /test/lib
|
||||
* @enablePreview
|
||||
* @run main CheckACC_STRICTFlagOnDefaultMethodTest
|
||||
*/
|
||||
|
||||
import jdk.test.lib.compiler.CompilerUtils;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.MethodModel;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.sun.tools.classfile.ClassFile;
|
||||
import com.sun.tools.classfile.ConstantPoolException;
|
||||
import com.sun.tools.classfile.Descriptor;
|
||||
import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
|
||||
import com.sun.tools.classfile.Method;
|
||||
|
||||
import static com.sun.tools.classfile.AccessFlags.ACC_STRICT;
|
||||
|
||||
public class CheckACC_STRICTFlagOnDefaultMethodTest {
|
||||
private static final String AssertionErrorMessage =
|
||||
"All methods should have the ACC_STRICT access flag " +
|
||||
"please check output";
|
||||
private static final String offendingMethodErrorMessage =
|
||||
"Method %s of class %s doesn't have the ACC_STRICT access flag";
|
||||
private static final String SOURCE = """
|
||||
strictfp interface StrictfpInterface {
|
||||
default void default_interface_method() {}
|
||||
static void static_interface_method() {}
|
||||
}
|
||||
""";
|
||||
|
||||
private List<String> errors = new ArrayList<>();
|
||||
|
||||
public static void main(String[] args)
|
||||
throws IOException, ConstantPoolException, InvalidDescriptor {
|
||||
throws IOException {
|
||||
new CheckACC_STRICTFlagOnDefaultMethodTest().run();
|
||||
}
|
||||
|
||||
private void run()
|
||||
throws IOException, ConstantPoolException, InvalidDescriptor {
|
||||
String testClasses = System.getProperty("test.classes");
|
||||
check(testClasses,
|
||||
"CheckACC_STRICTFlagOnDefaultMethodTest$StrictfpInterface.class");
|
||||
if (errors.size() > 0) {
|
||||
throws IOException {
|
||||
Path src = Path.of("src");
|
||||
Path out = Path.of("out");
|
||||
ToolBox toolBox = new ToolBox();
|
||||
toolBox.writeJavaFiles(src, SOURCE);
|
||||
CompilerUtils.compile(src, out, "--release", "16");
|
||||
check(out, "StrictfpInterface.class");
|
||||
if (!errors.isEmpty()) {
|
||||
for (String error: errors) {
|
||||
System.err.println(error);
|
||||
}
|
||||
@ -70,42 +77,17 @@ public class CheckACC_STRICTFlagOnDefaultMethodTest {
|
||||
}
|
||||
}
|
||||
|
||||
void check(String dir, String... fileNames)
|
||||
throws
|
||||
IOException,
|
||||
ConstantPoolException,
|
||||
Descriptor.InvalidDescriptor {
|
||||
void check(Path dir, String... fileNames) throws IOException {
|
||||
for (String fileName : fileNames) {
|
||||
ClassFile classFileToCheck = ClassFile.read(new File(dir, fileName));
|
||||
ClassModel classFileToCheck = ClassFile.of().parse(dir.resolve(fileName));
|
||||
|
||||
for (Method method : classFileToCheck.methods) {
|
||||
if ((method.access_flags.flags & ACC_STRICT) == 0) {
|
||||
for (MethodModel method : classFileToCheck.methods()) {
|
||||
if ((method.flags().flagsMask() & ClassFile.ACC_STRICT) == 0) {
|
||||
errors.add(String.format(offendingMethodErrorMessage,
|
||||
method.getName(classFileToCheck.constant_pool),
|
||||
classFileToCheck.getName()));
|
||||
method.methodName().stringValue(),
|
||||
classFileToCheck.thisClass().asInternalName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this version of the code can be used when ClassFile API in not in a preview
|
||||
// void check(String dir, String... fileNames) throws IOException {
|
||||
// for (String fileName : fileNames) {
|
||||
// ClassModel classFileToCheck = ClassFile.of().parse(new File(dir, fileName).toPath());
|
||||
//
|
||||
// for (MethodModel method : classFileToCheck.methods()) {
|
||||
// if ((method.flags().flagsMask() & ClassFile.ACC_STRICT) == 0) {
|
||||
// errors.add(String.format(offendingMethodErrorMessage,
|
||||
// method.methodName().stringValue(),
|
||||
// classFileToCheck.thisClass().asInternalName()));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
strictfp interface StrictfpInterface {
|
||||
default void default_interface_method() {}
|
||||
static void static_interface_method() {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2024, 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,27 +25,49 @@
|
||||
* @test
|
||||
* @bug 8046060
|
||||
* @summary Different results of floating point multiplication for lambda code block
|
||||
* @modules jdk.jdeps/com.sun.tools.classfile
|
||||
* @compile -source 16 -target 16 LambdaTestStrictFPFlag.java
|
||||
* @library /tools/lib /test/lib
|
||||
* @enablePreview
|
||||
* @run main LambdaTestStrictFPFlag
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import com.sun.tools.classfile.*;
|
||||
import jdk.test.lib.compiler.CompilerUtils;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.MethodModel;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class LambdaTestStrictFPFlag {
|
||||
private static final String SOURCE = """
|
||||
class Test {
|
||||
strictfp void test() {
|
||||
Face itf = () -> { };
|
||||
}
|
||||
}
|
||||
|
||||
interface Face {
|
||||
void m();
|
||||
}
|
||||
""";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new LambdaTestStrictFPFlag().run();
|
||||
}
|
||||
|
||||
void run() throws Exception {
|
||||
ClassFile cf = getClassFile("LambdaTestStrictFPFlag$Test.class");
|
||||
ConstantPool cp = cf.constant_pool;
|
||||
Path src = Path.of("src");
|
||||
Path out = Path.of("out");
|
||||
|
||||
ToolBox toolBox = new ToolBox();
|
||||
toolBox.writeJavaFiles(src, SOURCE);
|
||||
CompilerUtils.compile(src, out, "--release", "16");
|
||||
|
||||
ClassModel cm = ClassFile.of().parse(out.resolve("Test.class"));
|
||||
boolean found = false;
|
||||
for (Method meth: cf.methods) {
|
||||
if (meth.getName(cp).startsWith("lambda$")) {
|
||||
if ((meth.access_flags.flags & AccessFlags.ACC_STRICT) == 0) {
|
||||
for (MethodModel meth: cm.methods()) {
|
||||
if (meth.methodName().stringValue().startsWith("lambda$")) {
|
||||
if ((meth.flags().flagsMask() & ClassFile.ACC_STRICT) == 0){
|
||||
throw new Exception("strict flag missing from lambda");
|
||||
}
|
||||
found = true;
|
||||
@ -55,41 +77,4 @@ public class LambdaTestStrictFPFlag {
|
||||
throw new Exception("did not find lambda method");
|
||||
}
|
||||
}
|
||||
|
||||
// this version of the code can be used when ClassFile API in not in a preview
|
||||
// void run() throws Exception {
|
||||
// ClassModel cm = getClassFile("LambdaTestStrictFPFlag$Test.class");
|
||||
// boolean found = false;
|
||||
// for (MethodModel meth: cm.methods()) {
|
||||
// if (meth.methodName().stringValue().startsWith("lambda$")) {
|
||||
// if ((meth.flags().flagsMask() & ClassFile.ACC_STRICT) == 0){
|
||||
// throw new Exception("strict flag missing from lambda");
|
||||
// }
|
||||
// found = true;
|
||||
// }
|
||||
// }
|
||||
// if (!found) {
|
||||
// throw new Exception("did not find lambda method");
|
||||
// }
|
||||
// }
|
||||
|
||||
ClassFile getClassFile(String name) throws IOException, ConstantPoolException {
|
||||
URL url = getClass().getResource(name);
|
||||
InputStream in = url.openStream();
|
||||
try {
|
||||
return ClassFile.read(in);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
class Test {
|
||||
strictfp void test() {
|
||||
Face itf = () -> { };
|
||||
}
|
||||
}
|
||||
|
||||
interface Face {
|
||||
void m();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2024, 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,12 +25,10 @@
|
||||
* @test
|
||||
* @bug 6866657
|
||||
* @summary add byteLength() method to primary classfile types
|
||||
* @modules jdk.jdeps/com.sun.tools.classfile
|
||||
* jdk.jdeps/com.sun.tools.javap
|
||||
* @modules jdk.jdeps/com.sun.tools.javap
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.tools.*;
|
||||
import com.sun.tools.javap.*;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2024, 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,12 +25,9 @@
|
||||
* @test
|
||||
* @bug 7186925
|
||||
* @summary JavapTask passes null to java.io.Writer
|
||||
* @modules jdk.jdeps/com.sun.tools.classfile
|
||||
* jdk.jdeps/com.sun.tools.javap
|
||||
* @modules jdk.jdeps/com.sun.tools.javap
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.tools.*;
|
||||
import com.sun.tools.javap.*;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2024, 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
|
||||
@ -28,7 +28,6 @@
|
||||
* @library lib
|
||||
* @modules java.base/sun.security.x509
|
||||
* java.management
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* jdk.jdeps/com.sun.tools.jdeps
|
||||
* @run main APIDeps
|
||||
*/
|
||||
@ -104,17 +103,17 @@ public class APIDeps {
|
||||
new String[] {"c.I", "e.E", "f.F", "m.Bar"},
|
||||
new String[] {"-classpath", testDir.getPath(), "-verbose:class", "-filter:none"});
|
||||
test(new File(mDir, "Gee.class"),
|
||||
new String[] {"g.G", "sun.security.x509.X509CertInfo", "com.sun.tools.classfile.ClassFile",
|
||||
new String[] {"g.G", "sun.security.x509.X509CertInfo", "com.sun.tools.jdeps.Analyzer",
|
||||
"com.sun.management.ThreadMXBean", "com.sun.source.tree.BinaryTree"},
|
||||
new String[] {"-classpath", testDir.getPath(), "-verbose"});
|
||||
|
||||
// -jdkinternals
|
||||
test(new File(mDir, "Gee.class"),
|
||||
new String[] {"sun.security.x509.X509CertInfo", "com.sun.tools.classfile.ClassFile"},
|
||||
new String[] {"sun.security.x509.X509CertInfo", "com.sun.tools.jdeps.Analyzer"},
|
||||
new String[] {"-jdkinternals", "-quiet"});
|
||||
// -jdkinternals parses all classes on -classpath and the input arguments
|
||||
test(new File(mDir, "Gee.class"),
|
||||
new String[] {"com.sun.tools.classfile.ClassFile",
|
||||
new String[] {"com.sun.tools.jdeps.Analyzer",
|
||||
"sun.security.x509.X509CertInfo"},
|
||||
// use -classpath tmp/a with no use of JDK internal API
|
||||
new String[] {"-classpath", dest.resolve("a").toString(), "-jdkinternals", "-quiet"});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2024, 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 @@ package m;
|
||||
|
||||
class Gee extends g.G {
|
||||
public sun.security.x509.X509CertInfo cert;
|
||||
public com.sun.tools.classfile.ClassFile cf; // not exported
|
||||
public com.sun.tools.jdeps.Analyzer analyzer; // not exported
|
||||
public com.sun.source.tree.BinaryTree tree; // exported
|
||||
public com.sun.management.ThreadMXBean mxbean; // exported
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user