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 import java.lang.StackWalker.StackFrame; 34 import static java.lang.StackWalker.Option.*; 35 import java.lang.invoke.MethodHandle; 36 import java.lang.invoke.MethodHandles; 37 import java.lang.invoke.MethodType; 38 import java.util.Arrays; 39 import java.util.EnumSet; 40 41 import org.testng.annotations.*; 42 import static org.testng.Assert.*; 43 44 public class EmbeddedStackWalkTest { 45 static final StackWalker WALKERS[] = new StackWalker[] { 46 StackWalker.getInstance(RETAIN_CLASS_REFERENCE), 47 StackWalker.getInstance(EnumSet.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE)), 48 StackWalker.getInstance(EnumSet.of(SHOW_HIDDEN_FRAMES, RETAIN_CLASS_REFERENCE)) 49 }; 50 51 static final int BIG_LOOP = 30; 52 static final int SMALL_LOOP = 5; 53 54 @DataProvider 55 public StackWalker[][] walkerProvider() { 56 return new StackWalker[][] { 57 new StackWalker[] { WALKERS[0] }, 58 new StackWalker[] { WALKERS[1] }, 59 new StackWalker[] { WALKERS[2] } 60 }; 61 } 62 63 @Test(dataProvider = "walkerProvider") 64 public void test(StackWalker walker) { 65 C1.call(walker, BIG_LOOP); 66 } 67 68 // line numbers are hardcoded for now. 69 // Should annotate the line numbers and auto-generated these constants 70 // for test verification instead 71 static final int BEGIN_LINE = 71; // the begin line number of approximate range. 72 static final int END_LINE = 136; // the end line number of approximate range. 73 static class C1 { // here is the begin line number of approximate range, L71. 74 public static void call(StackWalker walker, int loops) { 75 if (loops == 0) { 76 String caller = walker.walk(s -> 77 s.map(StackFrame::getClassName) 78 .filter(cn -> !cn.startsWith("sun.reflect.") && !cn.startsWith("java.lang.invoke")) 79 .skip(2).findFirst() 80 ).get(); 81 assertEquals(caller, C1.class.getName()); 82 83 walker.forEach(f -> C2.testEmbeddedWalker()); 84 } else { 85 call(walker, --loops); 86 } 87 } 88 } 89 90 static class C2 { 91 static final StackWalker embeddedWalkers[] = new StackWalker[] { 92 StackWalker.getInstance(), 93 StackWalker.getInstance(SHOW_REFLECT_FRAMES), 94 StackWalker.getInstance(SHOW_HIDDEN_FRAMES) 95 }; 96 97 public static void testEmbeddedWalker() { 98 walk(SMALL_LOOP); 99 } 100 101 static void walk(int loops) { 102 if (loops == 0) { 103 Arrays.stream(embeddedWalkers) 104 .forEach(walker -> run(walker)); 105 } else { 106 walk(--loops); 107 } 108 } 109 110 static void run(StackWalker walker) { 111 MethodHandles.Lookup lookup = MethodHandles.lookup(); 112 MethodHandle handle = null; 113 try { 114 handle = lookup.findStatic(C2.class, "call", 115 MethodType.methodType(void.class, StackWalker.class)); 116 handle.invoke(walker); 117 } catch(Throwable t) { 118 throw new RuntimeException(t); 119 } 120 } 121 122 static void call(StackWalker walker) { 123 String caller = walker.walk(s -> 124 s.map(StackFrame::getClassName) 125 .filter(cn -> !cn.startsWith("sun.reflect.") && !cn.startsWith("java.lang.invoke")) 126 .skip(2).findFirst() 127 ).get(); 128 assertEquals(caller, C2.class.getName()); 129 130 verify(walker, C1.class, "call"); 131 verify(walker, C2.class, "call"); 132 verify(walker, C2.class, "run"); 133 verify(walker, C2.class, "walk"); 134 verify(walker, C2.class, "testEmbeddedWalker"); 135 } // here is the end line number of approximate range, L136. 136 137 static void verify(StackWalker walker, Class<?> c, String mn) { 138 final String fileName = "EmbeddedStackWalkTest.java"; 139 walker.walk(s -> { 140 s.limit(BIG_LOOP) 141 .filter(f -> c.getName().equals(f.getClassName()) && mn.equals(f.getMethodName())) 142 .forEach(f -> { 143 assertEquals(f.getFileName().get(), fileName); 144 int line = f.getLineNumber().getAsInt(); 145 assertTrue(line >= BEGIN_LINE && line <= END_LINE); 146 147 StackTraceElement st = f.toStackTraceElement(); 148 assertEquals(c.getName(), st.getClassName()); 149 assertEquals(mn, st.getMethodName()); 150 assertEquals(st.getFileName(), fileName); 151 line = st.getLineNumber(); 152 assertTrue(line >= BEGIN_LINE && line <= END_LINE); 153 }); 154 return null; 155 }); 156 } 157 } 158 }