//
// Copyright (C) 2007 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.mc.basic;
import org.junit.Test;
import de.fosd.typechef.featureexpr.FeatureExpr;
import de.fosd.typechef.featureexpr.FeatureExprFactory;
import gov.nasa.jpf.ListenerAdapter;
import gov.nasa.jpf.jvm.bytecode.DSTORE;
import gov.nasa.jpf.jvm.bytecode.INVOKEVIRTUAL;
import gov.nasa.jpf.jvm.bytecode.ISTORE;
import gov.nasa.jpf.jvm.bytecode.InvokeInstruction;
import gov.nasa.jpf.jvm.bytecode.LRETURN;
import gov.nasa.jpf.util.ObjectList;
import gov.nasa.jpf.util.test.TestJPF;
import gov.nasa.jpf.vm.Instruction;
import gov.nasa.jpf.vm.MethodInfo;
import gov.nasa.jpf.vm.StackFrame;
import gov.nasa.jpf.vm.ThreadInfo;
import gov.nasa.jpf.vm.VM;
import gov.nasa.jpf.vm.Verify;
/**
* raw test for field/operand/local attribute handling
*/
@SuppressWarnings({ "unused" })
public class AttrsTest extends TestJPF {
//------------ this part we only need outside of JPF execution
static class AttrType {
public String toString() {
return "<an AttrType>";
}
}
static final AttrType ATTR = new AttrType();
static final Class<?> ATTR_CLASS = ATTR.getClass();
public static class IntListener extends ListenerAdapter {
public IntListener () {}
@Override
public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn){
MethodInfo mi = executedInsn.getMethodInfo();
// not very efficient, but who cares - it's a small test
if (executedInsn instanceof ISTORE){
if (mi.getName().equals("testIntPropagation")){
ISTORE istore = (ISTORE)executedInsn;
String localName = istore.getLocalVariableName();
int localIndex = istore.getLocalVariableIndex();
if (localName.equals("i")){
StackFrame frame = ti.getModifiableTopFrame();
frame.setLocalAttr(localIndex, ATTR);
Object a = frame.getLocalAttr(localIndex, ATTR_CLASS);
System.out.println("'i' attribute set to: " + a);
} else if (localName.equals("j")){
StackFrame frame = ti.getTopFrame();
Object a = frame.getLocalAttr(localIndex, ATTR_CLASS);
System.out.println("'j' AttrType attribute: " + a);
}
}
}
}
}
static int sInt;
int iInt;
static double sDouble;
double iDouble;
int echoInt (int a){
return a;
}
@Test public void testIntPropagation () {
if (verifyNoPropertyViolation("+listener=.test.mc.basic.AttrsTest$IntListener")) {
int i = 42; // this gets attributed
Verify.setLocalAttribute("i", 42); // this overwrites whatever the ISTORE listener did set on 'i'
int attr = Verify.getLocalAttribute("i");
Verify.println("'i' attribute after Verify.setLocalAttribute(\"i\",42): " + attr);
assertTrue( attr == 42);
iInt = echoInt(i); // return val -> instance field
sInt = iInt; // instance field -> static field
int j = sInt; // static field -> local - now j should have the initial i attribute, and value 42
attr = Verify.getLocalAttribute("j");
Verify.println("'j' attribute after assignment: " + attr);
assertTrue( attr == 42);
}
}
//----------------------------------------------------------------------------------------------
public static class DoubleListener extends ListenerAdapter {
public DoubleListener () {}
@Override
public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn){
MethodInfo mi = executedInsn.getMethodInfo();
if (executedInsn instanceof DSTORE){
if (mi.getName().equals("testDoublePropagation")){
DSTORE dstore = (DSTORE)executedInsn;
String localName = dstore.getLocalVariableName();
int localIndex = dstore.getLocalVariableIndex();
if (localName.equals("d")){
StackFrame frame = ti.getModifiableTopFrame();
System.out.print("listener setting 'd' attr = ");
frame.setLocalAttr(localIndex, ATTR);
Object a = frame.getLocalAttr(localIndex);
System.out.println( a);
} else if (localName.equals("r")){
StackFrame frame = ti.getTopFrame();
Object a = frame.getLocalAttr(localIndex, ATTR_CLASS);
System.out.println("'r' attribute: " + a);
/** get's overwritten in the model class
if (a != ATTR){
throw new JPFException("attribute propagation failed");
}
**/
}
}
}
}
}
@Test public void testDoublePropagation () {
if (verifyNoPropertyViolation("+listener=.test.mc.basic.AttrsTest$DoubleListener")) {
double d = 42.0; // this gets attributed
Verify.setLocalAttribute("d", 42); // this overwrites whatever the DSTORE listener did set on 'd'
int attr = Verify.getLocalAttribute("d");
assert attr == 42;
// some noise on the stack
iDouble = echoDouble(d);
sDouble = iDouble;
//double r = sDouble; // now r should have the same attribute
double r = echoDouble(d);
attr = Verify.getLocalAttribute("r");
Verify.print("@ 'r' attribute after assignment: " + attr);
Verify.println();
assert attr == 42;
}
}
//-----------------------------------------------------------------------------------------------
public static class InvokeListener extends ListenerAdapter {
@Override
public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn){
if (executedInsn instanceof InvokeInstruction) {
InvokeInstruction call = (InvokeInstruction)executedInsn;
MethodInfo mi = call.getInvokedMethod();
String mName = mi.getName();
if (mName.equals("goModel") || mName.equals("goNative")) {
Object[] a = call.getArgumentAttrs(ti);
assert a != null & a.length == 3;
System.out.println("listener notified of: " + mName + "(), attributes= "
+ a[0] + ',' + a[1] + ',' + a[2]);
// note - this is only acceptable if we know exactly there are just
// single attrs
assert a[0] instanceof Integer && a[1] instanceof Integer;
assert (((Integer)a[0]).intValue() == 1) &&
(((Integer)a[1]).intValue() == 2) &&
(((Integer)a[2]).intValue() == 3);
}
}
}
}
@Test public void testInvokeListener () {
if (verifyNoPropertyViolation("+listener=.test.mc.basic.AttrsTest$InvokeListener")) {
Verify.setLocalAttribute("this", 1);
double d = 42.0;
Verify.setLocalAttribute("d", 2);
int i = 42;
Verify.setLocalAttribute("i", 3);
double result = goNative(d, i); // that's going to be listened on
int attr = Verify.getLocalAttribute("result");
Verify.print("@ 'result' attribute: " + attr);
Verify.println();
assert attr == 6;
int r = goModel(d, i); // that's listened for, too
assert r == 6;
}
}
native double goNative (double d, int i);
@Test public void testNativeMethod () {
if (verifyNoPropertyViolation()) {
Verify.setLocalAttribute("this", 1);
double d = 42.0;
Verify.setLocalAttribute("d", 2);
int i = 42;
Verify.setLocalAttribute("i", 3);
double result = goNative(d, i);
int attr = Verify.getLocalAttribute("result");
Verify.print("@ 'result' attribute: " + attr);
Verify.println();
assert attr == 6;
}
}
int goModel (double d, int i) {
int a1 = Verify.getLocalAttribute("d");
int a2 = Verify.getLocalAttribute("i");
return a1*a2;
}
double echoDouble (double d){
return d;
}
@Test public void testExplicitRef () {
if (verifyNoPropertyViolation()) {
int attr = Verify.getFieldAttribute(this, "iDouble");
Verify.print("@ 'iDouble' attribute before set: ", Integer.toString(attr));
Verify.println();
Verify.setFieldAttribute(this, "iDouble", 42);
attr = Verify.getFieldAttribute(this, "iDouble");
Verify.print("@ 'iDouble' attribute after set: ", Integer.toString(attr));
Verify.println();
assert attr == 42;
}
}
@Test public void testExplicitArrayRef () {
if (verifyNoPropertyViolation()) {
int attr;
double[] myArray = new double[10];
attr = Verify.getElementAttribute(myArray, 5);
Verify.print("@ 'myArray[5]' attribute before set: ", Integer.toString(attr));
Verify.println();
Verify.setElementAttribute(myArray, 5, 42);
attr = Verify.getElementAttribute(myArray, 5);
Verify.print("@ 'myArray[5]' attribute after set: ", Integer.toString(attr));
Verify.println();
assert attr == 42;
}
}
@Test public void testArraycopy () {
if (verifyNoPropertyViolation()) {
int attr;
double[] a1 = new double[10];
double[] a2 = new double[10];
Verify.setElementAttribute(a1, 3, 42);
System.arraycopy(a1, 1, a2, 0, 3);
attr = Verify.getElementAttribute(a2, 2);
assert attr == 42;
}
}
double ddd;
@Test public void testArrayPropagation() {
if (verifyNoPropertyViolation()) {
int attr;
double[] a1 = new double[10];
double[] a2 = new double[10];
Verify.setElementAttribute(a1, 3, 42);
attr = Verify.getElementAttribute(a1, 3);
System.out.println("@ a1 : " + attr);
//attr = Verify.getElementAttribute(a1,3);
//System.out.println(attr);
ddd = a1[3];
//Verify.setFieldAttribute(this,"ddd",42);
//attr = Verify.getFieldAttribute(this,"ddd");
//System.out.println("@ ddd : " + attr);
double d = ddd;
//ccc = d;
//attr = Verify.getFieldAttribute(this,"ccc");
//System.out.println("ccc ; " + attr);
//double d = a1[3]; // now d should have the attr
a2[0] = d;
attr = Verify.getElementAttribute(a2, 0);
System.out.println("@ a2[0] : " + attr);
assert attr == 42;
}
}
@Test public void testBacktrack() {
if (verifyNoPropertyViolation()) {
int v = 42; // need to init or the compiler does not add it to the name table
Verify.setLocalAttribute("v", 42);
boolean b = Verify.getBoolean(); // restore point
System.out.println(b);
int attr = Verify.getLocalAttribute("v");
System.out.println(attr);
Verify.setLocalAttribute("v", -1);
attr = Verify.getLocalAttribute("v");
System.out.println(attr);
}
}
@Test public void testInteger() {
if (verifyNoPropertyViolation()) {
int v = 42;
Verify.setLocalAttribute("v", 4200);
// explicit
Integer o = new Integer(v);
int j = o.intValue();
int attr = Verify.getLocalAttribute("j");
assert attr == 4200;
// semi autoboxed
j = o;
boolean b = Verify.getBoolean(); // just cause some backtracking damage
attr = Verify.getLocalAttribute("j");
assert attr == 4200;
/** this does not work because of cached, preallocated Integer objects)
// fully autoboxed
Integer a = v;
j = a;
attr = Verify.getLocalAttribute("j");
assert attr == 4200;
**/
}
}
@Test public void testObjectAttr(){
if (verifyNoPropertyViolation()){
Integer o = new Integer(41);
Verify.setObjectAttribute(o, 42);
boolean b = Verify.getBoolean();
int attr = Verify.getObjectAttribute(o);
System.out.println("object attr = " + attr);
assert attr == 42;
}
}
//--- the multiple attributes tests
@Test
public void testIntAttrList(){
if (verifyNoPropertyViolation()){
int var = 42;
Verify.addLocalAttribute("var", Integer.valueOf(var));
Verify.addLocalAttribute("var", Integer.valueOf(-var));
int x = var;
int[] attrs = Verify.getLocalAttributes("x");
for (int i=0; i<attrs.length; i++){
System.out.printf("[%d] = %d\n", i, attrs[i]);
}
assertTrue( attrs.length == 2);
assertTrue( attrs[0] == -var); // lifo
assertTrue( attrs[1] == var);
}
}
public static class MixedAttrTypeListener extends ListenerAdapter {
public MixedAttrTypeListener() {}
@Override
public void executeInstruction (FeatureExpr ctx, VM vm, ThreadInfo ti, Instruction insnToExecute){
if (insnToExecute instanceof INVOKEVIRTUAL){
MethodInfo callee = ((INVOKEVIRTUAL)insnToExecute).getInvokedMethod();
if (callee.getUniqueName().equals("foo(J)J")){
System.out.println("--- pre-exec foo() invoke interception, setting arg attrs");
StackFrame frame = ti.getModifiableTopFrame();
// we are still in the caller stackframe
frame.addLongOperandAttr("foo-arg");
Long v = Long.valueOf( frame.peekLong(FeatureExprFactory.True()).getValue());
frame.addLongOperandAttr( v);
System.out.println(" operand attrs:");
for (Object a: frame.longOperandAttrIterator()){
System.out.println(a);
}
}
} else if (insnToExecute instanceof LRETURN){
MethodInfo mi = insnToExecute.getMethodInfo();
if (mi.getUniqueName().equals("foo(J)J")){
System.out.println("--- pre-exec foo() return interception");
StackFrame frame = ti.getModifiableTopFrame();
int varIdx = frame.getLocalVariableSlotIndex("x");
Object attr = frame.getLocalAttr(varIdx);
System.out.println(" got 'x' attributes");
for (Object a: frame.localAttrIterator(varIdx)){
System.out.println(a);
}
assertTrue(attr.equals("foo-arg"));
System.out.println(" setting lreturn operand attrs");
frame.addLongOperandAttr("returned");
for (Object a: frame.longOperandAttrIterator()){
System.out.println(a);
}
}
}
}
@Override
public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn){
if (executedInsn instanceof INVOKEVIRTUAL){
MethodInfo callee = ((INVOKEVIRTUAL)executedInsn).getInvokedMethod();
if (callee.getUniqueName().equals("foo(J)J")){
System.out.println("--- post-exec foo() invoke interception");
StackFrame frame = ti.getModifiableTopFrame(); // we are now in the callee
int varIdx = frame.getLocalVariableSlotIndex("x");
for (Object a: frame.localAttrIterator(varIdx)){
System.out.println(a);
}
Object attrs = frame.getLocalAttr(varIdx);
assertTrue( ObjectList.size(attrs) == 2);
Object sAttr = frame.getLocalAttr(varIdx, String.class);
assertTrue( sAttr != null && sAttr.equals("foo-arg"));
assertTrue( frame.getNextLocalAttr(varIdx, String.class, sAttr) == null);
Object lAttr = frame.getLocalAttr(varIdx, Long.class);
assertTrue( lAttr != null && lAttr.equals( frame.getLongLocalVariable(FeatureExprFactory.True(), varIdx)));
assertTrue( frame.getNextLocalAttr(varIdx, Long.class, lAttr) == null);
frame.removeLocalAttr(varIdx, lAttr);
System.out.println(" removing " + lAttr);
for (Object a: frame.localAttrIterator(varIdx)){
System.out.println(a);
}
}
} else if (executedInsn instanceof LRETURN){
MethodInfo mi = executedInsn.getMethodInfo();
if (mi.getUniqueName().equals("foo(J)J")){
StackFrame frame = ti.getTopFrame();
System.out.println("--- post-exec foo() return interception");
for (Object a: frame.longOperandAttrIterator()){
System.out.println(a);
}
String a = frame.getLongOperandAttr(String.class);
assertTrue( a.equals("returned"));
a = frame.getNextLongOperandAttr(String.class, a);
assertTrue( a.equals("foo-arg"));
a = frame.getNextLongOperandAttr(String.class, a);
assertTrue(a == null);
}
}
}
}
long foo (long x){
return x;
}
@Test
public void testListenerMixedLongAttrLists(){
if (verifyNoPropertyViolation("+listener=.test.mc.basic.AttrsTest$MixedAttrTypeListener")){
foo(42);
}
}
}