/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
import org.jikesrvm.VM;
import org.jikesrvm.runtime.Magic;
/**
* Test stack resize with native methods, various scenarios:
* -first entry to native code: first resize
* -second nested entry to native code: no resize
* -fill up stack and make another entry to native code: second resize
*/
class StackResize {
static boolean verbose = true; // set to true to get messages for each test
static boolean allTestPass = true;
public static native boolean expectResize(int count);
/* native method to be invoked when native frame exists on stack
* Stack should not be resized
*/
public static native boolean expectNoResize(int count);
/* Java callback from native
* From here we do another native call which should not cause the
* stack to resize because there are native frames on the stack
*/
public static boolean makeSecondNativeCall() {
Thread th = Thread.getCurrentThread();
int currentStackSize = Magic.getArrayLength(th.stack);
// call another native method
boolean resizeDidNotOccur = expectNoResize(currentStackSize);
if (resizeDidNotOccur == false) {
if (verbose)
VM.sysWriteln("> Unexpected stack resize with native frame present");
return false;
}
return true;
}
public static boolean checkResizeOccurred(int previousStackSize) {
Thread th = Thread.getCurrentThread();
int currentStackSize = Magic.getArrayLength(th.stack);
if (verbose) {
VM.sysWrite("check resize: previous ");
VM.sysWrite(previousStackSize);
VM.sysWrite(", current ");
VM.sysWrite(currentStackSize);
VM.sysWriteln();
}
return !(currentStackSize == previousStackSize);
}
/* recurse until the frame is within a few words of the
* stack limit, then call a native method expecting the
* stack to get resized.
*/
@NoOptCompile
public static boolean nativeWithStackAlmostFull() {
Thread th = Thread.getCurrentThread();
// VM.disableGC(); // holding frame pointer
int fp = Magic.getFramePointer();
int spaceLeft = fp - th.stackLimit;
// debug printing: OK until last frame, will cause stack overflow
// because sysWrite will need many frames
// VM.sysWrite("filling: left ");
// VM.sysWrite(spaceLeft); VM.sysWriteln();
// recursion to fill stack up to 3 words left
if ((spaceLeft) > (500 * 4)) {
// VM.enableGC();
return nativeWithStackAlmostFull();
} else {
// VM.enableGC();
int currentStackSize = Magic.getArrayLength(th.stack);
boolean resizeOccurred = expectResize(currentStackSize);
if (resizeOccurred) {
return true;
} else {
if (verbose)
VM.sysWriteln("> Second stack resize did not occur");
return false;
}
}
}
public static void main(String[] args) {
boolean returnValue;
FieldAccess tempObject;
System.loadLibrary("StackResize");
if (args.length != 0) {
if (args[0].equals("-quiet")) {
verbose = false;
// for verbose native, have to edit the flag in StackResize.c
}
}
if (verbose)
VM.sysWriteln("Checking stack size");
// Test 1
// First check if the current stack size is smaller than
// required for native call
Thread th = Thread.getCurrentThread();
int currentStackSpace = Magic.getArrayLength(th.stack);
if (currentStackSpace > VM.STACK_SIZE_JNINATIVE) {
if (verbose) {
VM.sysWriteln("StackResize: normal stack size already exceeds native requirement, stack will not get resized. Set up the system configuration for smaller normal stack: StackFrameLayoutConstants.java");
VM.sysWriteln();
}
VM.sysWriteln("FAIL: StackResize");
}
if (verbose)
VM.sysWriteln("Starting test 1");
// proceed with resize test
returnValue = expectResize(currentStackSpace);
checkTest(0, returnValue, "first stack resize");
// Test 2
// After the stack has been resized once, fill up the stack
// and call native again to force a second resize
if (verbose)
VM.sysWriteln("Starting test 2");
returnValue = nativeWithStackAlmostFull();
checkTest(0, returnValue, "second stack resize");
if (allTestPass)
System.out.println("PASS: StackResize");
else
System.out.println("FAIL: StackResize");
}
static void checkTest(int returnValue, boolean postCheck, String testName) {
if (returnValue == 0 && postCheck) {
printVerbose("PASS: " + testName);
} else {
allTestPass = false;
printVerbose("FAIL: " + testName);
}
}
static void printVerbose(String str) {
if (verbose)
System.out.println(str);
}
}