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