Package js.tinyvm

Source Code of js.tinyvm.CodeUtilities

package js.tinyvm;

import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantCP;
import org.apache.bcel.classfile.ConstantClass;
import org.apache.bcel.classfile.ConstantDouble;
import org.apache.bcel.classfile.ConstantFieldref;
import org.apache.bcel.classfile.ConstantFloat;
import org.apache.bcel.classfile.ConstantInteger;
import org.apache.bcel.classfile.ConstantLong;
import org.apache.bcel.classfile.ConstantNameAndType;
import org.apache.bcel.classfile.ConstantString;
import org.apache.bcel.classfile.JavaClass;

public class CodeUtilities implements OpCodeConstants, OpCodeInfo
{
   String iFullName;
   JavaClass iCF;
   Binary iBinary;

   public CodeUtilities (String aMethodName, JavaClass aCF, Binary aBinary)
   {
      iFullName = fullMethod(aCF, aMethodName);
      iCF = aCF;
      iBinary = aBinary;
   }

   /**
    * Return the ClassRecord for a class signature.
    * @param className the signature to lookup.
    * @return the associated class record, or null if it is a primitive array.
    * @throws js.tinyvm.TinyVMException
    */
   ClassRecord getClassRecord(String className) throws TinyVMException
   {
      ClassRecord ret;
      ret = iBinary.getClassRecord(className);
      if (ret == null)
      {
         throw new TinyVMException("Bug CU-3: Didn't find class " + className
            + " from class " + iCF.getClassName() + " method " + this.iFullName);
      }
      return ret;
   }

   ClassRecord getClassRecord(int aPoolIndex) throws TinyVMException
   {
      Constant pEntry = iCF.getConstantPool().getConstant(aPoolIndex); // TODO catch all (runtime) exceptions
      if (!(pEntry instanceof ConstantClass))
      {
         throw new TinyVMException("Classfile error: Instruction requiring "
            + "CONSTANT_Class entry got "
            + (pEntry == null? "null" : pEntry.getClass().getName()));
      }
      ConstantClass pClassEntry = (ConstantClass) pEntry;
      return getClassRecord(pClassEntry.getBytes(iCF.getConstantPool()));
   }


   public void exitOnBadOpCode (int aOpCode) throws TinyVMException
   {
      throw new TinyVMException("Unsupported " + OPCODE_NAME[aOpCode] + " in "
         + iFullName + ".\n"
         + "The following features/conditions are currently unsupported:\n"
         + "- Too many locals ( > 255).\n"
         + "- Too many constants ( > 1024).\n"
         + "- Too many static fields ( > 1024).\n"
         + "- Method code too long ( > 64 Kb!).\n" + "");
   }

   public static String fullMethod (JavaClass aCF, String aMethodName)
   {
      return aCF.getClassName() + ":" + aMethodName;
   }

   /**
    * Return the index of a given constant record
    * @param pRecord
    * @return the index of the record
    * @throws js.tinyvm.TinyVMException
    */
   int getConstantIndex(ConstantRecord pRecord) throws TinyVMException
   {
      int pIdx = iBinary.getConstantIndex(pRecord);

      if (pIdx == -1)
      {
         throw new TinyVMException("Bug CU-2: Didn't find constant " + pRecord.toString()
            + " of class " + iCF.getClassName());
      }
      return pIdx;
   }


   /**
    * Process a constant index.
    * Given a reference to the constant pool, return the corresponding index
    * into the leJOS constant table.
    * @param aPoolIndex the constant pool index
    * @return The constant table index
    * @throws js.tinyvm.TinyVMException
    */
   public int processConstantIndex (int aPoolIndex) throws TinyVMException
   {
      Constant pEntry = iCF.getConstantPool().getConstant(aPoolIndex);
      if (!(pEntry instanceof ConstantInteger)
         && !(pEntry instanceof ConstantFloat)
         && !(pEntry instanceof ConstantString)
         && !(pEntry instanceof ConstantDouble)
         && !(pEntry instanceof ConstantLong)
         && !(pEntry instanceof ConstantClass))
      {
         throw new TinyVMException("Classfile error: LDC-type instruction "
            + "does not refer to a suitable constant. Class " + iCF.getClassName() + " method " + iFullName);
      }

      ConstantRecord pRecord = new ConstantRecord(iCF.getConstantPool(), pEntry, iBinary);
      return getConstantIndex(pRecord);
   }

   /**
    * Process a class index.
    * Given a constant pool index for a class object, return the corresponding
    * index into the leJOS class table.
    * @param aPoolIndex the constant pool index
    * @return the class table index
    * @throws js.tinyvm.TinyVMException
    */
   public int processClassIndex (int aPoolIndex) throws TinyVMException
   {
      ClassRecord pClassRecord = getClassRecord(aPoolIndex);

      int pIdx = iBinary.getClassIndex(pClassRecord);
      if (pIdx == -1)
      {
         throw new TinyVMException("Bug CU-3: Didn't find class " + pClassRecord.iName
            + " from class " + iCF.getClassName() + " method " + this.iFullName);
      }
      return pIdx;
   }

   /**
    * Process and array index.
    * Given an index into the constant pool for an array class, return the
    * corresponding index into the leJOS class table.
    * @param aPoolIndex the constant index for the array
    * @return the class table index.
    * @throws js.tinyvm.TinyVMException
    */
   public int processArray(int aPoolIndex) throws TinyVMException
   {
      ClassRecord pClassRecord = getClassRecord(aPoolIndex);
      ClassRecord pArray = iBinary.getClassRecordForArray(pClassRecord);
      if (pArray == null)
      {
         throw new TinyVMException("Classfile error: Failed to locate array class for " +
                 pClassRecord.iName + " in class " + iCF.getClassName() + " method " + this.iFullName);
      }
      int pIdx = iBinary.getClassIndex(pArray);
      if (pIdx == -1)
      {
         throw new TinyVMException("Bug CU-3: Didn't find class " + pClassRecord.iName
            + " from class " + iCF.getClassName() + " method " + this.iFullName);
      }
      return pIdx;
   }


   public int processMultiArray (int aPoolIndex) throws TinyVMException
   {
      ClassRecord pClassRecord = getClassRecord(aPoolIndex);

      int pIdx = iBinary.getClassIndex(pClassRecord);
      if (pIdx == -1)
      {
         throw new TinyVMException("Bug CU-3: Didn't find class " + pClassRecord.iName
            + " from class " + iCF.getClassName() + " method " + this.iFullName);
      }
      return pIdx;
   }


   StaticFieldRecord getStaticFieldRecord(int aFieldIndexthrows TinyVMException
   {
      Constant pEntry = iCF.getConstantPool().getConstant(aFieldIndex); // TODO catch all (runtime) exceptions
      if (!(pEntry instanceof ConstantFieldref))
      {
         throw new TinyVMException("Classfile error: Instruction requiring "
            + "CONSTANT_Fieldref entry got "
            + (pEntry == null? "null" : pEntry.getClass().getName()));
      }
      ConstantFieldref pFieldEntry = (ConstantFieldref) pEntry;
      String className = pFieldEntry.getClass(iCF.getConstantPool()).replace(
         '.', '/');
      ClassRecord pClassRecord = getClassRecord(className);
      if (pClassRecord == null)
      {
         throw new TinyVMException("Attempt to use a field from a primitive array " +
                 className + " from class " + iCF.getClassName() + " method " + iFullName);

      }
      ConstantNameAndType cnat = (ConstantNameAndType) iCF.getConstantPool()
         .getConstant(pFieldEntry.getNameAndTypeIndex());
      String pName = cnat.getName(iCF.getConstantPool());
      // First find the actual defining class
      StaticFieldRecord pFieldRecord = pClassRecord.getStaticFieldRecord(pName);
      if (pFieldRecord == null)
      {
          throw new TinyVMException("Failed to locate static field " + pName +
                  " refrenced via class " + className + " from class " + iCF.getClassName());
      }
      return pFieldRecord;
   }

   /**
    * Mark the class as being used.
    * @param aPoolIndex
    * @throws js.tinyvm.TinyVMException
    */
   public void markClass (int aPoolIndex) throws TinyVMException
   {
      ClassRecord pClassRecord = getClassRecord(aPoolIndex);
      iBinary.markClassUsed(pClassRecord, true);
   }

   /**
    * Mark an array as being used.
    * @param aPoolIndex The constant pool index for the array.
    * @throws js.tinyvm.TinyVMException
    */
   public void markArray(int aPoolIndex) throws TinyVMException
   {
       ClassRecord pClassRecord = getClassRecord(aPoolIndex);
       ClassRecord pArray = iBinary.getClassRecordForArray(pClassRecord);
       if (pArray == null)
       {
         throw new TinyVMException("Classfile error: Failed to locate array class for " +
                 pClassRecord.iName + " in class " + iCF.getClassName() + " method " + this.iFullName);
       }
       iBinary.markClassUsed(pArray, true);
   }

   /**
    * Mark a primitive array as being used.
    * @param type The primitive type of the array.
    * @throws js.tinyvm.TinyVMException
    */
   public void markPrimitiveArray(byte type) throws TinyVMException
   {
       ClassRecord pClassRecord = getClassRecord(TinyVMType.tinyVMType(type).cname());
       ClassRecord pArray = iBinary.getClassRecordForArray(pClassRecord);
       if (pArray == null)
       {
         throw new TinyVMException("Classfile error: Failed to locate array class for " +
                 pClassRecord.iName + " in class " + iCF.getClassName() + " method " + this.iFullName);
       }
       iBinary.markClassUsed(pArray, true);
   }
   /**
    * Mark the static field as being used.
    * @param aFieldIndex
    * @throws js.tinyvm.TinyVMException
    */
   void markStaticField (int aFieldIndex) throws TinyVMException
   {
      Constant pEntry = iCF.getConstantPool().getConstant(aFieldIndex); // TODO catch all (runtime) exceptions
      if (!(pEntry instanceof ConstantFieldref))
      {
         throw new TinyVMException("Classfile error: Instruction requiring "
            + "CONSTANT_Fieldref entry got "
            + (pEntry == null? "null" : pEntry.getClass().getName()));
      }
      ConstantFieldref pFieldEntry = (ConstantFieldref) pEntry;
      String className = pFieldEntry.getClass(iCF.getConstantPool()).replace(
         '.', '/');
      ClassRecord pClassRecord = getClassRecord(className);
      if (pClassRecord == null) return;
      ConstantNameAndType cnat = (ConstantNameAndType) iCF.getConstantPool()
         .getConstant(pFieldEntry.getNameAndTypeIndex());
      String pName = cnat.getName(iCF.getConstantPool());
      iBinary.markClassUsed(pClassRecord, false);
      StaticFieldRecord pFieldRecord = pClassRecord.getStaticFieldRecord(pName);
      if (pFieldRecord == null)
      {
          throw new TinyVMException("Failed to mark/locate static field " + pName +
                 " refrenced via class " + className + " from class " + iCF.getClassName());
      }
      iBinary.markClassUsed(pFieldRecord.getClassRecord(), false);
      pFieldRecord.markUsed();
   }

   /**
    * Obtain the class that contains a specified static field.
    * @param aFieldIndex The index in the constant pool of the static field
    * @return The class record of the defining class
    * @throws js.tinyvm.TinyVMException
    */
   ClassRecord getStaticFieldClass (int aFieldIndex) throws TinyVMException
   {
      Constant pEntry = iCF.getConstantPool().getConstant(aFieldIndex); // TODO catch all (runtime) exceptions
      if (!(pEntry instanceof ConstantFieldref))
      {
         throw new TinyVMException("Classfile error: Instruction requiring "
            + "CONSTANT_Fieldref entry got "
            + (pEntry == null? "null" : pEntry.getClass().getName()));
      }
      ConstantFieldref pFieldEntry = (ConstantFieldref) pEntry;
      String className = pFieldEntry.getClass(iCF.getConstantPool()).replace(
         '.', '/');
      ClassRecord pClassRecord = getClassRecord(className);
      if (pClassRecord == null)
      {
          throw new TinyVMException("Classfile error: Failed to find class "
            + className);

      }
      return pClassRecord;
   }


   /**
    * Return the name of a static field
    * @param aFieldIndex The constant pool index for the field.
    * @throws js.tinyvm.TinyVMException
    */
   String getStaticFieldName (int aFieldIndex) throws TinyVMException
   {
      Constant pEntry = iCF.getConstantPool().getConstant(aFieldIndex); // TODO catch all (runtime) exceptions
      if (!(pEntry instanceof ConstantFieldref))
      {
         throw new TinyVMException("Classfile error: Instruction requiring "
            + "CONSTANT_Fieldref entry got "
            + (pEntry == null? "null" : pEntry.getClass().getName()));
      }
      ConstantFieldref pFieldEntry = (ConstantFieldref) pEntry;
      String className = pFieldEntry.getClass(iCF.getConstantPool()).replace(
         '.', '/');
      ClassRecord pClassRecord = getClassRecord(className);
      if (pClassRecord == null)
      {
          throw new TinyVMException("Classfile error: Failed to find class "
            + className);

      }
      ConstantNameAndType cnat = (ConstantNameAndType) iCF.getConstantPool()
         .getConstant(pFieldEntry.getNameAndTypeIndex());
      String pName = cnat.getName(iCF.getConstantPool());
      return pName;

   }

   /**
    * Check the field reference to see if it is for the special TYPE entry in a
    * primitive class.
    * @param aFieldIndex The constant pool index for the field
    * @throws js.tinyvm.TinyVMException
    */
   boolean isWrapperTYPEField (int aFieldIndex) throws TinyVMException
   {
      ClassRecord pClass = getStaticFieldClass(aFieldIndex);
      if (!pClass.isWrapper()) return false;
      String pName = getStaticFieldName(aFieldIndex);
      if (pName.equals("TYPE")) return true;
      return false;
   }

   /**
    * Mark a constant as being used.
    * @param aPoolIndex The constant pool index.
    * @throws js.tinyvm.TinyVMException
    */
   void markConstant(int aPoolIndex) throws TinyVMException
   {
      int constIdx = processConstantIndex(aPoolIndex);
      ConstantRecord pRec = iBinary.getConstantRecord(constIdx);
      pRec.markUsed();
   }
   /**
    * @return The word that should be written as parameter of an invocation
    *         opcode.
    * @throws TinyVMException
    */
   int processMethod (int aMethodIndex, boolean aSpecial, boolean aInterface)
      throws TinyVMException
   {
      Constant pEntry = iCF.getConstantPool().getConstant(aMethodIndex); // TODO catch all (runtime) exceptions
      if (!(pEntry instanceof ConstantCP))
      {
         throw new TinyVMException("Classfile error: Instruction requiring "
            + "CONSTANT_MethodRef or CONSTANT_InterfaceMethodRef " + "got "
            + (pEntry == null? "null" : pEntry.getClass().getName()));
      }
      ConstantCP pMethodEntry = (ConstantCP) pEntry;
      String className = pMethodEntry.getClass(iCF.getConstantPool()).replace(
         '.', '/');
      ConstantNameAndType pNT = (ConstantNameAndType) iCF.getConstantPool()
         .getConstant(pMethodEntry.getNameAndTypeIndex());
      Signature pSig = new Signature(pNT.getName(iCF.getConstantPool()), pNT
         .getSignature(iCF.getConstantPool()));
      if (className.startsWith("["))
      {
          // For arrays we use the methods contained in Object
          className = "java/lang/Object";
      }
      ClassRecord pClassRecord = getClassRecord(className);
      if (pClassRecord == null)
      {
         throw new TinyVMException("Bug CU-7: Didn't find class " + className
            + " from class " + iCF.getClassName() + " method " + iFullName);
      }

      MethodRecord pMethod;
      if (aInterface)
        pMethod = pClassRecord.getInterfaceMethodRecord(pSig);
      else
        pMethod = pClassRecord.getVirtualMethodRecord(pSig);
      if (pMethod == null)
      {
         throw new TinyVMException("Method " + pSig + " not found  in "
            + className +" interface " + aInterface);
      }
      ClassRecord pTopClass = pMethod.getClassRecord();
      if (aSpecial)
      {
         int pClassIndex = iBinary.getClassIndex(pTopClass);
         assert pClassIndex != -1 && pClassIndex < TinyVMConstants.MAX_CLASSES: "Check: class index in range";
         int pMethodIndex = pTopClass.getMethodIndex(pMethod);
         assert pMethodIndex != -1
            && pMethodIndex < TinyVMConstants.MAX_METHODS: "Check: method index in range";
         // _logger.log(Level.INFO, "processMethod: special: " + pClassIndex
         //    + ", " + pMethodIndex);
         return (pClassIndex << 8) | (pMethodIndex & 0xFF);
      }
      else
      {
         int pNumParams = pMethod.getNumParameterWords() - 1;
         assert pNumParams < TinyVMConstants.MAX_PARAMETER_WORDS: "Check: number of parameters not to high";
         int pSignature = pMethod.getSignatureId();
         assert pSignature < TinyVMConstants.MAX_SIGNATURES: "Check: signature in range";
         return (pNumParams << TinyVMConstants.M_ARGS_SHIFT) | pSignature;
      }
   }

   /**
    * @return The word that should be written as parameter of an invocation
    *         opcode.
    * @throws TinyVMException
    */
   MethodRecord findMethod (int aMethodIndex, boolean aSpecial, boolean aInterface)
      throws TinyVMException
   {
      Constant pEntry = iCF.getConstantPool().getConstant(aMethodIndex); // TODO catch all (runtime) exceptions
      if (!(pEntry instanceof ConstantCP))
      {
         throw new TinyVMException("Classfile error: Instruction requiring "
            + "CONSTANT_MethodRef or CONSTANT_InterfaceMethodRef " + "got "
            + (pEntry == null? "null" : pEntry.getClass().getName()));
      }
      ConstantCP pMethodEntry = (ConstantCP) pEntry;
      String className = pMethodEntry.getClass(iCF.getConstantPool()).replace(
         '.', '/');
      ConstantNameAndType pNT = (ConstantNameAndType) iCF.getConstantPool()
         .getConstant(pMethodEntry.getNameAndTypeIndex());
      Signature pSig = new Signature(pNT.getName(iCF.getConstantPool()), pNT
         .getSignature(iCF.getConstantPool()));
      if (className.startsWith("["))
      {
          // For arrays we use the methods contained in Object
             className = "java/lang/Object";
      }
      ClassRecord pClassRecord = getClassRecord(className);
      if (pClassRecord == null)
      {
         throw new TinyVMException("Bug CU-7: Didn't find class " + className
            + " from class " + iCF.getClassName());
      }
      MethodRecord pMethod;
      if (aInterface)
        pMethod = pClassRecord.getInterfaceMethodRecord(pSig);
      else
        pMethod = pClassRecord.getVirtualMethodRecord(pSig);
      //if (pMethod == null)
          // _logger.log(Level.INFO, "Failed to find " + pSig + " class " + className);
      return pMethod;
   }
  
   /**
    * Process a constant load operation.
    * Given a reference to the constant pool, return the corresponding
    * instruction and index required to load it.
    * @param aPoolIndex the constant pool index
    * @return The constant load instruction.
    * @throws js.tinyvm.TinyVMException
    */
   public int genConstantLoad (int aPoolIndex) throws TinyVMException
   {
      int idx = processConstantIndex(aPoolIndex);
      if (idx > TinyVMConstants.MAX_CONSTANTS) exitOnBadOpCode(OP_LDC);

      ConstantRecord pRecord = iBinary.getConstantRecord(idx);
      // Decide if we can use the optimized version of constant load to access
      // this value.
      int instruction;
      if (pRecord.constantValue().getAlignment() == 4 && idx < 256)
      {
         instruction = OP_LDC;
         iBinary.constOpLoads++;
      }
      else
      {
          // need to use normal form.
          instruction = OP_LDC_1 + idx/256;
          idx = idx % 256;
          iBinary.constNormLoads++;
          if (pRecord.constantValue().getType() == TinyVMType.T_OBJECT)
             iBinary.constString++;
      }
      return (instruction << 8) | idx;
   }

   /**
    * Generate and instruction to access a static field.
    * @param aPoolIndex The field to access
    * @param optInst The optimixed version of the instruction
    * @param normInst The normal version of the instruction.
    * @return
    * @throws TinyVMException
    */
   public int genStaticAccess(int aPoolIndex, int optInst, int normInst) throws TinyVMException
   {
      StaticFieldRecord fieldRec = getStaticFieldRecord(aPoolIndex);
      ClassRecord classRec = fieldRec.getClassRecord();
      int classIndex = iBinary.getClassIndex(classRec);
      assert classIndex >= 0 && classIndex <= 0xFF: "Check: class index in range";
      String name = fieldRec.getName();
      int fieldIndex = classRec.getStaticFieldIndex(name);
      StaticValue valueRec = classRec.getStaticValue(name);
      int offset = classRec.getStaticFieldOffset(name);
      int instruction;
      // Can we generate optimized version of the instruction?     
      if (valueRec.getAlignment() == 4 && offset/4 < 256)
      {
          instruction = optInst;
          offset = offset/4;
          iBinary.staticOpLoads++;
      }
      else
      {
          // Need to use the normal form, check the index is ok
          if (fieldIndex > TinyVMConstants.MAX_STATICS) exitOnBadOpCode(optInst);
          offset = fieldIndex % 256;
          instruction = normInst + (fieldIndex/256);
          iBinary.staticNormLoads++;
      }
      return (instruction << 16) | (classIndex << 8) | offset;
   }

   /**
    * Generate an instruction to access an instance field.
    * We use an optimized version of the opcode if the field is aligned correctly.
    * @param aFieldIndex The field we need to access.
    * @param optInst The optimized version of the instruction.
    * @param normInst The normal version of the instruction.
    * @return The field access instruction
    * @throws TinyVMException
    */
   int genFieldAccess (int aFieldIndex, int optInst, int normInst) throws TinyVMException
   {
      Constant pEntry = iCF.getConstantPool().getConstant(aFieldIndex); // TODO catch all (runtime) exceptions
      if (!(pEntry instanceof ConstantFieldref))
      {
         throw new TinyVMException("Classfile error: Instruction requiring "
            + "CONSTANT_Fieldref entry got "
            + (pEntry == null? "null" : pEntry.getClass().getName()));
      }
      ConstantFieldref pFieldEntry = (ConstantFieldref) pEntry;
      String className = pFieldEntry.getClass(iCF.getConstantPool()).replace(
         '.', '/');
      ClassRecord pClassRecord = getClassRecord(className);
      if (pClassRecord == null)
      {
         throw new TinyVMException("Attempt to use a field from a primitive array " +
                 className + " from class " + iCF.getClassName() + " method " + iFullName);

      }
      ConstantNameAndType cnat = (ConstantNameAndType) iCF.getConstantPool()
         .getConstant(pFieldEntry.getNameAndTypeIndex());
      String pName = cnat.getName(iCF.getConstantPool());
      int pOffset = pClassRecord.getInstanceFieldOffset(pName);
      if (pOffset == -1)
      {
         throw new TinyVMException("Error: Didn't find field " + className
            + ":" + pName + " from class " + iCF.getClassName());
      }
      assert pOffset <= TinyVMConstants.MAX_FIELD_OFFSET: "Check: field offset in range";
      TinyVMType fieldType = TinyVMType.tinyVMTypeFromSignature(cnat
         .getSignature(iCF.getConstantPool()));
      // Decide which form of the instruction to use.
      int instruction;
      if ((fieldType.type() == TinyVMType.T_INT_TYPE || fieldType.type() == TinyVMType.T_FLOAT_TYPE ||
              fieldType.type() == TinyVMType.T_REFERENCE_TYPE) && (pOffset & 0x3) == 0)
      {
         instruction = optInst;
         iBinary.fieldOpOp++;
      }
      else
      {
         instruction = normInst;
         iBinary.fieldNormOp++;
      }
      return (instruction << 16) | (fieldType.type() << TinyVMConstants.F_SIZE_SHIFT) | pOffset;
   }

   static int getAndCopyFourBytesInt( byte[] aCode, int ix, byte[] pOutCode, int ox)
   {
      int a = 0;
     
      a |= (aCode[ ix + 0] & 0xFF) << 24;
      a |= (aCode[ ix + 1] & 0xFF) << 16;
      a |= (aCode[ ix + 2] & 0xFF) << 8;
      a |= (aCode[ ix + 3] & 0xFF) << 0;

      for( int i = 0; i < 4; i ++)
         pOutCode[ ox + i] = aCode[ ix + i];

      return a;
   }  
  
   static int getFourBytesInt( byte[] aCode, int ix )
   {
      int a = 0;
     
      a |= (aCode[ ix + 0] & 0xFF) << 24;
      a |= (aCode[ ix + 1] & 0xFF) << 16;
      a |= (aCode[ ix + 2] & 0xFF) << 8;
      a |= (aCode[ ix + 3] & 0xFF) << 0;
      return a;
   }

   public byte[] processCode (byte[] aCode) throws TinyVMException
   {
      byte[] pOutCode = new byte[aCode.length];
      int i = 0;
      while (i < aCode.length)
      {
         pOutCode[i] = aCode[i];
         int pOpCode = pOutCode[i] & 0xFF;

         i++;
         //System.out.println("Opcode " + OPCODE_NAME[pOpCode] + " addr " + i);
         switch (pOpCode)
         {
            case OP_LDC:
               {
                  int inst = genConstantLoad(aCode[i] & 0xFF);
                  pOutCode[i-1] = (byte) (inst >> 8);
                  pOutCode[i++] = (byte) (inst & 0xFF);          
               }
               break;
            case OP_LDC_W:
               {
                  // Convert long version into short version plus noop
                  int inst = genConstantLoad((aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF));
                  pOutCode[i-1] = (byte) (inst >> 8);
                  pOutCode[i++] = (byte) (inst & 0xFF);
                  pOutCode[i++] = (byte) OP_NOP;
                  iBinary.constWideLoads++;
               }
               break;
            case OP_LDC2_W:
               int pIdx1 = processConstantIndex((aCode[i] & 0xFF) << 8
                  | (aCode[i + 1] & 0xFF));
               pOutCode[i++] = (byte) (pIdx1 >> 8);
               pOutCode[i++] = (byte) (pIdx1 & 0xFF);
               break;
            case OP_ANEWARRAY:
               int pIdx5 = processArray((aCode[i] & 0xFF) << 8
                  | (aCode[i + 1] & 0xFF));
               // Write the two byte signature
               pOutCode[i++] = (byte) (pIdx5 >> 8);
               pOutCode[i++] = (byte) (pIdx5 & 0xFF);
               break;
            case OP_MULTIANEWARRAY:
               int pIdx2 = processMultiArray((aCode[i] & 0xFF) << 8
                  | (aCode[i + 1] & 0xFF));
               // Write the two byte signature
               pOutCode[i++] = (byte) (pIdx2 >> 8);
               pOutCode[i++] = (byte) (pIdx2 & 0xFF);
               // Include the number of actual dimensions required
               pOutCode[i] = aCode[i];
               i++;
               break;
            case OP_CHECKCAST:
            case OP_INSTANCEOF:
               int pIdx3 = processClassIndex((aCode[i] & 0xFF) << 8
                  | (aCode[i + 1] & 0xFF));
               pOutCode[i++] = (byte) (pIdx3 >> 8);
               pOutCode[i++] = (byte) (pIdx3 & 0xFF);
               break;
            case OP_NEW:
               int pIdx4 = processClassIndex((aCode[i] & 0xFF) << 8
                  | (aCode[i + 1] & 0xFF));
               assert pIdx4 < TinyVMConstants.MAX_CLASSES: "Check: class index in range";
               pOutCode[i++] = (byte) (pIdx4 >> 8);
               pOutCode[i++] = (byte) (pIdx4 & 0xFF);
               break;
            case OP_GETSTATIC:
               {
                  int idx = (aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF);
                  if (isWrapperTYPEField(idx))
                  {
                     // If this is one of the rather odd static fields in the
                     // wrapper classes, then replace reads of it with a load
                     // of the appropriate class constant.
                     idx = getConstantIndex(getStaticFieldClass(idx).getPrimitiveClass().getClassConstant());
                     pOutCode[i-1] = (byte)OP_LDC_1;
                     pOutCode[i++] = (byte) (idx & 0xFF);
                     pOutCode[i++] = (byte) OP_NOP;
                     break;
                  }
                  // fall through
                  int inst = genStaticAccess((aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF), OP_GETSTATIC, OP_GETSTATIC_1);
                  pOutCode[i-1] = (byte)(inst >> 16);
                  pOutCode[i++] = (byte)(inst >> 8);
                  pOutCode[i++] = (byte)inst;
               }
               break;
            case OP_PUTSTATIC:
               {
                  int inst = genStaticAccess((aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF), OP_PUTSTATIC, OP_PUTSTATIC_1);
                  pOutCode[i-1] = (byte)(inst >> 16);
                  pOutCode[i++] = (byte)(inst >> 8);
                  pOutCode[i++] = (byte)inst;
               }
               break;
            case OP_GETFIELD:
               {
                  int inst = genFieldAccess((aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF), OP_GETFIELD, OP_GETFIELD_1);
                  pOutCode[i-1] = (byte) (inst >> 16);
                  pOutCode[i++] = (byte)(inst >> 8);
                  pOutCode[i++] = (byte) inst;
               }
               break;
            case OP_PUTFIELD:
               {
                  int inst = genFieldAccess((aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF), OP_PUTFIELD, OP_PUTFIELD_1);
                  pOutCode[i-1] = (byte) (inst >> 16);
                  pOutCode[i++] = (byte)(inst >> 8);
                  pOutCode[i++] = (byte) inst;
               }
               break;
            case OP_INVOKEINTERFACE:
               // Opcode is changed:
               pOutCode[i - 1] = (byte) OP_INVOKEVIRTUAL;
               int pWord3 = processMethod((aCode[i] & 0xFF) << 8
                  | (aCode[i + 1] & 0xFF), false, true);
               pOutCode[i++] = (byte) (pWord3 >> 8);
               pOutCode[i++] = (byte) (pWord3 & 0xFF);
               pOutCode[i++] = (byte) OP_NOP; // before: count
               pOutCode[i++] = (byte) OP_NOP; // before: 0
               break;
            case OP_INVOKESPECIAL:
            case OP_INVOKESTATIC:
               // Opcode is changed:
               int pWord4 = processMethod((aCode[i] & 0xFF) << 8
                  | (aCode[i + 1] & 0xFF), true, false);
               pOutCode[i++] = (byte) (pWord4 >> 8);
               pOutCode[i++] = (byte) (pWord4 & 0xFF);
               break;
            case OP_INVOKEVIRTUAL:
               // Opcode is changed:
               int pWord5 = processMethod((aCode[i] & 0xFF) << 8
                  | (aCode[i + 1] & 0xFF), false, false);
               pOutCode[i++] = (byte) (pWord5 >> 8);
               pOutCode[i++] = (byte) (pWord5 & 0xFF);
               break;
            case OP_LOOKUPSWITCH:
               {
                  int oi = i;
                  while( (i % 4) != 0)
                     i ++;

                  int dft = getAndCopyFourBytesInt( aCode, i, pOutCode, oi); i += 4; oi += 4;
                  int npairs = getAndCopyFourBytesInt( aCode, i, pOutCode, oi); i += 4; oi += 4;
                  //System.out.println( "lookupswitch: dft: " + dft + ", npairs: " + npairs + ", padding: " + (i - oi));

                  for( int k = 0; k < npairs; k ++)
                  {
                     int idx = getAndCopyFourBytesInt( aCode, i, pOutCode, oi); i += 4; oi += 4;
                     int off = getAndCopyFourBytesInt( aCode, i, pOutCode, oi); i += 4; oi += 4;
                     //System.out.println( "lookupswitch: idx: " + idx + ", off: " + off);
                  }

                  while( oi < i)
                     pOutCode[oi++] = 0;
               }
               break;

            case OP_TABLESWITCH:
               {
                  int oi = i;
                  while( (i % 4) != 0)
                     i ++;

                  int dft = getAndCopyFourBytesInt( aCode, i, pOutCode, oi); i += 4; oi += 4;
                  int low = getAndCopyFourBytesInt( aCode, i, pOutCode, oi); i += 4; oi += 4;
                  int hig = getAndCopyFourBytesInt( aCode, i, pOutCode, oi); i += 4; oi += 4;
                  //System.out.println( "tableswitch: dft: " + dft + ", low: " + low + ", hig: " + hig + ", padding: " + (i - oi));

                  for( int k = low; k <= hig; k ++)
                  {
                     int idx = getAndCopyFourBytesInt( aCode, i, pOutCode, oi); i += 4; oi += 4;
                     //System.out.println( "tableswitch: idx: " + idx);
                  }

                  while( oi < i)
                     pOutCode[oi++] = 0;
               }
               break;

            case OP_WIDE:
                if( (aCode[i] & 0xFF) == OP_IINC && aCode[i+1] == 0)
                {
                   for( int k = 0; k < 5; k ++, i ++)
                      pOutCode[i] = aCode[i];
                   break;
                }
                // Fall through

            case OP_GOTO_W:
            case OP_JSR_W:
               exitOnBadOpCode(pOpCode);
               break;
            case OP_BREAKPOINT:
            {
               throw new TinyVMException("Invalid opcode detected: " + pOpCode
                  + " " + OPCODE_NAME[pOpCode]);
            }
            default:
               int pArgs = OPCODE_ARGS[pOpCode];
               if (pArgs == -1)
               {
                  throw new TinyVMException("Bug CU-1: Got " + pOpCode + " in "
                     + iFullName + ".");
               }
               for (int ctr = 0; ctr < pArgs; ctr++)
                  pOutCode[i + ctr] = aCode[i + ctr];
               i += pArgs;
               break;
         }
      }
      return pOutCode;
   }

   public void processCalls (byte[] aCode, JavaClass aClassFile, Binary aBinary) throws TinyVMException
   {
      int i = 0;
      while (i < aCode.length)
      {
         int pOpCode = aCode[i] & 0xFF;

         i++;
         //System.out.println("Opcode " + OPCODE_NAME[pOpCode] + " addr " + i);
         switch (pOpCode)
         {
            case OP_LDC:
               {
                  markConstant(aCode[i] & 0xFF);
                  i++;
               }
               break;
            case OP_LDC_W:
            case OP_LDC2_W:
               {
                  markConstant((aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF));
                  i += 2;
               }
               break;

            case OP_ANEWARRAY:
                markArray((aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF));
                i += 2;
                break;
            case OP_NEWARRAY:
                markPrimitiveArray(aCode[i]);
                i += 1;
                break;
            case OP_MULTIANEWARRAY:
                markClass((aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF));
                i += 3;
                break;
            case OP_NEW:
            case OP_CHECKCAST:
            case OP_INSTANCEOF:
               markClass((aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF));
               i += 2;
               break;
            case OP_GETSTATIC:
               {
                  int idx = (aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF);
                  if (isWrapperTYPEField(idx))
                  {
                     getStaticFieldClass(idx).getPrimitiveClass().getClassConstant().markUsed();
                  }
                  else
                     markStaticField((aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF));
                  i += 2;
                  break;
              }
           case OP_PUTSTATIC:
               markStaticField((aCode[i] & 0xFF) << 8 | (aCode[i + 1] & 0xFF));
               i += 2;
               break;
            case OP_INVOKEINTERFACE:
               // Opcode is changed:
               // _logger.log(Level.INFO, "Interface");
               MethodRecord pMeth0 = findMethod((aCode[i] & 0xFF) << 8
                  | (aCode[i + 1] & 0xFF), false, true);
               if (pMeth0 != null) pMeth0.getClassRecord().markMethod(pMeth0, true);
               i += 4;
               break;
            case OP_INVOKEVIRTUAL:
               // Opcode is changed:
               MethodRecord pMeth1 = findMethod((aCode[i] & 0xFF) << 8
                  | (aCode[i + 1] & 0xFF), false, false);
               if (pMeth1 != null) pMeth1.getClassRecord().markMethod(pMeth1, true);
               i += 2;
               break;
            case OP_INVOKESPECIAL:
            case OP_INVOKESTATIC:
               // Opcode is changed:
               MethodRecord pMeth2 = findMethod((aCode[i] & 0xFF) << 8
                  | (aCode[i + 1] & 0xFF), true, false);
               if (pMeth2 != null) pMeth2.getClassRecord().markMethod(pMeth2, true);
               i += 2;
               break;
            case OP_LOOKUPSWITCH:
               {
                   while( (i % 4) != 0)
                     i ++;

                  int dft = getFourBytesInt( aCode, i); i += 4;
                  int npairs = getFourBytesInt( aCode, i); i += 4;
                  //System.out.println( "lookupswitch: dft: " + dft + ", npairs: " + npairs + ", padding: " + (i - oi));
                  i += 8*npairs;
               }
               break;

            case OP_TABLESWITCH:
               {
                  while( (i % 4) != 0)
                     i ++;

                  int dft = getFourBytesInt( aCode, i); i += 4;
                  int low = getFourBytesInt( aCode, i); i += 4;
                  int hig = getFourBytesInt( aCode, i); i += 4;
                  //System.out.println( "tableswitch: dft: " + dft + ", low: " + low + ", hig: " + hig + ", padding: " + (i - oi));

                  for( int k = low; k <= hig; k ++)
                  {
                     i += 4;
                     //System.out.println( "tableswitch: idx: " + idx);
                  }

              }
               break;

            case OP_WIDE:
                if( (aCode[i] & 0xFF) == OP_IINC && aCode[i+1] == 0)
                {
                   i += 5;
                   break;
                }
                // Fall Through
            case OP_GOTO_W:
            case OP_JSR_W:
            //case OP_FREM:
            //case OP_DREM:
               exitOnBadOpCode(pOpCode);
               break;            
            default:
               int pArgs = OPCODE_ARGS[pOpCode];
               if (pArgs == -1)
               {
                  throw new TinyVMException("Bug CU-1: Got " + pOpCode + " in "
                     + iFullName + ".");
               }
               i += pArgs;
         }

      }
   }

   // private static final Logger _logger = Logger.getLogger("TinyVM");
}
TOP

Related Classes of js.tinyvm.CodeUtilities

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.