/**
   * 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());
          }
        }
    }
  }
 /** @return the immediate for the instruction, or -1 if there is no instruction */
 public int getImmediate() {
   return insn != null ? insn.getImmediate() : -1;
 }
 /**
  * Get the operand at index i from the underlying instruction
  *
  * @param i the index of the operand to fetch
  * @return the operand at index i, or null if there is no instruction
  */
 public Object getOperand(int i) {
   return insn != null ? insn.getOperand(i) : null;
 }
 /** @return the opcode of the Instruction, or -1 if there is no instruction */
 public int getOpcode() {
   return insn != null ? insn.getOpcode() : -1;
 }