/**
  * Should be called Before virtual execution of instructions putfield and putstatic so that all
  * corresponding getFields are set dirty. Similarly should also be called before virtual execution
  * of instructions AASTORE so that corresponding AALOAD are set dirty.
  *
  * @param method
  * @param callingParms
  * @param instr
  * @param stack
  * @param localVariables
  */
 public void fixOrderRelatedInstrs(
     MethodInfo method,
     Vector callingParms,
     GCInstruction instr,
     GCOperandStack stack,
     GCLocalVariables localVariables) {
   if (!isFieldIsObjectBased(instr)) {
     return;
   }
   String methodStr = oracle.getMethodOrFieldString(method);
   if (instr.getOpCode() == JavaInstructionsOpcodes.PUTSTATIC
       || instr.getOpCode() == JavaInstructionsOpcodes.PUTFIELD
       || instr.getOpCode() == JavaInstructionsOpcodes.AASTORE) {
     GCType type = (GCType) stack.peep();
     if (!type.isReference()) {
       return;
     }
     HashSet<TTReference> refSet = type.getReferences();
     if (refSet.size() == 1) {
       TTReference ref = refSet.iterator().next();
       if (ref.getClassThisPointer() == Type.NULL || ref.getNewId() < 0) {
         return;
       }
     }
     debugPrint("\n\n++++++++++ ", "fix-Order");
     debugPrint("method Str =", oracle.getMethodOrFieldString(method));
     debugPrint("instr =", instr);
     handlePutRecalls(new MethodCallInfo(method, callingParms), instr, stack);
   }
 }
 /**
  * In case the method is still under-call then put the record of the method fields where get was
  * used in a seperate map. When a method any next instruction is called again then the record is
  * pop from the map and corresponding instructions are made dirty.
  *
  * <p>This method create that record of method fields.
  *
  * @param methodCallInfo
  * @param instrDataSettingInstr
  */
 private void handlePutRecalls(
     MethodCallInfo methodCallInfo, GCInstruction instrDataSettingInstr, OperandStack stack) {
   if (true) return;
   try {
     /**
      * 1. Firstly get from input instructions the uniqueId for corresponding data reterival
      * instructions. 2. Subsequently, add those instructions in the two different maps depending
      * upon if the method is still under call or not.
      */
     ControllerForFieldInstr contr = ControllerForFieldInstr.getInstanceOf();
     HashSet<Integer> uniqueIdForDataRetrivalInstr = new HashSet<Integer>();
     if (instrDataSettingInstr.getOpCode() != JavaInstructionsOpcodes.AASTORE) {
       int cpIndex = instrDataSettingInstr.getOperandsData().intValueUnsigned();
       uniqueIdForDataRetrivalInstr.add(cpIndex);
     } else {
       uniqueIdForDataRetrivalInstr = getAAStoreNewIds(stack);
     }
     /**
      * following are the all getField or getStatic instruction for the given constant pool index.
      */
     HashSet<FieldRecord> getFieldOrStateRecordSet =
         contr.getRecords(
             uniqueIdForDataRetrivalInstr,
             instrDataSettingInstr.getOpCode() == JavaInstructionsOpcodes.AASTORE);
     /**
      * Now we iterate from all of those instructions and put them in two different maps
      * depenending up if their method is still under call or not.
      */
     Iterator<FieldRecord> fieldRectIt = getFieldOrStateRecordSet.iterator();
     while (fieldRectIt.hasNext()) {
       FieldRecord fieldRec = fieldRectIt.next();
       HashSet<FunctionStateKey> allTheMethodCallsForTheField = fieldRec.getStateKeys();
       Iterator<FunctionStateKey> methodCallIt = allTheMethodCallsForTheField.iterator();
       while (methodCallIt.hasNext()) {
         FunctionStateKey stateKey = methodCallIt.next();
         GCDataFlowAnalyzer dataFlowAnalyzer = GCDataFlowAnalyzer.getInstanceOf();
         HashSet<FunctionStateKey> allMethodInExecution = dataFlowAnalyzer.getMethodsInExecution();
         String methodString = oracle.getMethodOrFieldString(stateKey.getMethod());
         long instrId = fieldRec.getInstr().getInstructionId();
         if (allMethodInExecution.contains(stateKey)) {
           putInMap(fieldsToSetDirtyInUnderCallMethod, stateKey, fieldRec);
         } else {
           putInMap(fieldsToSetDirtyAfterMethodCalled, stateKey, fieldRec);
         }
       }
     }
   } catch (Exception d) {
     d.printStackTrace();
     Miscellaneous.exit();
   }
 }
 /**
  * This method is called when GetStatic or GetField or AALoad. It adds record of those
  * instructions so that they can be made dirty when putfield or putstatic is used for the same
  * field.
  *
  * @param method
  * @param callingParams
  * @param instr
  * @param stack
  * @param localVar
  */
 public void addRecord(
     MethodInfo method,
     Vector callingParams,
     GCInstruction instr,
     GCOperandStack stack,
     GCLocalVariables localVar) {
   if (!isFieldIsObjectBased(instr)
       || (instr.getOpCode() != JavaInstructionsOpcodes.GETSTATIC
           && instr.getOpCode() != JavaInstructionsOpcodes.GETFIELD
           && instr.getOpCode() != JavaInstructionsOpcodes.AALOAD)) {
     return;
   }
   addRecord(new FunctionStateKey(method, callingParams), instr, stack, localVar);
 }
  /**
   * check if the field saves an object.
   *
   * @param instr
   * @return
   */
  private boolean isFieldIsObjectBased(GCInstruction instr) {
    if (instr.getOpCode() == JavaInstructionsOpcodes.AALOAD
        || instr.getOpCode() == JavaInstructionsOpcodes.AASTORE) {
      return true;
    }
    if (instr.getOpCode() != JavaInstructionsOpcodes.PUTFIELD
        && instr.getOpCode() != JavaInstructionsOpcodes.GETFIELD
        && instr.getOpCode() != JavaInstructionsOpcodes.GETSTATIC
        && instr.getOpCode() != JavaInstructionsOpcodes.PUTSTATIC) {
      return false;
    }
    GlobalConstantPool pOne = GlobalConstantPool.getInstanceOf();

    int index = instr.getOperandsData().intValueUnsigned();
    FieldRefInfo fInfo = (FieldRefInfo) pOne.get(index, TagValues.CONSTANT_Fieldref);
    int nameAndTypeIndex = fInfo.getNameAndTypeIndex().intValueUnsigned();
    NameAndTypeInfo nAtInfo =
        (NameAndTypeInfo) pOne.get(nameAndTypeIndex, TagValues.CONSTANT_NameAndType);

    String description =
        ((UTF8Info)
                pOne.get(nAtInfo.getDescriptorIndex().intValueUnsigned(), TagValues.CONSTANT_Utf8))
            .convertBytes();
    VerificationFrameFactory frameFactory = VerificationPlaceHolder.getInstanceOf().getFactory();
    Type fieldType = frameFactory.createType();
    InitializeFirstInstruction.getType(description, 0, fieldType);
    return fieldType.isReference();
  }
  /**
   * Call it BEFORE executing an instruction virtually.
   *
   * @param instr
   * @param stack
   * @param localVar
   */
  private void addRecord(
      FunctionStateKey stateKey,
      GCInstruction instr,
      GCOperandStack stack,
      GCLocalVariables localVar) {

    MethodInfo method = instr.getMethod();
    String methodStr = oracle.getMethodOrFieldString(method);
    if (methodStr.contains("jvmTestCases.Main.fooGetOnly")) {}
    debugPrint("\n\n", "***** adding record *****");
    debugPrint("method Str=", methodStr);
    debugPrint("instr =", instr);
    HashSet<Integer> unqiueForField = new HashSet<Integer>();
    if (instr.getOpCode() != JavaInstructionsOpcodes.AALOAD) {
      int cpIndex = instr.getOperandsData().intValueUnsigned();
      unqiueForField.add(cpIndex);
    } else {
      unqiueForField = getAALOADNewIds(stack);
    }
    Iterator<Integer> it = unqiueForField.iterator();
    while (it.hasNext()) {
      contrForField.addRecord(stateKey, instr, it.next());
    }
  }