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 * @test 26 * @bug 8143214 27 * @summary Verify outputs of Thread.dumpStack() and Throwable.printStackTrace(). 28 * This test should also been run against jdk9 successfully except of 29 * VM option MemberNameInStackFrame. 30 * @run main/othervm DumpStackTest 31 * @run main/othervm -Dstackwalk.newThrowable=false DumpStackTest 32 * @run main/othervm -Dstackwalk.newThrowable=true -XX:-MemberNameInStackFrame DumpStackTest 33 * @run main/othervm -Dstackwalk.newThrowable=true -XX:+MemberNameInStackFrame DumpStackTest 34 */ 35 36 import java.lang.invoke.MethodHandle; 37 import java.lang.invoke.MethodHandles; 38 import java.lang.invoke.MethodType; 39 import java.lang.reflect.Method; 40 import java.util.Arrays; 41 import java.util.function.Consumer; 42 43 public class DumpStackTest { 44 45 public static void main(String args[]) { 46 test(); 47 testThread(); 48 testLambda(); 49 testMethodInvoke(); 50 testMethodHandle(); 51 } 52 53 static class CallFrame { 54 final String classname; 55 final String methodname; 56 CallFrame(Class<?> c, String methodname) { 57 this(c.getName(), methodname); 58 } 59 CallFrame(String classname, String methodname) { 60 this.classname = classname; 61 this.methodname = methodname; 62 } 63 64 String getClassName() { 65 return classname; 66 } 67 String getMethodName() { 68 return methodname; 69 } 70 String getFileName() { 71 int i = classname.lastIndexOf('.'); 72 int j = classname.lastIndexOf('$'); 73 String name = classname.substring(i+1, j >= 0 ? j : classname.length()); 74 return name + ".java"; 75 } 76 @Override 77 public String toString() { 78 return classname + "." + methodname + "(" + getFileName() + ")"; 79 } 80 } 81 82 static void test() { 83 CallFrame[] callStack = new CallFrame[] { 84 new CallFrame(Thread.class, "getStackTrace"), 85 new CallFrame(DumpStackTest.class, "test"), 86 new CallFrame(DumpStackTest.class, "main"), 87 // if invoked from jtreg 88 new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), // non-public class 89 new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), 90 new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), 91 new CallFrame(Method.class, "invoke"), 92 new CallFrame(Thread.class, "run"), 93 }; 94 95 assertStackTrace(Thread.currentThread().getStackTrace(), callStack); 96 getStackTrace(callStack); 97 } 98 99 static void getStackTrace(CallFrame[] callStack) { 100 // this method is the top of the stack 101 callStack[0] = new CallFrame(DumpStackTest.class, "getStackTrace"); 102 103 try { 104 throw new RuntimeException(); 105 } catch(RuntimeException ex) { 106 assertStackTrace(ex.getStackTrace(), callStack); 107 } 108 } 109 static void testThread() { 110 Thread t1 = new Thread() { 111 public void run() { 112 c(); 113 } 114 115 void c() { 116 CallFrame[] callStack = new CallFrame[] { 117 new CallFrame(Thread.class, "getStackTrace"), 118 new CallFrame(this.getClass(), "c"), 119 new CallFrame(this.getClass(), "run") 120 }; 121 assertStackTrace(Thread.currentThread().getStackTrace(), callStack); 122 DumpStackTest.getStackTrace(callStack); 123 } 124 }; 125 t1.start(); 126 try { 127 t1.join(); 128 } catch(InterruptedException e) {} 129 } 130 131 static void testLambda() { 132 Consumer<Void> c = (x) -> consumeLambda(); 133 c.accept(null); 134 } 135 136 static void consumeLambda() { 137 CallFrame[] callStack = new CallFrame[]{ 138 new CallFrame(Thread.class, "getStackTrace"), 139 new CallFrame(DumpStackTest.class, "consumeLambda"), 140 new CallFrame(DumpStackTest.class, "lambda$testLambda$0"), 141 new CallFrame(DumpStackTest.class, "testLambda"), 142 new CallFrame(DumpStackTest.class, "main"), 143 // if invoked from jtreg 144 new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), 145 new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), 146 new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), 147 new CallFrame(Method.class, "invoke"), 148 new CallFrame(Thread.class, "run") 149 }; 150 assertStackTrace(Thread.currentThread().getStackTrace(), callStack); 151 DumpStackTest.getStackTrace(callStack); 152 } 153 154 static void testMethodInvoke() { 155 try { 156 Method m = DumpStackTest.class.getDeclaredMethod("methodInvoke"); 157 m.invoke(null); 158 } catch(Exception e) { 159 throw new RuntimeException(e); 160 } 161 } 162 163 static void methodInvoke() { 164 CallFrame[] callStack = new CallFrame[] { 165 new CallFrame(Thread.class, "getStackTrace"), 166 new CallFrame(DumpStackTest.class, "methodInvoke"), 167 new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), 168 new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), 169 new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), 170 new CallFrame(Method.class, "invoke"), 171 new CallFrame(DumpStackTest.class, "testMethodInvoke"), 172 new CallFrame(DumpStackTest.class, "main"), 173 // if invoked from jtreg 174 new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), 175 new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), 176 new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), 177 new CallFrame(Method.class, "invoke"), 178 new CallFrame(Thread.class, "run") 179 }; 180 assertStackTrace(Thread.currentThread().getStackTrace(), callStack); 181 DumpStackTest.getStackTrace(callStack); 182 } 183 184 static void testMethodHandle() { 185 MethodHandles.Lookup lookup = MethodHandles.lookup(); 186 try { 187 MethodHandle handle = lookup.findStatic(DumpStackTest.class, "methodHandle", 188 MethodType.methodType(void.class)); 189 handle.invoke(); 190 } catch(Throwable t) { 191 throw new RuntimeException(t); 192 } 193 } 194 195 static void methodHandle() { 196 CallFrame[] callStack = new CallFrame[]{ 197 new CallFrame(Thread.class, "getStackTrace"), 198 new CallFrame(DumpStackTest.class, "methodHandle"), 199 new CallFrame(DumpStackTest.class, "testMethodHandle"), 200 new CallFrame(DumpStackTest.class, "main"), 201 // if invoked from jtreg 202 new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), 203 new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), 204 new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), 205 new CallFrame(Method.class, "invoke"), 206 new CallFrame(Thread.class, "run") 207 }; 208 assertStackTrace(Thread.currentThread().getStackTrace(), callStack); 209 DumpStackTest.getStackTrace(callStack); 210 } 211 212 static void assertStackTrace(StackTraceElement[] actual, CallFrame[] expected) { 213 System.out.println("--- Actual ---"); 214 Arrays.stream(actual).forEach(e -> System.out.println(e)); 215 System.out.println("--- Expected ---"); 216 Arrays.stream(expected).forEach(e -> System.out.println(e)); 217 218 for (int i = 0, j = 0; i < actual.length; i++) { 219 // filter test framework classes 220 if (actual[i].getClassName().startsWith("com.sun.javatest.regtest")) 221 continue; 222 assertEquals(actual[i], expected[j++], i); 223 } 224 225 } 226 static void assertEquals(StackTraceElement actual, CallFrame expected, int idx) { 227 if (!actual.getClassName().equals(expected.getClassName()) || 228 !actual.getFileName().equals(expected.getFileName()) || 229 !actual.getMethodName().equals(expected.getMethodName())) { 230 throw new RuntimeException("StackTraceElements mismatch at index " + idx + 231 ". Expected [" + expected + "], but get [" + actual + "]"); 232 } 233 } 234 }