Path: blob/master/test/jdk/java/lang/StackWalker/TestBCI.java
41149 views
/*1* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 814045026* @summary Basic test for the StackWalker::getByteCodeIndex method27* @modules jdk.jdeps/com.sun.tools.classfile28* @run main TestBCI29*/3031import com.sun.tools.classfile.Attribute;32import com.sun.tools.classfile.ClassFile;33import com.sun.tools.classfile.Code_attribute;34import com.sun.tools.classfile.ConstantPoolException;35import com.sun.tools.classfile.Descriptor;36import com.sun.tools.classfile.LineNumberTable_attribute;37import com.sun.tools.classfile.Method;3839import java.lang.StackWalker.StackFrame;40import java.io.IOException;41import java.io.InputStream;42import java.util.Arrays;43import java.util.Comparator;44import java.util.HashMap;45import java.util.Map;46import java.util.Optional;47import java.util.SortedSet;48import java.util.TreeSet;49import java.util.function.Function;50import java.util.stream.Collectors;5152import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE;5354public class TestBCI {55public static void main(String... args) throws Exception {56TestBCI test = new TestBCI(Walker.class);57System.out.println("Line number table:");58test.methods.values().stream()59.sorted(Comparator.comparing(MethodInfo::name).reversed())60.forEach(System.out::println);6162// walk the stack63test.walk();64}6566private final Map<String, MethodInfo> methods;67private final Class<?> clazz;68TestBCI(Class<?> c) throws ConstantPoolException, IOException {69Map<String, MethodInfo> methods;70String filename = c.getName().replace('.', '/') + ".class";71try (InputStream in = c.getResourceAsStream(filename)) {72ClassFile cf = ClassFile.read(in);73methods = Arrays.stream(cf.methods)74.map(m -> new MethodInfo(cf, m))75.collect(Collectors.toMap(MethodInfo::name, Function.identity()));76}77this.clazz = c;78this.methods = methods;79}8081void walk() {82Walker walker = new Walker();83walker.m1();84}8586void verify(StackFrame frame) {87if (frame.getDeclaringClass() != clazz)88return;8990int bci = frame.getByteCodeIndex();91int lineNumber = frame.getLineNumber();92System.out.format("%s.%s bci %d (%s:%d)%n",93frame.getClassName(), frame.getMethodName(), bci,94frame.getFileName(), lineNumber);9596MethodInfo method = methods.get(frame.getMethodName());97SortedSet<Integer> values = method.findLineNumbers(bci).get();98if (!values.contains(lineNumber)) {99throw new RuntimeException("line number for bci: " + bci + " "100+ lineNumber + " not matched line number table: " + values);101}102}103104/*105* BCIs in the execution stack when StackWalker::forEach is invoked106* will cover BCI range in the line number table.107*/108class Walker {109final StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE);110void m1() {111int i = (int)Math.random()+2;112m2(i*2);113}114115void m2(int i) {116i++;117m3(i);118}119120void m3(int i) {121i++; m4(i++);122}123124int m4(int i) {125walker.forEach(TestBCI.this::verify);126return i;127}128}129130static class MethodInfo {131final Method method;132final String name;133final String paramTypes;134final String returnType;135final Map<Integer, SortedSet<Integer>> bciToLineNumbers = new HashMap<>();136MethodInfo(ClassFile cf, Method m) {137this.method = m;138139String name;140String paramTypes;141String returnType;142LineNumberTable_attribute.Entry[] lineNumberTable;143try {144// method name145name = m.getName(cf.constant_pool);146// signature147paramTypes = m.descriptor.getParameterTypes(cf.constant_pool);148returnType = m.descriptor.getReturnType(cf.constant_pool);149Code_attribute codeAttr = (Code_attribute)150m.attributes.get(Attribute.Code);151lineNumberTable = ((LineNumberTable_attribute)152codeAttr.attributes.get(Attribute.LineNumberTable)).line_number_table;153} catch (ConstantPoolException|Descriptor.InvalidDescriptor e) {154throw new RuntimeException(e);155}156this.name = name;157this.paramTypes = paramTypes;158this.returnType = returnType;159Arrays.stream(lineNumberTable).forEach(entry ->160bciToLineNumbers.computeIfAbsent(entry.start_pc, _n -> new TreeSet<>())161.add(entry.line_number));162}163164String name() {165return name;166}167168Optional<SortedSet<Integer>> findLineNumbers(int value) {169return bciToLineNumbers.entrySet().stream()170.sorted(Map.Entry.comparingByKey(Comparator.reverseOrder()))171.filter(e -> e.getKey().intValue() <= value)172.map(Map.Entry::getValue)173.findFirst();174}175176@Override177public String toString() {178StringBuilder sb = new StringBuilder();179sb.append(name);180sb.append(paramTypes).append(returnType).append(" ");181bciToLineNumbers.entrySet().stream()182.sorted(Map.Entry.comparingByKey())183.forEach(entry -> sb.append("bci:").append(entry.getKey()).append(" ")184.append(entry.getValue()).append(" "));185return sb.toString();186}187}188189}190191192