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