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