//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package gov.nasa.jpf.test.basic;
import cmu.conditional.One;
import de.fosd.typechef.featureexpr.FeatureExpr;
import de.fosd.typechef.featureexpr.FeatureExprFactory;
import gov.nasa.jpf.annotation.MJI;
import gov.nasa.jpf.vm.DirectCallStackFrame;
import gov.nasa.jpf.vm.MJIEnv;
import gov.nasa.jpf.vm.MethodInfo;
import gov.nasa.jpf.vm.NativePeer;
import gov.nasa.jpf.vm.ThreadInfo;
import gov.nasa.jpf.vm.UncaughtException;
/**
* native peer class for unit testing MJI
*/
public class JPF_gov_nasa_jpf_test_basic_MJITest extends NativePeer {
// intercept <clinit>
@MJI
public void $clinit (MJIEnv env, int rcls, FeatureExpr ctx) {
System.out.println("# entering native <clinit>");
env.setStaticIntField(ctx, rcls, "sdata", One.valueOf(42));
}
// intercept MJITest(int i) ctor
@MJI
public void $init__I__V (MJIEnv env, int robj, int i, FeatureExpr ctx) {
// NOTE : if we directly intercept the ctor, then we also have
// to take care of calling the proper superclass ctors
// better approach is to refactor this into a separate native method
// (say init0(..))
System.out.println("# entering native <init>(I)");
env.setIntField(ctx, robj, "idata", One.valueOf(i));
}
@MJI
public int nativeCreate2DimIntArray__II___3_3I (MJIEnv env, int robj, int size1,
int size2, FeatureExpr ctx) {
System.out.println("# entering nativeCreate2DimIntArray()");
int ar = env.newObjectArray("[I", size1);
for (int i = 0; i < size1; i++) {
int ea = env.newIntArray(size2);
if (i == 1) {
env.setIntArrayElement(ctx, ea, 1, One.valueOf(42));
}
env.setReferenceArrayElement(ctx, ar, i, new One<>(ea));
}
return ar;
}
// check if the non-mangled name lookup works
@MJI
public int nativeCreateIntArray (MJIEnv env, int robj, int size, FeatureExpr ctx) {
System.out.println("# entering nativeCreateIntArray()");
int ar = env.newIntArray(size);
env.setIntArrayElement(ctx, ar, 1, One.valueOf(1));
return ar;
}
@MJI
public int nativeCreateStringArray (MJIEnv env, int robj, int size, FeatureExpr ctx) {
System.out.println("# entering nativeCreateStringArray()");
int ar = env.newObjectArray("Ljava/lang/String;", size);
env.setReferenceArrayElement(ctx, ar, 1, new One<>(env.newString(FeatureExprFactory.True(), "one")));
return ar;
}
@MJI
public void nativeException____V (MJIEnv env, int robj, FeatureExpr ctx) {
System.out.println("# entering nativeException()");
env.throwException(ctx, "java.lang.UnsupportedOperationException", "caught me");
}
@SuppressWarnings("null")
@MJI
public int nativeCrash (MJIEnv env, int robj, FeatureExpr ctx) {
System.out.println("# entering nativeCrash()");
String s = null;
return s.length();
}
@MJI
public int nativeInstanceMethod (MJIEnv env, int robj, double d,
char c, boolean b, int i, FeatureExpr ctx) {
System.out.println("# entering nativeInstanceMethod() d=" + d +
", c=" + c + ", b=" + b + ", i=" + i);
if ((d == 2.0) && (c == '?') && b) {
return i + 2;
}
return 0;
}
@SuppressWarnings("deprecation")
@MJI
public long nativeStaticMethod__JLjava_lang_String_2__J (MJIEnv env, int rcls, long l,
int stringRef, FeatureExpr ctx) {
System.out.println("# entering nativeStaticMethod()");
String s = env.getStringObject(ctx, stringRef);
if ("Blah".equals(s)) {
return l + 2;
}
return 0;
}
/*
* nativeRoundtripLoop shows how to
*
* (1) round trip into JPF executed code from within native methods
*
* (2) loop inside of native methods that do round trips (using the
* DirectCallStackFrame's local slots)
*
* the call chain is:
*
* JPF: testRoundtripLoop
* VM: nativeRoundTripLoop x 3
* JPF: roundtrip
* VM: nativeInnerRoundtrip
*/
@MJI
public int nativeInnerRoundtrip__I__I (MJIEnv env, int robj, int a, FeatureExpr ctx){
System.out.println("# entering nativeInnerRoundtrip()");
return a+2;
}
@MJI
public int nativeRoundtripLoop__I__I (MJIEnv env, int robj, int a, FeatureExpr ctx) {
System.out.println("# entering nativeRoundtripLoop(): " + a);
MethodInfo mi = env.getClassInfo(robj).getMethod("roundtrip(I)I",false);
ThreadInfo ti = env.getThreadInfo();
DirectCallStackFrame frame = ti.getReturnedDirectCall();
if (frame == null){ // first time
frame = mi.createDirectCallStackFrame(ctx, ti, 1);
frame.setLocalVariable(ctx, 0, 0);
int argOffset = frame.setReferenceArgument(ctx, 0, robj, null);
frame.setArgument( argOffset, a+1, null);
ti.pushFrame(frame);
return 42; // whatever, we come back
} else { // direct call returned
// this method can't be executed unless the class is already initialized,
// i.e. we don't have to check for overlayed clinit calls and the frame
// has to be the one we pushed
assert frame.getCallee() == mi;
// this shows how to get information back from the JPF roundtrip into
// the native method
int r = frame.getResult(); // the return value of the direct call above
int i = frame.getLocalVariable(ctx, 0).getValue();
if (i < 3) { // repeat the round trip
// we have to reset so that the PC is re-initialized
frame.reset();
frame.setLocalVariable(ctx, 0, i + 1);
int argOffset = frame.setReferenceArgument( ctx, 0, robj, null);
frame.setArgument( argOffset, r+1, null);
ti.pushFrame(frame);
return 42;
} else { // done, return the final value
return r;
}
}
}
/**
* this shows how to synchronously JPF-enter a method from native peer or
* listener code
*/
@MJI
public int nativeHiddenRoundtrip__I__I (MJIEnv env, int robj, int a, FeatureExpr ctx){
ThreadInfo ti = env.getThreadInfo();
System.out.println("# entering nativeHiddenRoundtrip: " + a);
MethodInfo mi = env.getClassInfo(robj).getMethod("atomicStuff(I)I",false);
DirectCallStackFrame frame = mi.createDirectCallStackFrame(ctx, ti, 0);
int argOffset = frame.setReferenceArgument( ctx, 0, robj, null);
frame.setArgument( argOffset, a, null);
frame.setFireWall();
try {
ti.executeMethodHidden(frame);
//ti.advancePC();
} catch (UncaughtException ux) { // frame's method is firewalled
System.out.println("# hidden method execution failed, leaving nativeHiddenRoundtrip: " + ux);
ti.clearPendingException();
ti.popFrame(ctx); // this is still the DirectCallStackFrame, and we want to continue execution
return -1;
}
// get the return value from the (already popped) frame
int res = frame.getResult();
System.out.println("# exit nativeHiddenRoundtrip: " + res);
return res;
}
}