// // Copyright (C) 2010 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.jvm.bytecode; import cmu.conditional.Conditional; import cmu.conditional.One; import de.fosd.typechef.featureexpr.FeatureExpr; import gov.nasa.jpf.vm.Instruction; import gov.nasa.jpf.vm.NativeStackFrame; import gov.nasa.jpf.vm.StackFrame; import gov.nasa.jpf.vm.ThreadInfo; import gov.nasa.jpf.vm.Types; /** * synthetic return instruction for native method invocations, so that * we don't have to do special provisions to copy the caller args in case * a post exec listener wants them. */ public class NATIVERETURN extends ReturnInstruction { Object ret; Object retAttr; Byte retType; // this is more simple than a normal ReturnInstruction because NativeMethodInfos // are not synchronized, and NativeStackFrames are never the first frame in a thread @Override public Conditional<Instruction> execute(FeatureExpr ctx, ThreadInfo ti) { if (!ti.isFirstStepInsn()) { ti.leave(); // takes care of unlocking before potentially creating a CG // NativeMethodInfo is never synchronized, so no thread CG here } StackFrame frame = ti.getModifiableTopFrame(); getAndSaveReturnValue(frame, ctx); // NativeStackFrame can never can be the first stack frame, so no thread CG frame = ti.popAndGetModifiableTopFrame(ctx); // remove args, push return value and continue with next insn frame.removeArguments(ctx, mi); pushReturnValue(ctx, frame); if (retAttr != null) { setReturnAttr(ti, retAttr); } return getNext(ctx, ti); } @Override public void cleanupTransients() { ret = null; retAttr = null; returnFrame = null; } @Override public boolean isExtendedInstruction() { return true; } public static final int OPCODE = 260; @Override public int getByteCode() { return OPCODE; } @Override public void accept(InstructionVisitor insVisitor) { insVisitor.visit(this); } @Override protected void getAndSaveReturnValue(StackFrame frame, FeatureExpr ctx) { // it's got to be a NativeStackFrame since this insn is created by JPF NativeStackFrame nativeFrame = (NativeStackFrame) frame; returnFrame = nativeFrame; ret = nativeFrame.getReturnValue(); retAttr = nativeFrame.getReturnAttr(); retType = nativeFrame.getMethodInfo().getReturnTypeCode(); } public int getReturnTypeSize() { switch (retType) { case Types.T_BOOLEAN: case Types.T_BYTE: case Types.T_CHAR: case Types.T_SHORT: case Types.T_INT: case Types.T_FLOAT: return 1; case Types.T_LONG: case Types.T_DOUBLE: return 2; default: return 1; } } // this is only called internally right before we return protected Object getReturnedOperandAttr(FeatureExpr ctx, StackFrame frame) { return retAttr; } // <2do> this should use the getResult..() methods of NativeStackFrame @SuppressWarnings({ "rawtypes", "unchecked" }) @Override protected void pushReturnValue(FeatureExpr ctx, StackFrame fr) { int retSize = 1; // in case of a return type mismatch, we get a ClassCastException, which // is handled in executeMethod() and reported as a InvocationTargetException // (not completely accurate, but we rather go with safety) if (ret != null) { switch (retType) { case Types.T_BOOLEAN: if (ret instanceof Conditional) { fr.push(ctx, ((Conditional) ret).map(ret -> Types.booleanToInt(((Boolean) ret).booleanValue()))); } else { fr.push(ctx, One.valueOf(Types.booleanToInt(((Boolean) ret).booleanValue()))); } break; case Types.T_BYTE: fr.push(ctx, One.valueOf((int) (((Byte) ret).byteValue()))); break; case Types.T_CHAR: if (ret instanceof Conditional) { fr.push(ctx, ((Conditional) ret).map(ret -> (int) ((Character) ret).charValue())); } else { fr.push(ctx, One.valueOf((int) ((Character) ret).charValue())); } break; case Types.T_SHORT: fr.push(ctx, One.valueOf((int) ((Short) ret).shortValue())); break; case Types.T_INT: if (ret instanceof Conditional) { fr.push(ctx, (Conditional) ret); } else { fr.push(ctx, One.valueOf(((Integer) ret))); } break; case Types.T_LONG: if (ret instanceof Conditional) { fr.push(ctx, ((Conditional) ret)); } else { fr.push(ctx, new One<>((Long) ret)); retSize = 2; } retSize = 2; break; case Types.T_FLOAT: if (ret instanceof Conditional) { fr.push(ctx, ((Conditional<Float>) ret).map(x -> Types.floatToInt(x))); } else { fr.push(ctx, One.valueOf(Types.floatToInt((Float) ret))); } break; case Types.T_DOUBLE: if (ret instanceof Conditional) { fr.push(ctx, ((Conditional<Double>) ret).map(x -> Types.doubleToLong(x))); } else { long lval = Types.doubleToLong(((Double) ret).doubleValue()); fr.push(ctx, new One<>(lval)); } retSize = 2; break; default: // everything else is supposed to be a reference if (ret instanceof Conditional) { fr.push(ctx, (Conditional) ret, true); } else { fr.push(ctx, ((Integer) ret).intValue(), true); } } if (retAttr != null) { if (retSize == 1) { fr.setOperandAttr(retAttr); } else { fr.setLongOperandAttr(retAttr); } } } } @Override public Object getReturnAttr(ThreadInfo ti) { if (isCompleted(ti)) { return retAttr; } else { NativeStackFrame nativeFrame = (NativeStackFrame) ti.getTopFrame(); return nativeFrame.getReturnAttr(); } } @Override public Object getReturnValue(FeatureExpr ctx, ThreadInfo ti) { if (isCompleted(ti)) { return ret; } else { NativeStackFrame nativeFrame = (NativeStackFrame) ti.getTopFrame(); return nativeFrame.getReturnValue(); } } // public String toString(){ // StringBuilder sb = new StringBuilder(); // sb.append(super.toString()); // sb.append(" "); // sb.append(mi.getFullName()); // // return sb.toString(); // } }