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 }