bool DisassemblerX64::decodeInstructionType()

in runtime/disassembler-x64.cpp [1093:1220]


bool DisassemblerX64::decodeInstructionType(uint8_t** data) {
  uint8_t current;

  // Scan for prefixes.
  while (true) {
    current = **data;
    if (current == OPERAND_SIZE_OVERRIDE_PREFIX) {  // Group 3 prefix.
      operand_size_ = current;
    } else if ((current & 0xF0) == 0x40) {
      // REX prefix.
      setRex(current);
      // TODO(srdjan): Should we enable printing of REX.W?
      // if (rexW()) print("REX.W ");
    } else if ((current & 0xFE) == 0xF2) {  // Group 1 prefix (0xF2 or 0xF3).
      group_1_prefix_ = current;
    } else if (current == 0xF0) {
      print("lock ");
    } else {  // Not a prefix - an opcode.
      break;
    }
    (*data)++;
  }

  const InstructionDesc& idesc = instruction_table.get(current);
  byte_size_operand_ = idesc.byte_size_operation;

  switch (idesc.type) {
    case ZERO_OPERANDS_INSTR:
      if (current >= 0xA4 && current <= 0xA7) {
        // String move or compare operations.
        if (group_1_prefix_ == REP_PREFIX) {
          // REP.
          print("rep ");
        }
        if ((current & 0x01) == 0x01) {
          // Operation size: word, dword or qword
          switch (operandSize()) {
            case WORD_SIZE:
              print("%sw", idesc.mnem);
              break;
            case DOUBLEWORD_SIZE:
              print("%sl", idesc.mnem);
              break;
            case QUADWORD_SIZE:
              print("%sq", idesc.mnem);
              break;
            default:
              UNREACHABLE("bad operand size");
          }
        } else {
          // Operation size: byte
          print("%s", idesc.mnem);
        }
      } else if (current == 0x99 && rexW()) {
        print("cqo");  // Cdql is called cdq and cdqq is called cqo.
      } else {
        print("%s", idesc.mnem);
      }
      (*data)++;
      break;

    case TWO_OPERANDS_INSTR:
      (*data)++;
      (*data) += printOperands(idesc.mnem, idesc.op_order_, *data);
      break;

    case JUMP_CONDITIONAL_SHORT_INSTR:
      (*data) += jumpConditionalShort(*data);
      break;

    case REGISTER_INSTR:
      print("%s%s %s", idesc.mnem, operandSizeCode(),
            nameOfCPURegister(baseReg(current & 0x07)));
      (*data)++;
      break;
    case PUSHPOP_INSTR:
      print("%s %s", idesc.mnem, nameOfCPURegister(baseReg(current & 0x07)));
      (*data)++;
      break;
    case MOVE_REG_INSTR: {
      intptr_t addr = 0;
      int imm_bytes = 0;
      switch (operandSize()) {
        case WORD_SIZE:
          addr = LoadUnaligned(reinterpret_cast<int16_t*>(*data + 1));
          imm_bytes = 2;
          break;
        case DOUBLEWORD_SIZE:
          addr = LoadUnaligned(reinterpret_cast<int32_t*>(*data + 1));
          imm_bytes = 4;
          break;
        case QUADWORD_SIZE:
          addr = LoadUnaligned(reinterpret_cast<int64_t*>(*data + 1));
          imm_bytes = 8;
          break;
        default:
          UNREACHABLE("bad operand size");
      }
      (*data) += 1 + imm_bytes;
      print("mov%s %s,", operandSizeCode(),
            nameOfCPURegister(baseReg(current & 0x07)));
      printImmediateValue(addr, /*signed_value=*/false, imm_bytes);
      break;
    }

    case CALL_JUMP_INSTR: {
      int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(*data + 1)) + 5;
      print("%s ", idesc.mnem);
      printJump(*data, disp);
      (*data) += 5;
      break;
    }

    case SHORT_IMMEDIATE_INSTR: {
      print("%s%s %s,", idesc.mnem, operandSizeCode(), rax());
      printImmediate(*data + 1, DOUBLEWORD_SIZE);
      (*data) += 5;
      break;
    }

    case NO_INSTR:
      return false;

    default:
      UNIMPLEMENTED("type not implemented");
  }
  return true;
}