view src/main/gov/nasa/jpf/jvm/bytecode/NATIVERETURN.java @ 0:61d41facf527

initial v8 import (history reset)
author Peter Mehlitz <Peter.C.Mehlitz@nasa.gov>
date Fri, 23 Jan 2015 10:14:01 -0800
parents
children 8aded593a50f
line wrap: on
line source

/*
 * Copyright (C) 2014, United States Government, as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All rights reserved.
 *
 * The Java Pathfinder core (jpf-core) platform is licensed under the
 * Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 *        http://www.apache.org/licenses/LICENSE-2.0. 
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */

package gov.nasa.jpf.jvm.bytecode;

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 JVMReturnInstruction {

  Object ret;
  Object retAttr;
  Byte retType;

  // this is more simple than a normal JVMReturnInstruction because NativeMethodInfos
  // are not synchronized, and NativeStackFrames are never the first frame in a thread
  @Override
  public Instruction execute (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);

    // NativeStackFrame can never can be the first stack frame, so no thread CG

    frame = ti.popAndGetModifiableTopFrame();

    // remove args, push return value and continue with next insn
    frame.removeArguments(mi);
    pushReturnValue(frame);

    if (retAttr != null) {
      setReturnAttr(ti, retAttr);
    }

    return frame.getPC().getNext();
  }

  @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(JVMInstructionVisitor insVisitor) {
	  insVisitor.visit(this);
  }

  @Override
  protected void getAndSaveReturnValue (StackFrame frame) {
    // 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();
  }

  @Override
  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
  @Override
  protected Object getReturnedOperandAttr (StackFrame frame) {
    return retAttr;
  }

  // <2do> this should use the getResult..() methods of NativeStackFrame
  
  @Override
  protected void pushReturnValue (StackFrame fr) {
    int  ival;
    long lval;
    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:
        ival = Types.booleanToInt(((Boolean) ret).booleanValue());
        fr.push(ival);
        break;

      case Types.T_BYTE:
        fr.push(((Byte) ret).byteValue());
        break;

      case Types.T_CHAR:
        fr.push(((Character) ret).charValue());
        break;

      case Types.T_SHORT:
        fr.push(((Short) ret).shortValue());
        break;

      case Types.T_INT:
        fr.push(((Integer) ret).intValue());
        break;

      case Types.T_LONG:
        fr.pushLong(((Long)ret).longValue());
        retSize=2;
        break;

      case Types.T_FLOAT:
        ival = Types.floatToInt(((Float) ret).floatValue());
        fr.push(ival);
        break;

      case Types.T_DOUBLE:
        lval = Types.doubleToLong(((Double) ret).doubleValue());
        fr.pushLong(lval);
        retSize=2;
        break;

      default:
        // everything else is supposed to be a reference
        fr.push(((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(ThreadInfo ti) {
    if (isCompleted(ti)){
      return ret;
    } else {
      NativeStackFrame nativeFrame = (NativeStackFrame) ti.getTopFrame();
      return nativeFrame.getReturnValue();
    }
  }

  @Override
  public String toString(){
    StringBuilder sb = new StringBuilder();
    sb.append("nativereturn ");
    sb.append(mi.getFullName());

    return sb.toString();
  }

}