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