Path: blob/master/test/jdk/java/lang/StackWalker/StackWalkTest.java
41149 views
/*1* Copyright (c) 2015, 2017, 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*/2223import static java.lang.StackWalker.Option.*;24import java.lang.StackWalker.StackFrame;25import java.util.Arrays;26import java.util.EnumSet;27import java.util.HashSet;28import java.util.List;29import java.util.Random;30import java.util.Set;31import java.util.TreeSet;3233import jdk.test.lib.RandomFactory;3435/**36* @test37* @bug 814045038* @summary Stack Walk Test (use -Dseed=X to set PRNG seed)39* @library /test/lib40* @build jdk.test.lib.RandomFactory41* @compile StackRecorderUtil.java42* @run main/othervm StackWalkTest43* @run main/othervm/java.security.policy=stackwalktest.policy StackWalkTest44* @run main/othervm StackWalkTest -random:5045* @run main/othervm/java.security.policy=stackwalktest.policy StackWalkTest -random:5046* @author danielfuchs, bchristi47* @key randomness48*/49public class StackWalkTest {50private static boolean random = false;51private static boolean verbose = false;52private static int randomRuns = 50;5354private static final int MAX_RANDOM_DEPTH = 1000;5556static final Set<String> infrastructureClasses = new TreeSet<>(Arrays.asList(57"jdk.internal.reflect.NativeMethodAccessorImpl",58"jdk.internal.reflect.DelegatingMethodAccessorImpl",59"java.lang.reflect.Method",60"com.sun.javatest.regtest.MainWrapper$MainThread",61"com.sun.javatest.regtest.agent.MainWrapper$MainThread",62"java.lang.Thread"63));64static final List<Class<?>> streamPipelines = Arrays.asList(65classForName("java.util.stream.AbstractPipeline"),66classForName("java.util.stream.TerminalOp")67);68static Class<?> classForName(String name) {69try {70return Class.forName(name);71} catch (ClassNotFoundException e){72throw new RuntimeException(e);73}74}7576private static boolean isStreamPipeline(Class<?> clazz) {77for (Class<?> c : streamPipelines) {78if (c.isAssignableFrom(clazz)) {79return true;80}81}82return false;83}8485StackRecorderUtil recorder;86int count = 0;87boolean didWalk = false;8889final int estDepth;90final Set<StackWalker.Option> swOptions;9192public StackWalkTest() {93this(EnumSet.noneOf(StackWalker.Option.class), -1);94}9596public StackWalkTest(Set<StackWalker.Option> swOptions) {97this(swOptions, -1);98}99100public StackWalkTest(int estimatedDepth) {101this(EnumSet.noneOf(StackWalker.Option.class), -1);102}103104public StackWalkTest(Set<StackWalker.Option> swOptions, int estimatedDepth) {105this.swOptions = swOptions;106this.estDepth = estimatedDepth;107}108109private StackWalker createStackWalker() {110// test all StackWalker factory methods111if (this.estDepth < 0) {112if (swOptions.isEmpty()) {113return StackWalker.getInstance();114} else {115return StackWalker.getInstance(swOptions);116}117}118return StackWalker.getInstance(swOptions, estDepth);119}120public void consume(StackFrame sf) {121if (count == 0 && swOptions.contains(StackWalker.Option.RETAIN_CLASS_REFERENCE)122&& isStreamPipeline(sf.getDeclaringClass())) {123return;124}125if (verbose) {126System.out.println("\t" + sf.getClassName() + "." + sf.getMethodName());127}128if (count >= recorder.frameCount()) {129// We've gone past main()...130if (infrastructureClasses.contains(sf.getClassName())) {131// safe to ignore132return;133}134}135try {136recorder.compareFrame(count, sf);137} catch (IndexOutOfBoundsException e) {138// Extra non-infra frame in stream139throw new RuntimeException("extra non-infra stack frame at count "140+ count + ": <" + sf + ">", e);141}142count++;143}144145public class Call {146public void walk(int total, int markAt) {147recorder.add(Call.class, "walk", "StackWalkTest.java");148long swFrameCount = createStackWalker().walk(s -> s.count());149150if (verbose) {151System.out.println("Call.walk() total=" + total + ", markAt=" + markAt);152System.out.println("recorder frames:");153for (StackRecorderUtil.TestFrame f : recorder) {154System.out.println("\t" + f.declaringClass + "." + f.methodName);155}156System.out.println("\nStackWalker recorded " + swFrameCount + " frames");157System.out.flush();158}159long recFrameCount = (long)recorder.frameCount();160if (swFrameCount < recFrameCount) {161throw new RuntimeException("StackWalker recorded fewer frames ("+162swFrameCount + ") than recorded ("+ recorder.frameCount() +163") - " + "estimatedDepth set to " + estDepth);164}165if (verbose) {166System.out.println("StackWalker frames:");167}168createStackWalker().forEach(StackWalkTest.this::consume);169didWalk = true;170}171public void call(int total, int current, int markAt) {172recorder.add(Call.class, "call", "StackWalkTest.java");173if (current < total) {174testCall.call(total, current+1, markAt);175} else {176walk(total, markAt);177}178}179}180181public class Marker extends Call {182@Override183public void call(int total, int current, int markAt) {184recorder.add(Marker.class, "call", "StackWalkTest.java");185if (current < total) {186testCall.call(total, current+1, markAt);187} else {188walk(total, markAt);189}190}191}192private Call markerCall = new Marker();193194public class Test extends Call {195@Override196public void call(int total, int current, int markAt) {197recorder.add(Test.class, "call", "StackWalkTest.java");198if (current < total) {199int nexti = current + 1;200if (nexti==markAt) {201markerCall.call(total, nexti, markAt);202} else {203testCall.call2(total, nexti, markAt);204}205} else {206walk(total, markAt);207}208}209public void call2(int total, int current, int markAt) {210recorder.add(Test.class, "call2", "StackWalkTest.java");211if (current < total) {212int nexti = current + 1;213if (nexti==markAt) {214markerCall.call(total, nexti, markAt);215} else {216test2Call.call(total, nexti, markAt);217}218} else {219walk(total, markAt);220}221}222}223private Test testCall = new Test();224225/** Inherits call() from Call */226public class Test2 extends Call {}227private Test2 test2Call = new Test2();228229public void runTest(Class callerClass, String callerMethod, int stackDepth,230int markAt) {231if (didWalk) {232throw new IllegalStateException("StackWalkTest already used");233}234// Test may run into StackOverflow when running in -Xcomp mode on deep stack235assert stackDepth <= 1000;236assert markAt <= stackDepth : "markAt(" + markAt + ") > stackDepth("237+ stackDepth + ")";238System.out.print("runTest(" + swOptions239+ "), estimatedDepth=" + estDepth);240241recorder = new StackRecorderUtil(swOptions);242recorder.add(callerClass, callerMethod, "StackWalkTest.java");243recorder.add(StackWalkTest.class, "runTest", "StackWalkTest.java");244245Test test1 = new Test();246test1.call(stackDepth, 0, markAt);247248System.out.println(" finished");249if (!didWalk) {250throw new IllegalStateException("Test wasn't actually performed");251}252}253254public static void main(String[] args) {255String rand = "-random";256String randItems = "-random:";257for(String arg : args) {258if (arg.startsWith(rand)) {259random = true;260try {261if(arg.startsWith(randItems)) {262randomRuns = Integer.valueOf(arg.substring(randItems.length()));263}264} catch(NumberFormatException e) {}265} else if("-verbose".equals(arg)) {266verbose = true;267}268}269if (random) {270Random rng = RandomFactory.getRandom();271for (int iters = 0; iters < randomRuns; iters++) {272Set<StackWalker.Option> opts = new HashSet<>();273if (rng.nextBoolean()) {274opts.add(RETAIN_CLASS_REFERENCE);275}276277int depth = 1 + rng.nextInt(MAX_RANDOM_DEPTH);278279StackWalkTest swt;280if (rng.nextBoolean() && depth > 1) {281// Test that specifying an estimatedDepth doesn't prevent282// full stack traversal283swt = new StackWalkTest(opts, 1+rng.nextInt(depth-1));284} else {285swt = new StackWalkTest(opts);286}287288int markAt = rng.nextInt(depth+1);289System.out.print(depth + "@" + markAt + " ");290System.out.flush();291swt.runTest(StackWalkTest.class, "main", depth, markAt);292}293} else {294// Long stack, default maxDepth295StackWalkTest swt;296swt = new StackWalkTest();297swt.runTest(StackWalkTest.class, "main", 1000, 10);298299// Long stack, matching maxDepth300swt = new StackWalkTest(2000);301swt.runTest(StackWalkTest.class, "main", 1000, 10);302303// Long stack, maximum maxDepth304swt = new StackWalkTest(Integer.MAX_VALUE);305swt.runTest(StackWalkTest.class, "main", 1000, 10);306307//308// Single batch309//310swt = new StackWalkTest(); // default maxDepth311swt.runTest(StackWalkTest.class, "main", 6, 3);312313swt = new StackWalkTest(4); // maxDepth < stack314swt.runTest(StackWalkTest.class, "main", 6, 3);315316swt = new StackWalkTest(2); // maxDepth < marker317swt.runTest(StackWalkTest.class, "main", 6, 4);318319//320// 2 batches321//322swt = new StackWalkTest(); // default maxDepth323swt.runTest(StackWalkTest.class, "main", 24, 10);324swt = new StackWalkTest(18); // maxDepth < stack325swt.runTest(StackWalkTest.class, "main", 24, 10);326swt = new StackWalkTest(8); // maxDepth < marker327swt.runTest(StackWalkTest.class, "main", 24, 10);328329//330// 3 batch331//332swt = new StackWalkTest(); // default maxDepth333swt.runTest(StackWalkTest.class, "main", 60, 20);334swt = new StackWalkTest(35); // maxDepth < stack335swt.runTest(StackWalkTest.class, "main", 60, 20);336swt = new StackWalkTest(8); // maxDepth < marker337swt.runTest(StackWalkTest.class, "main", 60, 20);338339//340// StackWalker.Options341//342swt = new StackWalkTest();343swt.runTest(StackWalkTest.class, "main", 50, 10);344345swt = new StackWalkTest(EnumSet.of(RETAIN_CLASS_REFERENCE));346swt.runTest(StackWalkTest.class, "main", 80, 40);347348swt = new StackWalkTest(EnumSet.of(RETAIN_CLASS_REFERENCE), 50);349swt.runTest(StackWalkTest.class, "main", 1000, 524);350}351}352}353354355