/**
   * Replace the previous instruction(s), from the end of the peephole window up to i with a new
   * Instruction sequence. It will replace all the previous instructions through i. Must not be
   * called with an index that falls outside of the peephole window.
   *
   * @param i the index of the previous instruction to replace. Follows the same indexing strategy
   *     as the previous() method 0 is the last instruction in the window, 1 is two instructions
   *     ago, up to PEEPHOLE_WINDOW_SIZE-1 which is the oldest instruction that can be replaced.
   * @param insns The new instruction sequence to insert at i
   */
  private void replace(int i, Instruction[] insns) {
    if (insns.length == 0) return;

    int size = instructions.size();
    int idx = i + 1;
    if (size >= idx) {
      int realIdx = size - idx;

      assert !indexBeforeLabel(realIdx)
          : "Attempting to replace instruction sequence that spans a label";

      // replace the instruction
      InstructionInfo info = instructions.get(realIdx);
      info.setInstruction(insns[0]);

      // Delete any remaining instructions, saving the list of labelNexts from the last deleted
      // instruction
      List<Label> labelNexts = null;
      for (int r = size - 1; r >= (realIdx + 1); --r) {
        InstructionInfo temp = instructions.remove(r);
        if (r == size - 1) {
          // Save the labelNexts from the last deleted instruction
          labelNexts = temp.getLabelNexts();
        }
      }

      // Add the remaining instructions
      for (int r = 1, l = insns.length; r < l; ++r) addInstruction(insns[r]);

      if (labelNexts != null) {
        // Apply any saved labelNexts to the last instruction added
        for (Label l : labelNexts) labelNext(l);
      }
    } else {
      assert false : "Trying to replace instructions that fall outside the peephole window";
    }
  }