/**
   * Renders disassembled instructions into the code table, starting at the specified row and
   * instruction address.
   *
   * @param instructions A list of instructions to render into the table.
   * @param row The table row to start at.
   * @param address The code address to start at.
   */
  private void renderInstructions(Iterable<WAMInstruction> instructions, int row, int address) {
    for (WAMInstruction instruction : instructions) {
      WAMLabel label = instruction.getLabel();

      labeledTable.put(ADDRESS, row, String.format("%08X", address));
      labeledTable.put(LABEL, row, (label == null) ? "" : (label.toPrettyString() + ":"));
      labeledTable.put(MNEMONIC, row, instruction.getMnemonic().getPretty());

      int fieldMask = instruction.getMnemonic().getFieldMask();

      String arg = "";

      for (int i = 2; i < 32; i = i * 2) {
        if ((fieldMask & i) != 0) {
          if (!"".equals(arg)) {
            arg += ", ";
          }

          switch (i) {
            case 2:
              arg += Integer.toString(instruction.getReg1());
              break;

            case 4:
              arg += Integer.toString(instruction.getReg2());
              break;

            case 8:
              FunctorName fn = instruction.getFn();
              if (fn != null) {
                arg += fn.getName() + "/" + fn.getArity();
              }

              break;

            case 16:
              WAMLabel target1 = instruction.getTarget1();
              if (target1 != null) {
                arg += target1.getName() + "/" + target1.getArity() + "_" + target1.getId();
              }

              break;
          }
        }
      }

      labeledTable.put(ARG_1, row, arg);

      row++;
      address += instruction.sizeof();
    }
  }
  /**
   * Should be notified every time byte-code is added to the machine.
   *
   * @param codeBuffer A buffer containing the byte-code.
   * @param start The start offset within the buffer of the new code.
   * @param length The length of the new code.
   * @param interner The machines interner to lookup interned names with.
   * @param codeView The machines code view to find interned names matching addresses.
   */
  public void onCodeUpdate(
      ByteBuffer codeBuffer,
      int start,
      int length,
      VariableAndFunctorInterner interner,
      WAMCodeView codeView) {
    log.fine(
        "public void onCodeUpdate(ByteBuffer codeBuffer, int start = "
            + start
            + ", int length = "
            + length
            + ", VariableAndFunctorInterner interner, WAMCodeView codeView): called");

    // Take a copy of the new bytecode.
    copyAndResizeCodeBuffer(codeBuffer, start, length);

    // Disassemble the new area of byte code.
    SizeableList<WAMInstruction> instructions =
        WAMInstruction.disassemble(start, length, this.codeBuffer, interner, codeView);

    // Figure out where to start writing the disassembled code into the table.
    Map.Entry<Integer, Integer> entry = addressToRow.floorEntry(start);
    int firstRow = (entry == null) ? 0 : (entry.getValue() + 1);

    int address = start;
    int row = firstRow;

    // Build the mapping between addresses and rows.
    for (WAMInstruction instruction : instructions) {
      addressToRow.put(address, row);
      rowToAddress.add(row, address);

      row++;
      address += instruction.sizeof();
    }

    // Render the instructions into the table to be displayed.
    renderInstructions(instructions, firstRow, start);
  }