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 import static java.lang.StackWalker.Option.*; 25 import java.lang.StackWalker.StackFrame; 26 import java.util.Arrays; 27 import java.util.List; 28 import java.util.Optional; 29 import java.util.logging.Logger; 30 import java.util.stream.Collectors; 31 32 /** 33 * @test 34 * @bug 8140450 35 * @summary Stack Stream Test 36 * @run main/othervm StackStreamTest 37 */ 38 public class StackStreamTest { 39 public static void main(String[] argv) throws Exception { 40 new StackStreamTest().test(); 41 } 42 43 private static Logger logger = Logger.getLogger("stackstream"); 44 public StackStreamTest() { 45 } 46 47 public void test() { 48 A.a(); 49 } 50 static class A { 51 public static void a() { 52 B.b(); 53 } 54 } 55 static class B { 56 public static void b() { 57 C.c(); 58 } 59 } 60 static class C { 61 public static void c() { 62 D.d(); 63 } 64 } 65 static class D { 66 public static void d() { 67 E.e(); 68 } 69 } 70 static class E { 71 public static void e() { 72 F.f(); 73 } 74 } 75 static class F { 76 public static void f() { 77 logger.severe("log message"); 78 G.g(); 79 new K().k(); 80 } 81 } 82 83 private static boolean isTestClass(StackFrame f) { 84 // Filter jtreg frames from the end of the stack 85 return f.getClassName().startsWith("StackStreamTest"); 86 } 87 88 static class G { 89 static StackWalker STE_WALKER = StackWalker.getInstance(); 90 static StackWalker DEFAULT_WALKER = StackWalker.getInstance(); 91 92 private static final List<String> GOLDEN_CLASS_NAMES = 93 Arrays.asList("StackStreamTest$G", 94 "StackStreamTest$F", 95 "StackStreamTest$E", 96 "StackStreamTest$D", 97 "StackStreamTest$C", 98 "StackStreamTest$B", 99 "StackStreamTest$A", 100 "StackStreamTest", 101 "StackStreamTest"); 102 private static final List<String> GOLDEN_METHOD_NAMES = 103 Arrays.asList("g", "f", "e", "d", "c", "b", "a", "test", "main"); 104 105 106 public static void g() { 107 108 System.out.println("Thread dump"); 109 Thread.dumpStack(); 110 111 caller(); 112 firstFrame(); 113 114 // Check class names 115 System.out.println("check class names"); 116 List<String> sfs = DEFAULT_WALKER.walk(s -> { 117 return s.filter(StackStreamTest::isTestClass) 118 .map(StackFrame::getClassName) 119 .collect(Collectors.toList()); 120 }); 121 equalsOrThrow("class names", sfs, GOLDEN_CLASS_NAMES); 122 123 // Check method names 124 System.out.println("methodNames()"); 125 sfs = DEFAULT_WALKER.walk(s -> { 126 return s.filter(StackStreamTest::isTestClass) 127 .map(StackFrame::getMethodName) 128 .collect(Collectors.toList());} 129 ); 130 equalsOrThrow("method names", sfs, GOLDEN_METHOD_NAMES); 131 132 Exception exc = new Exception("G.g stack"); 133 exc.printStackTrace(); 134 135 System.out.println("Stream of StackTraceElement"); 136 StackWalker.getInstance() 137 .walk(s -> 138 { 139 s.map(StackFrame::toStackTraceElement) 140 .forEach(ste -> System.out.println("STE: " + ste)); 141 return null; 142 }); 143 144 // Do we need this? 145 System.out.println("Collect StackTraceElement"); 146 List<StackTraceElement> stacktrace = STE_WALKER.walk(s -> 147 { 148 // Filter out jtreg frames 149 return s.filter(StackStreamTest::isTestClass) 150 .collect(Collectors.mapping(StackFrame::toStackTraceElement, Collectors.toList())); 151 }); 152 int i=0; 153 for (StackTraceElement s : stacktrace) { 154 System.out.format(" %d: %s%n", i++, s); 155 } 156 157 // Check STEs for correctness 158 checkStackTraceElements(GOLDEN_CLASS_NAMES, GOLDEN_METHOD_NAMES, stacktrace); 159 } 160 161 static void checkStackTraceElements(List<String> classNames, 162 List<String> methodNames, 163 List<StackTraceElement> stes) { 164 if (classNames.size() != methodNames.size() ) { 165 throw new RuntimeException("Test error: classNames and methodNames should be same size"); 166 } 167 if (classNames.size() != stes.size()) { 168 dumpSTEInfo(classNames, methodNames, stes); 169 throw new RuntimeException("wrong number of elements in stes"); 170 } 171 for (int i = 0; i < classNames.size() ; i++) { 172 if (!classNames.get(i).equals(stes.get(i).getClassName()) || 173 !methodNames.get(i).equals(stes.get(i).getMethodName())) { 174 dumpSTEInfo(classNames, methodNames, stes); 175 throw new RuntimeException("class & method names don't match"); 176 } 177 } 178 } 179 180 static void dumpSTEInfo(List<String> classNames, List<String> methodNames, 181 List<StackTraceElement> stes) { 182 System.out.println("Observed class, method names:"); 183 for (StackTraceElement ste : stes) { 184 System.out.println(" " + ste.getClassName() + ", " + ste.getMethodName()); 185 } 186 System.out.println("Expected class, method names:"); 187 for (int i = 0; i < classNames.size(); i++) { 188 System.out.println(" " + classNames.get(i) + ", " + methodNames.get(i)); 189 } 190 } 191 192 static void firstFrame() { 193 System.out.println("first frame()"); 194 StackWalker sw = StackWalker.getInstance(RETAIN_CLASS_REFERENCE); 195 sw.forEach(e -> { 196 System.out.println(e.getClassName() + "," + e.getMethodName()); 197 }); 198 System.out.println("\n"); 199 Optional<StackFrame> frame = sw.walk(s -> 200 { 201 return s.filter(e -> { 202 System.err.println(e.getClassName() + " == " + 203 e.getClassName().equals("StackStreamTest")); 204 return e.getClassName().equals("StackStreamTest"); 205 }).findFirst(); 206 }); 207 Class<?> c = frame.get().getDeclaringClass(); 208 System.out.println("\nfirst frame: " + c); 209 if (c != StackStreamTest.class) { 210 throw new RuntimeException("Unexpected first caller class " + c); 211 } 212 } 213 } 214 215 private static <T> void equalsOrThrow(String label, List<T> list, List<T> expected) { 216 System.out.println("List: " + list); 217 System.out.println("Expectd: " + list); 218 if (!list.equals(expected)) { 219 System.err.println("Observed " + label); 220 for (T s1 : list) { 221 System.out.println(" " + s1); 222 } 223 System.err.println("Expected " + label); 224 for (T s2 : expected) { 225 System.out.println(" " + s2); 226 } 227 throw new RuntimeException("Error with " + label); 228 } 229 } 230 231 232 static class K { 233 void k() { 234 k1(); 235 } 236 void k1() { 237 k2(); 238 } 239 void k2() { 240 k3(); 241 } 242 void k3() { 243 k4(); 244 } 245 void k4() { 246 k5(); 247 } 248 void k5() { 249 k6(); 250 } 251 void k6() { 252 k7(); 253 } 254 void k7() { 255 k8(); 256 } 257 void k8() { 258 k9(); 259 } 260 void k9() { 261 k10(); 262 } 263 void k10() { 264 k20(); 265 } 266 void k20() { 267 new Caller().test(); 268 } 269 270 class Caller { 271 void test() { 272 Class<?> c = StackWalker.getInstance(RETAIN_CLASS_REFERENCE).getCallerClass(); 273 System.out.println("\nTesting K class : " + c); 274 Thread.dumpStack(); 275 if (c != K.class) { 276 throw new RuntimeException("Unexpected caller class "+ c); 277 } 278 } 279 } 280 } 281 282 static void caller() { 283 Class<?> c = StackWalker.getInstance(RETAIN_CLASS_REFERENCE).getCallerClass(); 284 System.out.println("\ncaller class : " + c); 285 if (c != G.class) { 286 throw new RuntimeException("Unexpected caller class "+ c); 287 } 288 } 289 290 }