1 /* |
|
2 * Copyright (c) 2015, 2016, 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 8136421 |
|
27 * @requires vm.jvmci |
|
28 * @library / /test/lib |
|
29 * @library ../common/patches |
|
30 * @modules java.base/jdk.internal.misc |
|
31 * @modules java.base/jdk.internal.org.objectweb.asm |
|
32 * java.base/jdk.internal.org.objectweb.asm.tree |
|
33 * jdk.internal.vm.ci/jdk.vm.ci.hotspot |
|
34 * jdk.internal.vm.ci/jdk.vm.ci.code |
|
35 * jdk.internal.vm.ci/jdk.vm.ci.meta |
|
36 * @build jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper |
|
37 * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI |
|
38 * -Djvmci.Compiler=null |
|
39 * compiler.jvmci.compilerToVM.GetNextStackFrameTest |
|
40 */ |
|
41 |
|
42 package compiler.jvmci.compilerToVM; |
|
43 |
|
44 import compiler.jvmci.common.CTVMUtilities; |
|
45 import jdk.test.lib.Asserts; |
|
46 import jdk.vm.ci.hotspot.CompilerToVMHelper; |
|
47 import jdk.vm.ci.hotspot.HotSpotStackFrameReference; |
|
48 import jdk.vm.ci.meta.ResolvedJavaMethod; |
|
49 |
|
50 import java.lang.reflect.Method; |
|
51 |
|
52 public class GetNextStackFrameTest { |
|
53 private static final int RECURSION_AMOUNT = 3; |
|
54 private static final ResolvedJavaMethod REC_FRAME_METHOD; |
|
55 private static final ResolvedJavaMethod FRAME1_METHOD; |
|
56 private static final ResolvedJavaMethod FRAME2_METHOD; |
|
57 private static final ResolvedJavaMethod FRAME3_METHOD; |
|
58 private static final ResolvedJavaMethod FRAME4_METHOD; |
|
59 private static final ResolvedJavaMethod RUN_METHOD; |
|
60 |
|
61 static { |
|
62 Method method; |
|
63 try { |
|
64 Class<?> aClass = GetNextStackFrameTest.class; |
|
65 method = aClass.getDeclaredMethod("recursiveFrame", int.class); |
|
66 REC_FRAME_METHOD = CTVMUtilities.getResolvedMethod(method); |
|
67 method = aClass.getDeclaredMethod("frame1"); |
|
68 FRAME1_METHOD = CTVMUtilities.getResolvedMethod(method); |
|
69 method = aClass.getDeclaredMethod("frame2"); |
|
70 FRAME2_METHOD = CTVMUtilities.getResolvedMethod(method); |
|
71 method = aClass.getDeclaredMethod("frame3"); |
|
72 FRAME3_METHOD = CTVMUtilities.getResolvedMethod(method); |
|
73 method = aClass.getDeclaredMethod("frame4"); |
|
74 FRAME4_METHOD = CTVMUtilities.getResolvedMethod(method); |
|
75 method = Thread.class.getDeclaredMethod("run"); |
|
76 RUN_METHOD = CTVMUtilities.getResolvedMethod(Thread.class, method); |
|
77 } catch (NoSuchMethodException e) { |
|
78 throw new Error("TEST BUG: can't find a test method : " + e, e); |
|
79 } |
|
80 } |
|
81 |
|
82 public static void main(String[] args) { |
|
83 new GetNextStackFrameTest().test(); |
|
84 } |
|
85 |
|
86 private void test() { |
|
87 // Create new thread to get new clean stack |
|
88 Thread thread = new Thread(() -> recursiveFrame(RECURSION_AMOUNT)); |
|
89 thread.start(); |
|
90 try { |
|
91 thread.join(); |
|
92 } catch (InterruptedException e) { |
|
93 throw new Error("Interrupted while waiting to join", e); |
|
94 } |
|
95 } |
|
96 |
|
97 // Helper methods for a longer stack |
|
98 private void recursiveFrame(int recursionAmount) { |
|
99 if (--recursionAmount != 0) { |
|
100 recursiveFrame(recursionAmount); |
|
101 } else { |
|
102 frame1(); |
|
103 } |
|
104 } |
|
105 |
|
106 private void frame1() { |
|
107 frame2(); |
|
108 } |
|
109 |
|
110 private void frame2() { |
|
111 frame3(); |
|
112 } |
|
113 |
|
114 private void frame3() { |
|
115 frame4(); |
|
116 } |
|
117 |
|
118 private void frame4() { |
|
119 check(); |
|
120 } |
|
121 |
|
122 private void check() { |
|
123 findFirst(); |
|
124 walkThrough(); |
|
125 skipAll(); |
|
126 findNextSkipped(); |
|
127 findYourself(); |
|
128 } |
|
129 |
|
130 /** |
|
131 * Finds the first topmost frame from the list of methods to search |
|
132 */ |
|
133 private void findFirst() { |
|
134 checkNextFrameFor(null /* topmost frame */, |
|
135 new ResolvedJavaMethod[] |
|
136 {FRAME2_METHOD, FRAME3_METHOD, FRAME4_METHOD}, |
|
137 FRAME4_METHOD, 0); |
|
138 } |
|
139 |
|
140 /** |
|
141 * Walks through whole stack and checks that every frame could be found |
|
142 * while going down the stack till the end |
|
143 */ |
|
144 private void walkThrough() { |
|
145 // Check that we would get a frame 4 starting from the topmost frame |
|
146 HotSpotStackFrameReference nextStackFrame = checkNextFrameFor( |
|
147 null /* topmost frame */, |
|
148 new ResolvedJavaMethod[] {FRAME4_METHOD}, |
|
149 FRAME4_METHOD, 0); |
|
150 // Check that we would get a frame 3 starting from frame 4 when we try |
|
151 // to search one of the next two frames |
|
152 nextStackFrame = checkNextFrameFor(nextStackFrame, |
|
153 new ResolvedJavaMethod[] {FRAME3_METHOD, |
|
154 FRAME2_METHOD}, |
|
155 FRAME3_METHOD, 0); |
|
156 // Check that we would get a frame 1 |
|
157 nextStackFrame = checkNextFrameFor(nextStackFrame, |
|
158 new ResolvedJavaMethod[] {FRAME1_METHOD}, |
|
159 FRAME1_METHOD, 0); |
|
160 // Check that we would skip (RECURSION_AMOUNT - 1) methods and find a |
|
161 // recursionFrame starting from frame 1 |
|
162 nextStackFrame = checkNextFrameFor(nextStackFrame, |
|
163 new ResolvedJavaMethod[] {REC_FRAME_METHOD}, |
|
164 REC_FRAME_METHOD, RECURSION_AMOUNT - 1); |
|
165 // Check that we would get a Thread::run method frame; |
|
166 nextStackFrame = checkNextFrameFor(nextStackFrame, |
|
167 new ResolvedJavaMethod[] {RUN_METHOD}, |
|
168 RUN_METHOD, 0); |
|
169 // Check that there are no more frames after thread's run method |
|
170 nextStackFrame = CompilerToVMHelper.getNextStackFrame(nextStackFrame, |
|
171 null /* any */, 0); |
|
172 Asserts.assertNull(nextStackFrame, |
|
173 "Found stack frame after Thread::run"); |
|
174 } |
|
175 |
|
176 /** |
|
177 * Skips all frames to get null at the end of the stack |
|
178 */ |
|
179 private void skipAll() { |
|
180 // Skip all frames (stack size) + 2 (getNextStackFrame() itself |
|
181 // and from CompilerToVMHelper) |
|
182 int initialSkip = Thread.currentThread().getStackTrace().length + 2; |
|
183 HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper |
|
184 .getNextStackFrame(null /* topmost frame */, null /* any */, |
|
185 initialSkip); |
|
186 Asserts.assertNull(nextStackFrame, "Unexpected frame"); |
|
187 } |
|
188 |
|
189 /** |
|
190 * Search for any frame skipping one frame |
|
191 */ |
|
192 private void findNextSkipped() { |
|
193 // Get frame 4 |
|
194 HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper |
|
195 .getNextStackFrame(null /* topmost frame */, |
|
196 new ResolvedJavaMethod[] {FRAME4_METHOD}, 0); |
|
197 // Get frame 2 by skipping one method starting from frame 4 |
|
198 checkNextFrameFor(nextStackFrame, null /* any */, |
|
199 FRAME2_METHOD , 1 /* skip one */); |
|
200 } |
|
201 |
|
202 /** |
|
203 * Finds test method in the stack |
|
204 */ |
|
205 private void findYourself() { |
|
206 Method method; |
|
207 Class<?> aClass = CompilerToVMHelper.CompilerToVMClass(); |
|
208 try { |
|
209 method = aClass.getDeclaredMethod( |
|
210 "getNextStackFrame", |
|
211 HotSpotStackFrameReference.class, |
|
212 ResolvedJavaMethod[].class, |
|
213 int.class); |
|
214 } catch (NoSuchMethodException e) { |
|
215 throw new Error("TEST BUG: can't find getNextStackFrame : " + e, e); |
|
216 } |
|
217 ResolvedJavaMethod self |
|
218 = CTVMUtilities.getResolvedMethod(aClass, method); |
|
219 checkNextFrameFor(null /* topmost frame */, null /* any */, self, 0); |
|
220 } |
|
221 |
|
222 /** |
|
223 * Searches next frame and checks that it equals to expected |
|
224 * |
|
225 * @param currentFrame start frame to search from |
|
226 * @param searchMethods a list of methods to search |
|
227 * @param expected expected frame |
|
228 * @param skip amount of frames to be skipped |
|
229 * @return frame reference |
|
230 */ |
|
231 private HotSpotStackFrameReference checkNextFrameFor( |
|
232 HotSpotStackFrameReference currentFrame, |
|
233 ResolvedJavaMethod[] searchMethods, |
|
234 ResolvedJavaMethod expected, |
|
235 int skip) { |
|
236 HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper |
|
237 .getNextStackFrame(currentFrame, searchMethods, skip); |
|
238 Asserts.assertNotNull(nextStackFrame); |
|
239 Asserts.assertTrue(nextStackFrame.isMethod(expected), |
|
240 "Unexpected next frame: " + nextStackFrame |
|
241 + " from current frame: " + currentFrame); |
|
242 return nextStackFrame; |
|
243 } |
|
244 } |
|