/**
  * Optimizations for OP_getproperty: findpropstrict name, getproperty name -> getlex name
  *
  * @param i the getproperty instruction
  */
 private void op_getproperty(InstructionInfo i) {
   InstructionInfo prev = previous(1);
   switch (prev.getOpcode()) {
     case OP_findpropstrict:
       {
         // can optimize findpropstrict, followed by getprop of the same name
         // if there are any instructions btwn the findpropstrict and getprop (such as to compute a
         // runtime
         // multiname), we won't match this pattern
         if (i.getOperand(0).equals(prev.getOperand(0)))
           replace(
               1, InstructionFactory.createModifiedInstruction(OP_getlex, prev.getInstruction()));
         break;
       }
   }
 }
 /**
  * evaluates an instruction and determines if it will result in true or false on TOS.
  *
  * @param i is an instruction to analyze
  * @return whether TOS is true, false, or not known
  */
 private static ConstantBoolean isTrueInstructionInfo(InstructionInfo i) {
   ConstantBoolean ret = ConstantBoolean.DONT_KNOW;
   switch (i.getOpcode()) {
     case OP_pushtrue:
       ret = ConstantBoolean.TRUE;
       break;
     case OP_pushfalse:
       ret = ConstantBoolean.FALSE;
       break;
     case OP_pushbyte:
       {
         int value = i.getImmediate();
         assert value >= 0;
         ret = ECMASupport.toBoolean(value) ? ConstantBoolean.TRUE : ConstantBoolean.FALSE;
         break;
       }
     case OP_pushint:
       {
         int value = (Integer) i.getOperand(0);
         ret = ECMASupport.toBoolean(value) ? ConstantBoolean.TRUE : ConstantBoolean.FALSE;
         break;
       }
     case OP_pushuint:
       {
         long value = (Long) i.getOperand(0);
         ret = ECMASupport.toBoolean(value) ? ConstantBoolean.TRUE : ConstantBoolean.FALSE;
         break;
       }
     case OP_pushstring:
       {
         String value = i.getOperand(0).toString();
         ret = ECMASupport.toBoolean(value) ? ConstantBoolean.TRUE : ConstantBoolean.FALSE;
         break;
       }
     case OP_pushnull:
       ret = ConstantBoolean.FALSE;
       break;
   }
   return ret;
 }
  /**
   * Helper method to perform optimizations around jumps when we get a labeling operation. Shared
   * with labelNext and labelCurrent methods
   *
   * @param l the Label object passed into the label operation
   * @param kind what kind of labeling operation are we doing (labelNext or labelCurrent)
   */
  private void jumpOptimizations(Label l, LabelKind kind) {
    // Need to start looking at different indexes for label current vs. label next
    // this is because for a label next, the next instruction won't have come in yet.
    int idx = kind == LabelKind.LABEL_CURRENT ? 1 : 0;

    InstructionInfo prev = previous(idx);
    switch (prev.getOpcode()) {
      case OP_jump:
        {
          InstructionInfo prev2 = previous(idx + 1);
          Instruction insn = prev2.getInstruction();
          if (insn != null && insn.isBranch() && insn.getTarget() == l) {
            // If the previous instructions were an if that jumped here, and it
            // only jumped over another jump, then we can invert the if instruction
            // and save a jump
            //   iffalse L1, jump L2, L1    -> iftrue L2, L1
            Instruction newIf = invertIf(prev2, prev);
            if (newIf != null) {
              if (kind == LabelKind.LABEL_CURRENT) {
                // labelCurrent, so we need to preserve the last instruction
                Instruction[] newInsns = {newIf, previous(0).getInstruction()};
                replace(idx + 1, newInsns);
              } else {
                // labelNext so we can just delete the last instruction
                replace(idx + 1, newIf);
              }
            }
          }
          // If the previous instruction was a jump, and it just jumped
          // to the next instruction, then we can remove the jump and just fall
          // through
          //   jump L1, L1 -> L1
          else if (prev.getOperand(0) == l) {
            if (kind == LabelKind.LABEL_NEXT)
              // can just delete the jump because we don't have the next instruction yet
              delete(idx);
            else
              // replace the jump with its target
              replace(idx, previous(0).getInstruction());
          }
        }
    }
  }
 /**
  * Optimizations for OP_convert_d: convert_d, convert_d -> convert_d pushbyte n, convert_d ->
  * pushdouble n pushint n, convert_d -> pushdouble n pushuint n, convert_d -> pushdouble n
  * pushdouble n, convert_d -> pushdouble n pushnan, convert_d -> pushnan lf32, convert_d -> lf32
  * lf64, convert_d -> lf64
  *
  * @param i The convert_d instruction
  */
 private void op_convert_d(InstructionInfo i) {
   InstructionInfo prev = previous(1);
   switch (prev.getOpcode()) {
     case OP_pushbyte:
       {
         // replace pushbyte, convert d with pushdouble - should be faster
         replace(
             1,
             InstructionFactory.getInstruction(
                 OP_pushdouble, new Double(convertByteImmediateToDouble(prev.getImmediate()))));
         break;
       }
     case OP_pushint:
     case OP_pushuint:
       {
         // replace pushint , convert d with pushdouble - should be faster
         replace(
             1,
             InstructionFactory.getInstruction(
                 OP_pushdouble, new Double(((Number) prev.getOperand(0)).doubleValue())));
         break;
       }
     case OP_pushdouble:
     case OP_pushnan:
     case OP_lf32:
     case OP_lf64:
     case OP_convert_d:
       {
         // result is already a double, just erase the op_convert_d
         delete(0);
         break;
       }
     default:
       {
         // nothing to do - instruction has already been added
       }
   }
 }