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