blob: 10a75a8140270cb1c546061944fc436cfd97f98a [file] [log] [blame]
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8136421
* @requires vm.jvmci
* @library / /test/lib
* @library ../common/patches
* @modules java.base/jdk.internal.misc
* @modules java.base/jdk.internal.org.objectweb.asm
* java.base/jdk.internal.org.objectweb.asm.tree
* jdk.internal.vm.ci/jdk.vm.ci.hotspot
* jdk.internal.vm.ci/jdk.vm.ci.code
* jdk.internal.vm.ci/jdk.vm.ci.meta
* @build jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
* -Djvmci.Compiler=null
* compiler.jvmci.compilerToVM.GetNextStackFrameTest
*/
package compiler.jvmci.compilerToVM;
import compiler.jvmci.common.CTVMUtilities;
import jdk.test.lib.Asserts;
import jdk.vm.ci.hotspot.CompilerToVMHelper;
import jdk.vm.ci.hotspot.HotSpotStackFrameReference;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import java.lang.reflect.Method;
public class GetNextStackFrameTest {
private static final int RECURSION_AMOUNT = 3;
private static final ResolvedJavaMethod REC_FRAME_METHOD;
private static final ResolvedJavaMethod FRAME1_METHOD;
private static final ResolvedJavaMethod FRAME2_METHOD;
private static final ResolvedJavaMethod FRAME3_METHOD;
private static final ResolvedJavaMethod FRAME4_METHOD;
private static final ResolvedJavaMethod RUN_METHOD;
static {
Method method;
try {
Class<?> aClass = GetNextStackFrameTest.class;
method = aClass.getDeclaredMethod("recursiveFrame", int.class);
REC_FRAME_METHOD = CTVMUtilities.getResolvedMethod(method);
method = aClass.getDeclaredMethod("frame1");
FRAME1_METHOD = CTVMUtilities.getResolvedMethod(method);
method = aClass.getDeclaredMethod("frame2");
FRAME2_METHOD = CTVMUtilities.getResolvedMethod(method);
method = aClass.getDeclaredMethod("frame3");
FRAME3_METHOD = CTVMUtilities.getResolvedMethod(method);
method = aClass.getDeclaredMethod("frame4");
FRAME4_METHOD = CTVMUtilities.getResolvedMethod(method);
method = Thread.class.getDeclaredMethod("run");
RUN_METHOD = CTVMUtilities.getResolvedMethod(Thread.class, method);
} catch (NoSuchMethodException e) {
throw new Error("TEST BUG: can't find a test method : " + e, e);
}
}
public static void main(String[] args) {
new GetNextStackFrameTest().test();
}
private void test() {
// Create new thread to get new clean stack
Thread thread = new Thread(() -> recursiveFrame(RECURSION_AMOUNT));
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
throw new Error("Interrupted while waiting to join", e);
}
}
// Helper methods for a longer stack
private void recursiveFrame(int recursionAmount) {
if (--recursionAmount != 0) {
recursiveFrame(recursionAmount);
} else {
frame1();
}
}
private void frame1() {
frame2();
}
private void frame2() {
frame3();
}
private void frame3() {
frame4();
}
private void frame4() {
check();
}
private void check() {
findFirst();
walkThrough();
skipAll();
findNextSkipped();
findYourself();
}
/**
* Finds the first topmost frame from the list of methods to search
*/
private void findFirst() {
checkNextFrameFor(null /* topmost frame */,
new ResolvedJavaMethod[]
{FRAME2_METHOD, FRAME3_METHOD, FRAME4_METHOD},
FRAME4_METHOD, 0);
}
/**
* Walks through whole stack and checks that every frame could be found
* while going down the stack till the end
*/
private void walkThrough() {
// Check that we would get a frame 4 starting from the topmost frame
HotSpotStackFrameReference nextStackFrame = checkNextFrameFor(
null /* topmost frame */,
new ResolvedJavaMethod[] {FRAME4_METHOD},
FRAME4_METHOD, 0);
// Check that we would get a frame 3 starting from frame 4 when we try
// to search one of the next two frames
nextStackFrame = checkNextFrameFor(nextStackFrame,
new ResolvedJavaMethod[] {FRAME3_METHOD,
FRAME2_METHOD},
FRAME3_METHOD, 0);
// Check that we would get a frame 1
nextStackFrame = checkNextFrameFor(nextStackFrame,
new ResolvedJavaMethod[] {FRAME1_METHOD},
FRAME1_METHOD, 0);
// Check that we would skip (RECURSION_AMOUNT - 1) methods and find a
// recursionFrame starting from frame 1
nextStackFrame = checkNextFrameFor(nextStackFrame,
new ResolvedJavaMethod[] {REC_FRAME_METHOD},
REC_FRAME_METHOD, RECURSION_AMOUNT - 1);
// Check that we would get a Thread::run method frame;
nextStackFrame = checkNextFrameFor(nextStackFrame,
new ResolvedJavaMethod[] {RUN_METHOD},
RUN_METHOD, 0);
// Check that there are no more frames after thread's run method
nextStackFrame = CompilerToVMHelper.getNextStackFrame(nextStackFrame,
null /* any */, 0);
Asserts.assertNull(nextStackFrame,
"Found stack frame after Thread::run");
}
/**
* Skips all frames to get null at the end of the stack
*/
private void skipAll() {
// Skip all frames (stack size) + 2 (getNextStackFrame() itself
// and from CompilerToVMHelper)
int initialSkip = Thread.currentThread().getStackTrace().length + 2;
HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper
.getNextStackFrame(null /* topmost frame */, null /* any */,
initialSkip);
Asserts.assertNull(nextStackFrame, "Unexpected frame");
}
/**
* Search for any frame skipping one frame
*/
private void findNextSkipped() {
// Get frame 4
HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper
.getNextStackFrame(null /* topmost frame */,
new ResolvedJavaMethod[] {FRAME4_METHOD}, 0);
// Get frame 2 by skipping one method starting from frame 4
checkNextFrameFor(nextStackFrame, null /* any */,
FRAME2_METHOD , 1 /* skip one */);
}
/**
* Finds test method in the stack
*/
private void findYourself() {
Method method;
Class<?> aClass = CompilerToVMHelper.CompilerToVMClass();
try {
method = aClass.getDeclaredMethod(
"getNextStackFrame",
HotSpotStackFrameReference.class,
ResolvedJavaMethod[].class,
int.class);
} catch (NoSuchMethodException e) {
throw new Error("TEST BUG: can't find getNextStackFrame : " + e, e);
}
ResolvedJavaMethod self
= CTVMUtilities.getResolvedMethod(aClass, method);
checkNextFrameFor(null /* topmost frame */, null /* any */, self, 0);
}
/**
* Searches next frame and checks that it equals to expected
*
* @param currentFrame start frame to search from
* @param searchMethods a list of methods to search
* @param expected expected frame
* @param skip amount of frames to be skipped
* @return frame reference
*/
private HotSpotStackFrameReference checkNextFrameFor(
HotSpotStackFrameReference currentFrame,
ResolvedJavaMethod[] searchMethods,
ResolvedJavaMethod expected,
int skip) {
HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper
.getNextStackFrame(currentFrame, searchMethods, skip);
Asserts.assertNotNull(nextStackFrame);
Asserts.assertTrue(nextStackFrame.isMethod(expected),
"Unexpected next frame: " + nextStackFrame
+ " from current frame: " + currentFrame);
return nextStackFrame;
}
}