Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 22 additions & 43 deletions test/jdk/java/lang/StackWalker/TestBCI.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand All @@ -66,12 +62,12 @@ public static void main(String... args) throws Exception {

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()));
}
Expand Down Expand Up @@ -129,37 +125,20 @@ int m4(int i) {
}

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() {
Expand All @@ -178,7 +157,7 @@ Optional<SortedSet<Integer>> findLineNumbers(int value) {
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(" ")
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand All @@ -47,7 +51,7 @@
* @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
*/
Expand Down Expand Up @@ -87,75 +91,83 @@ public static void main(String[] args) throws Exception {
}

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)) {
Comment on lines +121 to +125
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this additional test necessary, I don't see it in the original test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was part of the now-removed ReferenceFinder logic; it scans cp as a fast path and then does instruction scan for all methods to find relevant methods to pass to visitor.

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;

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);
}
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 = 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();
return csMethodsMissingAnnotation;
}

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;
}
}
Expand All @@ -174,12 +186,11 @@ private static boolean isCallerSensitive(Method m, ConstantPool cp)
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;
}
Expand Down
Loading