--- /dev/null 2015-11-24 12:24:11.000000000 -0800 +++ new/jdk/test/java/lang/StackWalker/EmbeddedStackWalkTest.java 2015-11-24 12:24:10.000000000 -0800 @@ -0,0 +1,158 @@ +/* + * 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. + */ + + +/** + * @test + * @bug 8143214 + * @summary Verify StackWalker works well when embedded in another + * StackWalker's functions. + * @run testng/othervm EmbeddedStackWalkTest + */ + +import java.lang.StackWalker.StackFrame; +import static java.lang.StackWalker.Option.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Arrays; +import java.util.EnumSet; + +import org.testng.annotations.*; +import static org.testng.Assert.*; + +public class EmbeddedStackWalkTest { + static final StackWalker WALKERS[] = new StackWalker[] { + StackWalker.getInstance(RETAIN_CLASS_REFERENCE), + StackWalker.getInstance(EnumSet.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE)), + StackWalker.getInstance(EnumSet.of(SHOW_HIDDEN_FRAMES, RETAIN_CLASS_REFERENCE)) + }; + + static final int BIG_LOOP = 30; + static final int SMALL_LOOP = 5; + + @DataProvider + public StackWalker[][] walkerProvider() { + return new StackWalker[][] { + new StackWalker[] { WALKERS[0] }, + new StackWalker[] { WALKERS[1] }, + new StackWalker[] { WALKERS[2] } + }; + } + + @Test(dataProvider = "walkerProvider") + public void test(StackWalker walker) { + C1.call(walker, BIG_LOOP); + } + + // line numbers are hardcoded for now. + // Should annotate the line numbers and auto-generated these constants + // for test verification instead + static final int BEGIN_LINE = 71; // the begin line number of approximate range. + static final int END_LINE = 136; // the end line number of approximate range. + static class C1 { // here is the begin line number of approximate range, L71. + public static void call(StackWalker walker, int loops) { + if (loops == 0) { + String caller = walker.walk(s -> + s.map(StackFrame::getClassName) + .filter(cn -> !cn.startsWith("sun.reflect.") && !cn.startsWith("java.lang.invoke")) + .skip(2).findFirst() + ).get(); + assertEquals(caller, C1.class.getName()); + + walker.forEach(f -> C2.testEmbeddedWalker()); + } else { + call(walker, --loops); + } + } + } + + static class C2 { + static final StackWalker embeddedWalkers[] = new StackWalker[] { + StackWalker.getInstance(), + StackWalker.getInstance(SHOW_REFLECT_FRAMES), + StackWalker.getInstance(SHOW_HIDDEN_FRAMES) + }; + + public static void testEmbeddedWalker() { + walk(SMALL_LOOP); + } + + static void walk(int loops) { + if (loops == 0) { + Arrays.stream(embeddedWalkers) + .forEach(walker -> run(walker)); + } else { + walk(--loops); + } + } + + static void run(StackWalker walker) { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodHandle handle = null; + try { + handle = lookup.findStatic(C2.class, "call", + MethodType.methodType(void.class, StackWalker.class)); + handle.invoke(walker); + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + static void call(StackWalker walker) { + String caller = walker.walk(s -> + s.map(StackFrame::getClassName) + .filter(cn -> !cn.startsWith("sun.reflect.") && !cn.startsWith("java.lang.invoke")) + .skip(2).findFirst() + ).get(); + assertEquals(caller, C2.class.getName()); + + verify(walker, C1.class, "call"); + verify(walker, C2.class, "call"); + verify(walker, C2.class, "run"); + verify(walker, C2.class, "walk"); + verify(walker, C2.class, "testEmbeddedWalker"); + } // here is the end line number of approximate range, L136. + + static void verify(StackWalker walker, Class c, String mn) { + final String fileName = "EmbeddedStackWalkTest.java"; + walker.walk(s -> { + s.limit(BIG_LOOP) + .filter(f -> c.getName().equals(f.getClassName()) && mn.equals(f.getMethodName())) + .forEach(f -> { + assertEquals(f.getFileName().get(), fileName); + int line = f.getLineNumber().getAsInt(); + assertTrue(line >= BEGIN_LINE && line <= END_LINE); + + StackTraceElement st = f.toStackTraceElement(); + assertEquals(c.getName(), st.getClassName()); + assertEquals(mn, st.getMethodName()); + assertEquals(st.getFileName(), fileName); + line = st.getLineNumber(); + assertTrue(line >= BEGIN_LINE && line <= END_LINE); + }); + return null; + }); + } + } +}