DumpStackTest.java revision 14176:8606d027b2c2
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
36import java.lang.invoke.MethodHandle;
37import java.lang.invoke.MethodHandles;
38import java.lang.invoke.MethodType;
39import java.lang.reflect.Method;
40import java.util.Arrays;
41import java.util.function.Consumer;
42
43public 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("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"), // non-public class
89                new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"),
90                new CallFrame("jdk.internal.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("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"),
145                new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"),
146                new CallFrame("jdk.internal.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("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"),
168                new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"),
169                new CallFrame("jdk.internal.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("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"),
175                new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"),
176                new CallFrame("jdk.internal.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("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"),
203                new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"),
204                new CallFrame("jdk.internal.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}
235