1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 /** 26 * @test 27 * @bug 8143214 28 * @summary Verify StackWalker works well when embedded in another 29 * StackWalker's functions. 30 * @run testng/othervm EmbeddedStackWalkTest 31 */ 32 33 package test.java.lang.StackWalker; 34 35 import java.lang.StackWalker.StackFrame; 36 import static java.lang.StackWalker.Option.*; 37 import java.lang.invoke.MethodHandle; 38 import java.lang.invoke.MethodHandles; 39 import java.lang.invoke.MethodType; 40 import java.util.Arrays; 41 import java.util.EnumSet; 42 43 import org.testng.annotations.*; 44 import static org.testng.Assert.*; 45 46 public class EmbeddedStackWalkTest { 47 static final StackWalker WALKERS[] = new StackWalker[] { 48 StackWalker.getInstance(RETAIN_CLASS_REFERENCE), 49 StackWalker.getInstance(EnumSet.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE)), 50 StackWalker.getInstance(EnumSet.of(SHOW_HIDDEN_FRAMES, RETAIN_CLASS_REFERENCE)) 51 }; 52 53 static final int BIG_LOOP = 30; 54 static final int SMALL_LOOP = 5; 55 56 @DataProvider walkerProvider()57 public StackWalker[][] walkerProvider() { 58 return new StackWalker[][] { 59 new StackWalker[] { WALKERS[0] }, 60 new StackWalker[] { WALKERS[1] }, 61 new StackWalker[] { WALKERS[2] } 62 }; 63 } 64 65 @Test(dataProvider = "walkerProvider") test(StackWalker walker)66 public void test(StackWalker walker) { 67 C1.call(walker, BIG_LOOP); 68 } 69 70 // line numbers are hardcoded for now. 71 // Should annotate the line numbers and auto-generated these constants 72 // for test verification instead 73 static final int BEGIN_LINE = 71; // the begin line number of approximate range. 74 static final int END_LINE = 136; // the end line number of approximate range. 75 static class C1 { // here is the begin line number of approximate range, L71. call(StackWalker walker, int loops)76 public static void call(StackWalker walker, int loops) { 77 if (loops == 0) { 78 String caller = walker.walk(s -> 79 s.map(StackFrame::getClassName) 80 .filter(cn -> !cn.startsWith("jdk.internal.reflect.") && !cn.startsWith("java.lang.invoke")) 81 .skip(2).findFirst() 82 ).get(); 83 assertEquals(caller, C1.class.getName()); 84 85 walker.forEach(f -> C2.testEmbeddedWalker()); 86 } else { 87 call(walker, --loops); 88 } 89 } 90 } 91 92 static class C2 { 93 static final StackWalker embeddedWalkers[] = new StackWalker[] { 94 StackWalker.getInstance(), 95 StackWalker.getInstance(SHOW_REFLECT_FRAMES), 96 StackWalker.getInstance(SHOW_HIDDEN_FRAMES) 97 }; 98 testEmbeddedWalker()99 public static void testEmbeddedWalker() { 100 walk(SMALL_LOOP); 101 } 102 walk(int loops)103 static void walk(int loops) { 104 if (loops == 0) { 105 Arrays.stream(embeddedWalkers) 106 .forEach(walker -> run(walker)); 107 } else { 108 walk(--loops); 109 } 110 } 111 run(StackWalker walker)112 static void run(StackWalker walker) { 113 MethodHandles.Lookup lookup = MethodHandles.lookup(); 114 MethodHandle handle = null; 115 try { 116 handle = lookup.findStatic(C2.class, "call", 117 MethodType.methodType(void.class, StackWalker.class)); 118 handle.invoke(walker); 119 } catch(Throwable t) { 120 throw new RuntimeException(t); 121 } 122 } 123 call(StackWalker walker)124 static void call(StackWalker walker) { 125 String caller = walker.walk(s -> 126 s.map(StackFrame::getClassName) 127 .filter(cn -> !cn.startsWith("jdk.internal.reflect.") && !cn.startsWith("java.lang.invoke")) 128 .skip(2).findFirst() 129 ).get(); 130 assertEquals(caller, C2.class.getName()); 131 132 verify(walker, C1.class, "call"); 133 verify(walker, C2.class, "call"); 134 verify(walker, C2.class, "run"); 135 verify(walker, C2.class, "walk"); 136 verify(walker, C2.class, "testEmbeddedWalker"); 137 } // here is the end line number of approximate range, L136. 138 verify(StackWalker walker, Class<?> c, String mn)139 static void verify(StackWalker walker, Class<?> c, String mn) { 140 final String fileName = "EmbeddedStackWalkTest.java"; 141 walker.walk(s -> { 142 s.limit(BIG_LOOP) 143 .filter(f -> c.getName().equals(f.getClassName()) && mn.equals(f.getMethodName())) 144 .forEach(f -> { 145 assertEquals(f.getFileName(), fileName); 146 int line = f.getLineNumber(); 147 assertTrue(line >= BEGIN_LINE && line <= END_LINE); 148 149 StackTraceElement st = f.toStackTraceElement(); 150 assertEquals(c.getName(), st.getClassName()); 151 assertEquals(mn, st.getMethodName()); 152 assertEquals(st.getFileName(), fileName); 153 line = st.getLineNumber(); 154 assertTrue(line >= BEGIN_LINE && line <= END_LINE); 155 }); 156 return null; 157 }); 158 } 159 } 160 } 161