Home | History | Annotate | Download | only in ia32
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <assert.h>
      6 #include <stdio.h>
      7 #include <stdarg.h>
      8 
      9 #include "src/v8.h"
     10 
     11 #if V8_TARGET_ARCH_IA32
     12 
     13 #include "src/disasm.h"
     14 
     15 namespace disasm {
     16 
     17 enum OperandOrder {
     18   UNSET_OP_ORDER = 0,
     19   REG_OPER_OP_ORDER,
     20   OPER_REG_OP_ORDER
     21 };
     22 
     23 
     24 //------------------------------------------------------------------
     25 // Tables
     26 //------------------------------------------------------------------
     27 struct ByteMnemonic {
     28   int b;  // -1 terminates, otherwise must be in range (0..255)
     29   const char* mnem;
     30   OperandOrder op_order_;
     31 };
     32 
     33 
     34 static const ByteMnemonic two_operands_instr[] = {
     35   {0x01, "add", OPER_REG_OP_ORDER},
     36   {0x03, "add", REG_OPER_OP_ORDER},
     37   {0x09, "or", OPER_REG_OP_ORDER},
     38   {0x0B, "or", REG_OPER_OP_ORDER},
     39   {0x1B, "sbb", REG_OPER_OP_ORDER},
     40   {0x21, "and", OPER_REG_OP_ORDER},
     41   {0x23, "and", REG_OPER_OP_ORDER},
     42   {0x29, "sub", OPER_REG_OP_ORDER},
     43   {0x2A, "subb", REG_OPER_OP_ORDER},
     44   {0x2B, "sub", REG_OPER_OP_ORDER},
     45   {0x31, "xor", OPER_REG_OP_ORDER},
     46   {0x33, "xor", REG_OPER_OP_ORDER},
     47   {0x38, "cmpb", OPER_REG_OP_ORDER},
     48   {0x3A, "cmpb", REG_OPER_OP_ORDER},
     49   {0x3B, "cmp", REG_OPER_OP_ORDER},
     50   {0x84, "test_b", REG_OPER_OP_ORDER},
     51   {0x85, "test", REG_OPER_OP_ORDER},
     52   {0x87, "xchg", REG_OPER_OP_ORDER},
     53   {0x8A, "mov_b", REG_OPER_OP_ORDER},
     54   {0x8B, "mov", REG_OPER_OP_ORDER},
     55   {0x8D, "lea", REG_OPER_OP_ORDER},
     56   {-1, "", UNSET_OP_ORDER}
     57 };
     58 
     59 
     60 static const ByteMnemonic zero_operands_instr[] = {
     61   {0xC3, "ret", UNSET_OP_ORDER},
     62   {0xC9, "leave", UNSET_OP_ORDER},
     63   {0x90, "nop", UNSET_OP_ORDER},
     64   {0xF4, "hlt", UNSET_OP_ORDER},
     65   {0xCC, "int3", UNSET_OP_ORDER},
     66   {0x60, "pushad", UNSET_OP_ORDER},
     67   {0x61, "popad", UNSET_OP_ORDER},
     68   {0x9C, "pushfd", UNSET_OP_ORDER},
     69   {0x9D, "popfd", UNSET_OP_ORDER},
     70   {0x9E, "sahf", UNSET_OP_ORDER},
     71   {0x99, "cdq", UNSET_OP_ORDER},
     72   {0x9B, "fwait", UNSET_OP_ORDER},
     73   {0xFC, "cld", UNSET_OP_ORDER},
     74   {0xAB, "stos", UNSET_OP_ORDER},
     75   {-1, "", UNSET_OP_ORDER}
     76 };
     77 
     78 
     79 static const ByteMnemonic call_jump_instr[] = {
     80   {0xE8, "call", UNSET_OP_ORDER},
     81   {0xE9, "jmp", UNSET_OP_ORDER},
     82   {-1, "", UNSET_OP_ORDER}
     83 };
     84 
     85 
     86 static const ByteMnemonic short_immediate_instr[] = {
     87   {0x05, "add", UNSET_OP_ORDER},
     88   {0x0D, "or", UNSET_OP_ORDER},
     89   {0x15, "adc", UNSET_OP_ORDER},
     90   {0x25, "and", UNSET_OP_ORDER},
     91   {0x2D, "sub", UNSET_OP_ORDER},
     92   {0x35, "xor", UNSET_OP_ORDER},
     93   {0x3D, "cmp", UNSET_OP_ORDER},
     94   {-1, "", UNSET_OP_ORDER}
     95 };
     96 
     97 
     98 // Generally we don't want to generate these because they are subject to partial
     99 // register stalls.  They are included for completeness and because the cmp
    100 // variant is used by the RecordWrite stub.  Because it does not update the
    101 // register it is not subject to partial register stalls.
    102 static ByteMnemonic byte_immediate_instr[] = {
    103   {0x0c, "or", UNSET_OP_ORDER},
    104   {0x24, "and", UNSET_OP_ORDER},
    105   {0x34, "xor", UNSET_OP_ORDER},
    106   {0x3c, "cmp", UNSET_OP_ORDER},
    107   {-1, "", UNSET_OP_ORDER}
    108 };
    109 
    110 
    111 static const char* const jump_conditional_mnem[] = {
    112   /*0*/ "jo", "jno", "jc", "jnc",
    113   /*4*/ "jz", "jnz", "jna", "ja",
    114   /*8*/ "js", "jns", "jpe", "jpo",
    115   /*12*/ "jl", "jnl", "jng", "jg"
    116 };
    117 
    118 
    119 static const char* const set_conditional_mnem[] = {
    120   /*0*/ "seto", "setno", "setc", "setnc",
    121   /*4*/ "setz", "setnz", "setna", "seta",
    122   /*8*/ "sets", "setns", "setpe", "setpo",
    123   /*12*/ "setl", "setnl", "setng", "setg"
    124 };
    125 
    126 
    127 static const char* const conditional_move_mnem[] = {
    128   /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
    129   /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
    130   /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
    131   /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
    132 };
    133 
    134 
    135 enum InstructionType {
    136   NO_INSTR,
    137   ZERO_OPERANDS_INSTR,
    138   TWO_OPERANDS_INSTR,
    139   JUMP_CONDITIONAL_SHORT_INSTR,
    140   REGISTER_INSTR,
    141   MOVE_REG_INSTR,
    142   CALL_JUMP_INSTR,
    143   SHORT_IMMEDIATE_INSTR,
    144   BYTE_IMMEDIATE_INSTR
    145 };
    146 
    147 
    148 struct InstructionDesc {
    149   const char* mnem;
    150   InstructionType type;
    151   OperandOrder op_order_;
    152 };
    153 
    154 
    155 class InstructionTable {
    156  public:
    157   InstructionTable();
    158   const InstructionDesc& Get(byte x) const { return instructions_[x]; }
    159   static InstructionTable* get_instance() {
    160     static InstructionTable table;
    161     return &table;
    162   }
    163 
    164  private:
    165   InstructionDesc instructions_[256];
    166   void Clear();
    167   void Init();
    168   void CopyTable(const ByteMnemonic bm[], InstructionType type);
    169   void SetTableRange(InstructionType type,
    170                      byte start,
    171                      byte end,
    172                      const char* mnem);
    173   void AddJumpConditionalShort();
    174 };
    175 
    176 
    177 InstructionTable::InstructionTable() {
    178   Clear();
    179   Init();
    180 }
    181 
    182 
    183 void InstructionTable::Clear() {
    184   for (int i = 0; i < 256; i++) {
    185     instructions_[i].mnem = "";
    186     instructions_[i].type = NO_INSTR;
    187     instructions_[i].op_order_ = UNSET_OP_ORDER;
    188   }
    189 }
    190 
    191 
    192 void InstructionTable::Init() {
    193   CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
    194   CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
    195   CopyTable(call_jump_instr, CALL_JUMP_INSTR);
    196   CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
    197   CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
    198   AddJumpConditionalShort();
    199   SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
    200   SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
    201   SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
    202   SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
    203   SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,");  // 0x90 is nop.
    204   SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
    205 }
    206 
    207 
    208 void InstructionTable::CopyTable(const ByteMnemonic bm[],
    209                                  InstructionType type) {
    210   for (int i = 0; bm[i].b >= 0; i++) {
    211     InstructionDesc* id = &instructions_[bm[i].b];
    212     id->mnem = bm[i].mnem;
    213     id->op_order_ = bm[i].op_order_;
    214     ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered.
    215     id->type = type;
    216   }
    217 }
    218 
    219 
    220 void InstructionTable::SetTableRange(InstructionType type,
    221                                      byte start,
    222                                      byte end,
    223                                      const char* mnem) {
    224   for (byte b = start; b <= end; b++) {
    225     InstructionDesc* id = &instructions_[b];
    226     ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered.
    227     id->mnem = mnem;
    228     id->type = type;
    229   }
    230 }
    231 
    232 
    233 void InstructionTable::AddJumpConditionalShort() {
    234   for (byte b = 0x70; b <= 0x7F; b++) {
    235     InstructionDesc* id = &instructions_[b];
    236     ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered.
    237     id->mnem = jump_conditional_mnem[b & 0x0F];
    238     id->type = JUMP_CONDITIONAL_SHORT_INSTR;
    239   }
    240 }
    241 
    242 
    243 // The IA32 disassembler implementation.
    244 class DisassemblerIA32 {
    245  public:
    246   DisassemblerIA32(const NameConverter& converter,
    247                    bool abort_on_unimplemented = true)
    248       : converter_(converter),
    249         instruction_table_(InstructionTable::get_instance()),
    250         tmp_buffer_pos_(0),
    251         abort_on_unimplemented_(abort_on_unimplemented) {
    252     tmp_buffer_[0] = '\0';
    253   }
    254 
    255   virtual ~DisassemblerIA32() {}
    256 
    257   // Writes one disassembled instruction into 'buffer' (0-terminated).
    258   // Returns the length of the disassembled machine instruction in bytes.
    259   int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
    260 
    261  private:
    262   const NameConverter& converter_;
    263   InstructionTable* instruction_table_;
    264   v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
    265   unsigned int tmp_buffer_pos_;
    266   bool abort_on_unimplemented_;
    267 
    268   enum {
    269     eax = 0,
    270     ecx = 1,
    271     edx = 2,
    272     ebx = 3,
    273     esp = 4,
    274     ebp = 5,
    275     esi = 6,
    276     edi = 7
    277   };
    278 
    279 
    280   enum ShiftOpcodeExtension {
    281     kROL = 0,
    282     kROR = 1,
    283     kRCL = 2,
    284     kRCR = 3,
    285     kSHL = 4,
    286     KSHR = 5,
    287     kSAR = 7
    288   };
    289 
    290 
    291   const char* NameOfCPURegister(int reg) const {
    292     return converter_.NameOfCPURegister(reg);
    293   }
    294 
    295 
    296   const char* NameOfByteCPURegister(int reg) const {
    297     return converter_.NameOfByteCPURegister(reg);
    298   }
    299 
    300 
    301   const char* NameOfXMMRegister(int reg) const {
    302     return converter_.NameOfXMMRegister(reg);
    303   }
    304 
    305 
    306   const char* NameOfAddress(byte* addr) const {
    307     return converter_.NameOfAddress(addr);
    308   }
    309 
    310 
    311   // Disassembler helper functions.
    312   static void get_modrm(byte data, int* mod, int* regop, int* rm) {
    313     *mod = (data >> 6) & 3;
    314     *regop = (data & 0x38) >> 3;
    315     *rm = data & 7;
    316   }
    317 
    318 
    319   static void get_sib(byte data, int* scale, int* index, int* base) {
    320     *scale = (data >> 6) & 3;
    321     *index = (data >> 3) & 7;
    322     *base = data & 7;
    323   }
    324 
    325   typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
    326 
    327   int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
    328   int PrintRightOperand(byte* modrmp);
    329   int PrintRightByteOperand(byte* modrmp);
    330   int PrintRightXMMOperand(byte* modrmp);
    331   int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
    332   int PrintImmediateOp(byte* data);
    333   int F7Instruction(byte* data);
    334   int D1D3C1Instruction(byte* data);
    335   int JumpShort(byte* data);
    336   int JumpConditional(byte* data, const char* comment);
    337   int JumpConditionalShort(byte* data, const char* comment);
    338   int SetCC(byte* data);
    339   int CMov(byte* data);
    340   int FPUInstruction(byte* data);
    341   int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
    342   int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
    343   void AppendToBuffer(const char* format, ...);
    344 
    345 
    346   void UnimplementedInstruction() {
    347     if (abort_on_unimplemented_) {
    348       UNIMPLEMENTED();
    349     } else {
    350       AppendToBuffer("'Unimplemented Instruction'");
    351     }
    352   }
    353 };
    354 
    355 
    356 void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
    357   v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
    358   va_list args;
    359   va_start(args, format);
    360   int result = v8::internal::VSNPrintF(buf, format, args);
    361   va_end(args);
    362   tmp_buffer_pos_ += result;
    363 }
    364 
    365 int DisassemblerIA32::PrintRightOperandHelper(
    366     byte* modrmp,
    367     RegisterNameMapping direct_register_name) {
    368   int mod, regop, rm;
    369   get_modrm(*modrmp, &mod, &regop, &rm);
    370   RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
    371       &DisassemblerIA32::NameOfCPURegister;
    372   switch (mod) {
    373     case 0:
    374       if (rm == ebp) {
    375         int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
    376         AppendToBuffer("[0x%x]", disp);
    377         return 5;
    378       } else if (rm == esp) {
    379         byte sib = *(modrmp + 1);
    380         int scale, index, base;
    381         get_sib(sib, &scale, &index, &base);
    382         if (index == esp && base == esp && scale == 0 /*times_1*/) {
    383           AppendToBuffer("[%s]", (this->*register_name)(rm));
    384           return 2;
    385         } else if (base == ebp) {
    386           int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
    387           AppendToBuffer("[%s*%d%s0x%x]",
    388                          (this->*register_name)(index),
    389                          1 << scale,
    390                          disp < 0 ? "-" : "+",
    391                          disp < 0 ? -disp : disp);
    392           return 6;
    393         } else if (index != esp && base != ebp) {
    394           // [base+index*scale]
    395           AppendToBuffer("[%s+%s*%d]",
    396                          (this->*register_name)(base),
    397                          (this->*register_name)(index),
    398                          1 << scale);
    399           return 2;
    400         } else {
    401           UnimplementedInstruction();
    402           return 1;
    403         }
    404       } else {
    405         AppendToBuffer("[%s]", (this->*register_name)(rm));
    406         return 1;
    407       }
    408       break;
    409     case 1:  // fall through
    410     case 2:
    411       if (rm == esp) {
    412         byte sib = *(modrmp + 1);
    413         int scale, index, base;
    414         get_sib(sib, &scale, &index, &base);
    415         int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
    416                             : *reinterpret_cast<int8_t*>(modrmp + 2);
    417         if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
    418           AppendToBuffer("[%s%s0x%x]",
    419                          (this->*register_name)(rm),
    420                          disp < 0 ? "-" : "+",
    421                          disp < 0 ? -disp : disp);
    422         } else {
    423           AppendToBuffer("[%s+%s*%d%s0x%x]",
    424                          (this->*register_name)(base),
    425                          (this->*register_name)(index),
    426                          1 << scale,
    427                          disp < 0 ? "-" : "+",
    428                          disp < 0 ? -disp : disp);
    429         }
    430         return mod == 2 ? 6 : 3;
    431       } else {
    432         // No sib.
    433         int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
    434                             : *reinterpret_cast<int8_t*>(modrmp + 1);
    435         AppendToBuffer("[%s%s0x%x]",
    436                        (this->*register_name)(rm),
    437                        disp < 0 ? "-" : "+",
    438                        disp < 0 ? -disp : disp);
    439         return mod == 2 ? 5 : 2;
    440       }
    441       break;
    442     case 3:
    443       AppendToBuffer("%s", (this->*register_name)(rm));
    444       return 1;
    445     default:
    446       UnimplementedInstruction();
    447       return 1;
    448   }
    449   UNREACHABLE();
    450 }
    451 
    452 
    453 int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
    454   return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
    455 }
    456 
    457 
    458 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
    459   return PrintRightOperandHelper(modrmp,
    460                                  &DisassemblerIA32::NameOfByteCPURegister);
    461 }
    462 
    463 
    464 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
    465   return PrintRightOperandHelper(modrmp,
    466                                  &DisassemblerIA32::NameOfXMMRegister);
    467 }
    468 
    469 
    470 // Returns number of bytes used including the current *data.
    471 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
    472 int DisassemblerIA32::PrintOperands(const char* mnem,
    473                                     OperandOrder op_order,
    474                                     byte* data) {
    475   byte modrm = *data;
    476   int mod, regop, rm;
    477   get_modrm(modrm, &mod, &regop, &rm);
    478   int advance = 0;
    479   switch (op_order) {
    480     case REG_OPER_OP_ORDER: {
    481       AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
    482       advance = PrintRightOperand(data);
    483       break;
    484     }
    485     case OPER_REG_OP_ORDER: {
    486       AppendToBuffer("%s ", mnem);
    487       advance = PrintRightOperand(data);
    488       AppendToBuffer(",%s", NameOfCPURegister(regop));
    489       break;
    490     }
    491     default:
    492       UNREACHABLE();
    493       break;
    494   }
    495   return advance;
    496 }
    497 
    498 
    499 // Returns number of bytes used by machine instruction, including *data byte.
    500 // Writes immediate instructions to 'tmp_buffer_'.
    501 int DisassemblerIA32::PrintImmediateOp(byte* data) {
    502   bool sign_extension_bit = (*data & 0x02) != 0;
    503   byte modrm = *(data+1);
    504   int mod, regop, rm;
    505   get_modrm(modrm, &mod, &regop, &rm);
    506   const char* mnem = "Imm???";
    507   switch (regop) {
    508     case 0: mnem = "add"; break;
    509     case 1: mnem = "or"; break;
    510     case 2: mnem = "adc"; break;
    511     case 4: mnem = "and"; break;
    512     case 5: mnem = "sub"; break;
    513     case 6: mnem = "xor"; break;
    514     case 7: mnem = "cmp"; break;
    515     default: UnimplementedInstruction();
    516   }
    517   AppendToBuffer("%s ", mnem);
    518   int count = PrintRightOperand(data+1);
    519   if (sign_extension_bit) {
    520     AppendToBuffer(",0x%x", *(data + 1 + count));
    521     return 1 + count + 1 /*int8*/;
    522   } else {
    523     AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
    524     return 1 + count + 4 /*int32_t*/;
    525   }
    526 }
    527 
    528 
    529 // Returns number of bytes used, including *data.
    530 int DisassemblerIA32::F7Instruction(byte* data) {
    531   ASSERT_EQ(0xF7, *data);
    532   byte modrm = *(data+1);
    533   int mod, regop, rm;
    534   get_modrm(modrm, &mod, &regop, &rm);
    535   if (mod == 3 && regop != 0) {
    536     const char* mnem = NULL;
    537     switch (regop) {
    538       case 2: mnem = "not"; break;
    539       case 3: mnem = "neg"; break;
    540       case 4: mnem = "mul"; break;
    541       case 5: mnem = "imul"; break;
    542       case 7: mnem = "idiv"; break;
    543       default: UnimplementedInstruction();
    544     }
    545     AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
    546     return 2;
    547   } else if (mod == 3 && regop == eax) {
    548     int32_t imm = *reinterpret_cast<int32_t*>(data+2);
    549     AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
    550     return 6;
    551   } else if (regop == eax) {
    552     AppendToBuffer("test ");
    553     int count = PrintRightOperand(data+1);
    554     int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
    555     AppendToBuffer(",0x%x", imm);
    556     return 1+count+4 /*int32_t*/;
    557   } else {
    558     UnimplementedInstruction();
    559     return 2;
    560   }
    561 }
    562 
    563 
    564 int DisassemblerIA32::D1D3C1Instruction(byte* data) {
    565   byte op = *data;
    566   ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
    567   byte modrm = *(data+1);
    568   int mod, regop, rm;
    569   get_modrm(modrm, &mod, &regop, &rm);
    570   int imm8 = -1;
    571   int num_bytes = 2;
    572   if (mod == 3) {
    573     const char* mnem = NULL;
    574     switch (regop) {
    575       case kROL: mnem = "rol"; break;
    576       case kROR: mnem = "ror"; break;
    577       case kRCL: mnem = "rcl"; break;
    578       case kRCR: mnem = "rcr"; break;
    579       case kSHL: mnem = "shl"; break;
    580       case KSHR: mnem = "shr"; break;
    581       case kSAR: mnem = "sar"; break;
    582       default: UnimplementedInstruction();
    583     }
    584     if (op == 0xD1) {
    585       imm8 = 1;
    586     } else if (op == 0xC1) {
    587       imm8 = *(data+2);
    588       num_bytes = 3;
    589     } else if (op == 0xD3) {
    590       // Shift/rotate by cl.
    591     }
    592     ASSERT_NE(NULL, mnem);
    593     AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
    594     if (imm8 >= 0) {
    595       AppendToBuffer("%d", imm8);
    596     } else {
    597       AppendToBuffer("cl");
    598     }
    599   } else {
    600     UnimplementedInstruction();
    601   }
    602   return num_bytes;
    603 }
    604 
    605 
    606 // Returns number of bytes used, including *data.
    607 int DisassemblerIA32::JumpShort(byte* data) {
    608   ASSERT_EQ(0xEB, *data);
    609   byte b = *(data+1);
    610   byte* dest = data + static_cast<int8_t>(b) + 2;
    611   AppendToBuffer("jmp %s", NameOfAddress(dest));
    612   return 2;
    613 }
    614 
    615 
    616 // Returns number of bytes used, including *data.
    617 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
    618   ASSERT_EQ(0x0F, *data);
    619   byte cond = *(data+1) & 0x0F;
    620   byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
    621   const char* mnem = jump_conditional_mnem[cond];
    622   AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
    623   if (comment != NULL) {
    624     AppendToBuffer(", %s", comment);
    625   }
    626   return 6;  // includes 0x0F
    627 }
    628 
    629 
    630 // Returns number of bytes used, including *data.
    631 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
    632   byte cond = *data & 0x0F;
    633   byte b = *(data+1);
    634   byte* dest = data + static_cast<int8_t>(b) + 2;
    635   const char* mnem = jump_conditional_mnem[cond];
    636   AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
    637   if (comment != NULL) {
    638     AppendToBuffer(", %s", comment);
    639   }
    640   return 2;
    641 }
    642 
    643 
    644 // Returns number of bytes used, including *data.
    645 int DisassemblerIA32::SetCC(byte* data) {
    646   ASSERT_EQ(0x0F, *data);
    647   byte cond = *(data+1) & 0x0F;
    648   const char* mnem = set_conditional_mnem[cond];
    649   AppendToBuffer("%s ", mnem);
    650   PrintRightByteOperand(data+2);
    651   return 3;  // Includes 0x0F.
    652 }
    653 
    654 
    655 // Returns number of bytes used, including *data.
    656 int DisassemblerIA32::CMov(byte* data) {
    657   ASSERT_EQ(0x0F, *data);
    658   byte cond = *(data + 1) & 0x0F;
    659   const char* mnem = conditional_move_mnem[cond];
    660   int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
    661   return 2 + op_size;  // includes 0x0F
    662 }
    663 
    664 
    665 // Returns number of bytes used, including *data.
    666 int DisassemblerIA32::FPUInstruction(byte* data) {
    667   byte escape_opcode = *data;
    668   ASSERT_EQ(0xD8, escape_opcode & 0xF8);
    669   byte modrm_byte = *(data+1);
    670 
    671   if (modrm_byte >= 0xC0) {
    672     return RegisterFPUInstruction(escape_opcode, modrm_byte);
    673   } else {
    674     return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
    675   }
    676 }
    677 
    678 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
    679                                            int modrm_byte,
    680                                            byte* modrm_start) {
    681   const char* mnem = "?";
    682   int regop = (modrm_byte >> 3) & 0x7;  // reg/op field of modrm byte.
    683   switch (escape_opcode) {
    684     case 0xD9: switch (regop) {
    685         case 0: mnem = "fld_s"; break;
    686         case 2: mnem = "fst_s"; break;
    687         case 3: mnem = "fstp_s"; break;
    688         case 7: mnem = "fstcw"; break;
    689         default: UnimplementedInstruction();
    690       }
    691       break;
    692 
    693     case 0xDB: switch (regop) {
    694         case 0: mnem = "fild_s"; break;
    695         case 1: mnem = "fisttp_s"; break;
    696         case 2: mnem = "fist_s"; break;
    697         case 3: mnem = "fistp_s"; break;
    698         default: UnimplementedInstruction();
    699       }
    700       break;
    701 
    702     case 0xDD: switch (regop) {
    703         case 0: mnem = "fld_d"; break;
    704         case 1: mnem = "fisttp_d"; break;
    705         case 2: mnem = "fst_d"; break;
    706         case 3: mnem = "fstp_d"; break;
    707         default: UnimplementedInstruction();
    708       }
    709       break;
    710 
    711     case 0xDF: switch (regop) {
    712         case 5: mnem = "fild_d"; break;
    713         case 7: mnem = "fistp_d"; break;
    714         default: UnimplementedInstruction();
    715       }
    716       break;
    717 
    718     default: UnimplementedInstruction();
    719   }
    720   AppendToBuffer("%s ", mnem);
    721   int count = PrintRightOperand(modrm_start);
    722   return count + 1;
    723 }
    724 
    725 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
    726                                              byte modrm_byte) {
    727   bool has_register = false;  // Is the FPU register encoded in modrm_byte?
    728   const char* mnem = "?";
    729 
    730   switch (escape_opcode) {
    731     case 0xD8:
    732       has_register = true;
    733       switch (modrm_byte & 0xF8) {
    734         case 0xC0: mnem = "fadd_i"; break;
    735         case 0xE0: mnem = "fsub_i"; break;
    736         case 0xC8: mnem = "fmul_i"; break;
    737         case 0xF0: mnem = "fdiv_i"; break;
    738         default: UnimplementedInstruction();
    739       }
    740       break;
    741 
    742     case 0xD9:
    743       switch (modrm_byte & 0xF8) {
    744         case 0xC0:
    745           mnem = "fld";
    746           has_register = true;
    747           break;
    748         case 0xC8:
    749           mnem = "fxch";
    750           has_register = true;
    751           break;
    752         default:
    753           switch (modrm_byte) {
    754             case 0xE0: mnem = "fchs"; break;
    755             case 0xE1: mnem = "fabs"; break;
    756             case 0xE4: mnem = "ftst"; break;
    757             case 0xE8: mnem = "fld1"; break;
    758             case 0xEB: mnem = "fldpi"; break;
    759             case 0xED: mnem = "fldln2"; break;
    760             case 0xEE: mnem = "fldz"; break;
    761             case 0xF0: mnem = "f2xm1"; break;
    762             case 0xF1: mnem = "fyl2x"; break;
    763             case 0xF4: mnem = "fxtract"; break;
    764             case 0xF5: mnem = "fprem1"; break;
    765             case 0xF7: mnem = "fincstp"; break;
    766             case 0xF8: mnem = "fprem"; break;
    767             case 0xFC: mnem = "frndint"; break;
    768             case 0xFD: mnem = "fscale"; break;
    769             case 0xFE: mnem = "fsin"; break;
    770             case 0xFF: mnem = "fcos"; break;
    771             default: UnimplementedInstruction();
    772           }
    773       }
    774       break;
    775 
    776     case 0xDA:
    777       if (modrm_byte == 0xE9) {
    778         mnem = "fucompp";
    779       } else {
    780         UnimplementedInstruction();
    781       }
    782       break;
    783 
    784     case 0xDB:
    785       if ((modrm_byte & 0xF8) == 0xE8) {
    786         mnem = "fucomi";
    787         has_register = true;
    788       } else if (modrm_byte  == 0xE2) {
    789         mnem = "fclex";
    790       } else if (modrm_byte == 0xE3) {
    791         mnem = "fninit";
    792       } else {
    793         UnimplementedInstruction();
    794       }
    795       break;
    796 
    797     case 0xDC:
    798       has_register = true;
    799       switch (modrm_byte & 0xF8) {
    800         case 0xC0: mnem = "fadd"; break;
    801         case 0xE8: mnem = "fsub"; break;
    802         case 0xC8: mnem = "fmul"; break;
    803         case 0xF8: mnem = "fdiv"; break;
    804         default: UnimplementedInstruction();
    805       }
    806       break;
    807 
    808     case 0xDD:
    809       has_register = true;
    810       switch (modrm_byte & 0xF8) {
    811         case 0xC0: mnem = "ffree"; break;
    812         case 0xD0: mnem = "fst"; break;
    813         case 0xD8: mnem = "fstp"; break;
    814         default: UnimplementedInstruction();
    815       }
    816       break;
    817 
    818     case 0xDE:
    819       if (modrm_byte  == 0xD9) {
    820         mnem = "fcompp";
    821       } else {
    822         has_register = true;
    823         switch (modrm_byte & 0xF8) {
    824           case 0xC0: mnem = "faddp"; break;
    825           case 0xE8: mnem = "fsubp"; break;
    826           case 0xC8: mnem = "fmulp"; break;
    827           case 0xF8: mnem = "fdivp"; break;
    828           default: UnimplementedInstruction();
    829         }
    830       }
    831       break;
    832 
    833     case 0xDF:
    834       if (modrm_byte == 0xE0) {
    835         mnem = "fnstsw_ax";
    836       } else if ((modrm_byte & 0xF8) == 0xE8) {
    837         mnem = "fucomip";
    838         has_register = true;
    839       }
    840       break;
    841 
    842     default: UnimplementedInstruction();
    843   }
    844 
    845   if (has_register) {
    846     AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
    847   } else {
    848     AppendToBuffer("%s", mnem);
    849   }
    850   return 2;
    851 }
    852 
    853 
    854 // Mnemonics for instructions 0xF0 byte.
    855 // Returns NULL if the instruction is not handled here.
    856 static const char* F0Mnem(byte f0byte) {
    857   switch (f0byte) {
    858     case 0x18: return "prefetch";
    859     case 0xA2: return "cpuid";
    860     case 0xBE: return "movsx_b";
    861     case 0xBF: return "movsx_w";
    862     case 0xB6: return "movzx_b";
    863     case 0xB7: return "movzx_w";
    864     case 0xAF: return "imul";
    865     case 0xA5: return "shld";
    866     case 0xAD: return "shrd";
    867     case 0xAC: return "shrd";  // 3-operand version.
    868     case 0xAB: return "bts";
    869     case 0xBD: return "bsr";
    870     default: return NULL;
    871   }
    872 }
    873 
    874 
    875 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
    876 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
    877                                         byte* instr) {
    878   tmp_buffer_pos_ = 0;  // starting to write as position 0
    879   byte* data = instr;
    880   // Check for hints.
    881   const char* branch_hint = NULL;
    882   // We use these two prefixes only with branch prediction
    883   if (*data == 0x3E /*ds*/) {
    884     branch_hint = "predicted taken";
    885     data++;
    886   } else if (*data == 0x2E /*cs*/) {
    887     branch_hint = "predicted not taken";
    888     data++;
    889   }
    890   bool processed = true;  // Will be set to false if the current instruction
    891                           // is not in 'instructions' table.
    892   const InstructionDesc& idesc = instruction_table_->Get(*data);
    893   switch (idesc.type) {
    894     case ZERO_OPERANDS_INSTR:
    895       AppendToBuffer(idesc.mnem);
    896       data++;
    897       break;
    898 
    899     case TWO_OPERANDS_INSTR:
    900       data++;
    901       data += PrintOperands(idesc.mnem, idesc.op_order_, data);
    902       break;
    903 
    904     case JUMP_CONDITIONAL_SHORT_INSTR:
    905       data += JumpConditionalShort(data, branch_hint);
    906       break;
    907 
    908     case REGISTER_INSTR:
    909       AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
    910       data++;
    911       break;
    912 
    913     case MOVE_REG_INSTR: {
    914       byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
    915       AppendToBuffer("mov %s,%s",
    916                      NameOfCPURegister(*data & 0x07),
    917                      NameOfAddress(addr));
    918       data += 5;
    919       break;
    920     }
    921 
    922     case CALL_JUMP_INSTR: {
    923       byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
    924       AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
    925       data += 5;
    926       break;
    927     }
    928 
    929     case SHORT_IMMEDIATE_INSTR: {
    930       byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
    931       AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
    932       data += 5;
    933       break;
    934     }
    935 
    936     case BYTE_IMMEDIATE_INSTR: {
    937       AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
    938       data += 2;
    939       break;
    940     }
    941 
    942     case NO_INSTR:
    943       processed = false;
    944       break;
    945 
    946     default:
    947       UNIMPLEMENTED();  // This type is not implemented.
    948   }
    949   //----------------------------
    950   if (!processed) {
    951     switch (*data) {
    952       case 0xC2:
    953         AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
    954         data += 3;
    955         break;
    956 
    957       case 0x69:  // fall through
    958       case 0x6B:
    959         { int mod, regop, rm;
    960           get_modrm(*(data+1), &mod, &regop, &rm);
    961           int32_t imm =
    962               *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
    963           AppendToBuffer("imul %s,%s,0x%x",
    964                          NameOfCPURegister(regop),
    965                          NameOfCPURegister(rm),
    966                          imm);
    967           data += 2 + (*data == 0x6B ? 1 : 4);
    968         }
    969         break;
    970 
    971       case 0xF6:
    972         { data++;
    973           int mod, regop, rm;
    974           get_modrm(*data, &mod, &regop, &rm);
    975           if (regop == eax) {
    976             AppendToBuffer("test_b ");
    977             data += PrintRightByteOperand(data);
    978             int32_t imm = *data;
    979             AppendToBuffer(",0x%x", imm);
    980             data++;
    981           } else {
    982             UnimplementedInstruction();
    983           }
    984         }
    985         break;
    986 
    987       case 0x81:  // fall through
    988       case 0x83:  // 0x81 with sign extension bit set
    989         data += PrintImmediateOp(data);
    990         break;
    991 
    992       case 0x0F:
    993         { byte f0byte = data[1];
    994           const char* f0mnem = F0Mnem(f0byte);
    995           if (f0byte == 0x18) {
    996             data += 2;
    997             int mod, regop, rm;
    998             get_modrm(*data, &mod, &regop, &rm);
    999             const char* suffix[] = {"nta", "1", "2", "3"};
   1000             AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
   1001             data += PrintRightOperand(data);
   1002           } else if (f0byte == 0x1F && data[2] == 0) {
   1003             AppendToBuffer("nop");  // 3 byte nop.
   1004             data += 3;
   1005           } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
   1006             AppendToBuffer("nop");  // 4 byte nop.
   1007             data += 4;
   1008           } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
   1009                      data[4] == 0) {
   1010             AppendToBuffer("nop");  // 5 byte nop.
   1011             data += 5;
   1012           } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
   1013                      data[4] == 0 && data[5] == 0 && data[6] == 0) {
   1014             AppendToBuffer("nop");  // 7 byte nop.
   1015             data += 7;
   1016           } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
   1017                      data[4] == 0 && data[5] == 0 && data[6] == 0 &&
   1018                      data[7] == 0) {
   1019             AppendToBuffer("nop");  // 8 byte nop.
   1020             data += 8;
   1021           } else if (f0byte == 0xA2 || f0byte == 0x31) {
   1022             AppendToBuffer("%s", f0mnem);
   1023             data += 2;
   1024           } else if (f0byte == 0x28) {
   1025             data += 2;
   1026             int mod, regop, rm;
   1027             get_modrm(*data, &mod, &regop, &rm);
   1028             AppendToBuffer("movaps %s,%s",
   1029                            NameOfXMMRegister(regop),
   1030                            NameOfXMMRegister(rm));
   1031             data++;
   1032           } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
   1033             const char* const pseudo_op[] = {
   1034               "rcpps",
   1035               "andps",
   1036               "andnps",
   1037               "orps",
   1038               "xorps",
   1039               "addps",
   1040               "mulps",
   1041               "cvtps2pd",
   1042               "cvtdq2ps",
   1043               "subps",
   1044               "minps",
   1045               "divps",
   1046               "maxps",
   1047             };
   1048 
   1049             data += 2;
   1050             int mod, regop, rm;
   1051             get_modrm(*data, &mod, &regop, &rm);
   1052             AppendToBuffer("%s %s,",
   1053                            pseudo_op[f0byte - 0x53],
   1054                            NameOfXMMRegister(regop));
   1055             data += PrintRightXMMOperand(data);
   1056           } else if (f0byte == 0x50) {
   1057             data += 2;
   1058             int mod, regop, rm;
   1059             get_modrm(*data, &mod, &regop, &rm);
   1060             AppendToBuffer("movmskps %s,%s",
   1061                            NameOfCPURegister(regop),
   1062                            NameOfXMMRegister(rm));
   1063             data++;
   1064           } else if (f0byte== 0xC6) {
   1065             // shufps xmm, xmm/m128, imm8
   1066             data += 2;
   1067             int mod, regop, rm;
   1068             get_modrm(*data, &mod, &regop, &rm);
   1069             int8_t imm8 = static_cast<int8_t>(data[1]);
   1070             AppendToBuffer("shufps %s,%s,%d",
   1071                             NameOfXMMRegister(rm),
   1072                             NameOfXMMRegister(regop),
   1073                             static_cast<int>(imm8));
   1074             data += 2;
   1075           } else if ((f0byte & 0xF0) == 0x80) {
   1076             data += JumpConditional(data, branch_hint);
   1077           } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
   1078                      f0byte == 0xB7 || f0byte == 0xAF) {
   1079             data += 2;
   1080             data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
   1081           } else if ((f0byte & 0xF0) == 0x90) {
   1082             data += SetCC(data);
   1083           } else if ((f0byte & 0xF0) == 0x40) {
   1084             data += CMov(data);
   1085           } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
   1086             // shrd, shld, bts
   1087             data += 2;
   1088             AppendToBuffer("%s ", f0mnem);
   1089             int mod, regop, rm;
   1090             get_modrm(*data, &mod, &regop, &rm);
   1091             data += PrintRightOperand(data);
   1092             if (f0byte == 0xAB) {
   1093               AppendToBuffer(",%s", NameOfCPURegister(regop));
   1094             } else {
   1095               AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
   1096             }
   1097           } else if (f0byte == 0xBD) {
   1098             data += 2;
   1099             int mod, regop, rm;
   1100             get_modrm(*data, &mod, &regop, &rm);
   1101             AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
   1102             data += PrintRightOperand(data);
   1103           } else {
   1104             UnimplementedInstruction();
   1105           }
   1106         }
   1107         break;
   1108 
   1109       case 0x8F:
   1110         { data++;
   1111           int mod, regop, rm;
   1112           get_modrm(*data, &mod, &regop, &rm);
   1113           if (regop == eax) {
   1114             AppendToBuffer("pop ");
   1115             data += PrintRightOperand(data);
   1116           }
   1117         }
   1118         break;
   1119 
   1120       case 0xFF:
   1121         { data++;
   1122           int mod, regop, rm;
   1123           get_modrm(*data, &mod, &regop, &rm);
   1124           const char* mnem = NULL;
   1125           switch (regop) {
   1126             case esi: mnem = "push"; break;
   1127             case eax: mnem = "inc"; break;
   1128             case ecx: mnem = "dec"; break;
   1129             case edx: mnem = "call"; break;
   1130             case esp: mnem = "jmp"; break;
   1131             default: mnem = "???";
   1132           }
   1133           AppendToBuffer("%s ", mnem);
   1134           data += PrintRightOperand(data);
   1135         }
   1136         break;
   1137 
   1138       case 0xC7:  // imm32, fall through
   1139       case 0xC6:  // imm8
   1140         { bool is_byte = *data == 0xC6;
   1141           data++;
   1142           if (is_byte) {
   1143             AppendToBuffer("%s ", "mov_b");
   1144             data += PrintRightByteOperand(data);
   1145             int32_t imm = *data;
   1146             AppendToBuffer(",0x%x", imm);
   1147             data++;
   1148           } else {
   1149             AppendToBuffer("%s ", "mov");
   1150             data += PrintRightOperand(data);
   1151             int32_t imm = *reinterpret_cast<int32_t*>(data);
   1152             AppendToBuffer(",0x%x", imm);
   1153             data += 4;
   1154           }
   1155         }
   1156         break;
   1157 
   1158       case 0x80:
   1159         { data++;
   1160           int mod, regop, rm;
   1161           get_modrm(*data, &mod, &regop, &rm);
   1162           const char* mnem = NULL;
   1163           switch (regop) {
   1164             case 5:  mnem = "subb"; break;
   1165             case 7:  mnem = "cmpb"; break;
   1166             default: UnimplementedInstruction();
   1167           }
   1168           AppendToBuffer("%s ", mnem);
   1169           data += PrintRightByteOperand(data);
   1170           int32_t imm = *data;
   1171           AppendToBuffer(",0x%x", imm);
   1172           data++;
   1173         }
   1174         break;
   1175 
   1176       case 0x88:  // 8bit, fall through
   1177       case 0x89:  // 32bit
   1178         { bool is_byte = *data == 0x88;
   1179           int mod, regop, rm;
   1180           data++;
   1181           get_modrm(*data, &mod, &regop, &rm);
   1182           if (is_byte) {
   1183             AppendToBuffer("%s ", "mov_b");
   1184             data += PrintRightByteOperand(data);
   1185             AppendToBuffer(",%s", NameOfByteCPURegister(regop));
   1186           } else {
   1187             AppendToBuffer("%s ", "mov");
   1188             data += PrintRightOperand(data);
   1189             AppendToBuffer(",%s", NameOfCPURegister(regop));
   1190           }
   1191         }
   1192         break;
   1193 
   1194       case 0x66:  // prefix
   1195         while (*data == 0x66) data++;
   1196         if (*data == 0xf && data[1] == 0x1f) {
   1197           AppendToBuffer("nop");  // 0x66 prefix
   1198         } else if (*data == 0x90) {
   1199           AppendToBuffer("nop");  // 0x66 prefix
   1200         } else if (*data == 0x8B) {
   1201           data++;
   1202           data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
   1203         } else if (*data == 0x89) {
   1204           data++;
   1205           int mod, regop, rm;
   1206           get_modrm(*data, &mod, &regop, &rm);
   1207           AppendToBuffer("mov_w ");
   1208           data += PrintRightOperand(data);
   1209           AppendToBuffer(",%s", NameOfCPURegister(regop));
   1210         } else if (*data == 0xC7) {
   1211           data++;
   1212           AppendToBuffer("%s ", "mov_w");
   1213           data += PrintRightOperand(data);
   1214           int imm = *reinterpret_cast<int16_t*>(data);
   1215           AppendToBuffer(",0x%x", imm);
   1216           data += 2;
   1217         } else if (*data == 0x0F) {
   1218           data++;
   1219           if (*data == 0x38) {
   1220             data++;
   1221             if (*data == 0x17) {
   1222               data++;
   1223               int mod, regop, rm;
   1224               get_modrm(*data, &mod, &regop, &rm);
   1225               AppendToBuffer("ptest %s,%s",
   1226                              NameOfXMMRegister(regop),
   1227                              NameOfXMMRegister(rm));
   1228               data++;
   1229             } else if (*data == 0x2A) {
   1230               // movntdqa
   1231               data++;
   1232               int mod, regop, rm;
   1233               get_modrm(*data, &mod, &regop, &rm);
   1234               AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
   1235               data += PrintRightOperand(data);
   1236             } else {
   1237               UnimplementedInstruction();
   1238             }
   1239           } else if (*data == 0x3A) {
   1240             data++;
   1241             if (*data == 0x0B) {
   1242               data++;
   1243               int mod, regop, rm;
   1244               get_modrm(*data, &mod, &regop, &rm);
   1245               int8_t imm8 = static_cast<int8_t>(data[1]);
   1246               AppendToBuffer("roundsd %s,%s,%d",
   1247                              NameOfXMMRegister(regop),
   1248                              NameOfXMMRegister(rm),
   1249                              static_cast<int>(imm8));
   1250               data += 2;
   1251             } else if (*data == 0x16) {
   1252               data++;
   1253               int mod, regop, rm;
   1254               get_modrm(*data, &mod, &regop, &rm);
   1255               int8_t imm8 = static_cast<int8_t>(data[1]);
   1256               AppendToBuffer("pextrd %s,%s,%d",
   1257                              NameOfCPURegister(regop),
   1258                              NameOfXMMRegister(rm),
   1259                              static_cast<int>(imm8));
   1260               data += 2;
   1261             } else if (*data == 0x17) {
   1262               data++;
   1263               int mod, regop, rm;
   1264               get_modrm(*data, &mod, &regop, &rm);
   1265               int8_t imm8 = static_cast<int8_t>(data[1]);
   1266               AppendToBuffer("extractps %s,%s,%d",
   1267                              NameOfCPURegister(rm),
   1268                              NameOfXMMRegister(regop),
   1269                              static_cast<int>(imm8));
   1270               data += 2;
   1271             } else if (*data == 0x22) {
   1272               data++;
   1273               int mod, regop, rm;
   1274               get_modrm(*data, &mod, &regop, &rm);
   1275               int8_t imm8 = static_cast<int8_t>(data[1]);
   1276               AppendToBuffer("pinsrd %s,%s,%d",
   1277                              NameOfXMMRegister(regop),
   1278                              NameOfCPURegister(rm),
   1279                              static_cast<int>(imm8));
   1280               data += 2;
   1281             } else {
   1282               UnimplementedInstruction();
   1283             }
   1284           } else if (*data == 0x2E || *data == 0x2F) {
   1285             const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
   1286             data++;
   1287             int mod, regop, rm;
   1288             get_modrm(*data, &mod, &regop, &rm);
   1289             if (mod == 0x3) {
   1290               AppendToBuffer("%s %s,%s", mnem,
   1291                              NameOfXMMRegister(regop),
   1292                              NameOfXMMRegister(rm));
   1293               data++;
   1294             } else {
   1295               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
   1296               data += PrintRightOperand(data);
   1297             }
   1298           } else if (*data == 0x50) {
   1299             data++;
   1300             int mod, regop, rm;
   1301             get_modrm(*data, &mod, &regop, &rm);
   1302             AppendToBuffer("movmskpd %s,%s",
   1303                            NameOfCPURegister(regop),
   1304                            NameOfXMMRegister(rm));
   1305             data++;
   1306           } else if (*data == 0x54) {
   1307             data++;
   1308             int mod, regop, rm;
   1309             get_modrm(*data, &mod, &regop, &rm);
   1310             AppendToBuffer("andpd %s,%s",
   1311                            NameOfXMMRegister(regop),
   1312                            NameOfXMMRegister(rm));
   1313             data++;
   1314           } else if (*data == 0x56) {
   1315             data++;
   1316             int mod, regop, rm;
   1317             get_modrm(*data, &mod, &regop, &rm);
   1318             AppendToBuffer("orpd %s,%s",
   1319                            NameOfXMMRegister(regop),
   1320                            NameOfXMMRegister(rm));
   1321             data++;
   1322           } else if (*data == 0x57) {
   1323             data++;
   1324             int mod, regop, rm;
   1325             get_modrm(*data, &mod, &regop, &rm);
   1326             AppendToBuffer("xorpd %s,%s",
   1327                            NameOfXMMRegister(regop),
   1328                            NameOfXMMRegister(rm));
   1329             data++;
   1330           } else if (*data == 0x6E) {
   1331             data++;
   1332             int mod, regop, rm;
   1333             get_modrm(*data, &mod, &regop, &rm);
   1334             AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
   1335             data += PrintRightOperand(data);
   1336           } else if (*data == 0x6F) {
   1337             data++;
   1338             int mod, regop, rm;
   1339             get_modrm(*data, &mod, &regop, &rm);
   1340             AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
   1341             data += PrintRightXMMOperand(data);
   1342           } else if (*data == 0x70) {
   1343             data++;
   1344             int mod, regop, rm;
   1345             get_modrm(*data, &mod, &regop, &rm);
   1346             int8_t imm8 = static_cast<int8_t>(data[1]);
   1347             AppendToBuffer("pshufd %s,%s,%d",
   1348                            NameOfXMMRegister(regop),
   1349                            NameOfXMMRegister(rm),
   1350                            static_cast<int>(imm8));
   1351             data += 2;
   1352           } else if (*data == 0x76) {
   1353             data++;
   1354             int mod, regop, rm;
   1355             get_modrm(*data, &mod, &regop, &rm);
   1356             AppendToBuffer("pcmpeqd %s,%s",
   1357                            NameOfXMMRegister(regop),
   1358                            NameOfXMMRegister(rm));
   1359             data++;
   1360           } else if (*data == 0x90) {
   1361             data++;
   1362             AppendToBuffer("nop");  // 2 byte nop.
   1363           } else if (*data == 0xF3) {
   1364             data++;
   1365             int mod, regop, rm;
   1366             get_modrm(*data, &mod, &regop, &rm);
   1367             AppendToBuffer("psllq %s,%s",
   1368                            NameOfXMMRegister(regop),
   1369                            NameOfXMMRegister(rm));
   1370             data++;
   1371           } else if (*data == 0x73) {
   1372             data++;
   1373             int mod, regop, rm;
   1374             get_modrm(*data, &mod, &regop, &rm);
   1375             int8_t imm8 = static_cast<int8_t>(data[1]);
   1376             ASSERT(regop == esi || regop == edx);
   1377             AppendToBuffer("%s %s,%d",
   1378                            (regop == esi) ? "psllq" : "psrlq",
   1379                            NameOfXMMRegister(rm),
   1380                            static_cast<int>(imm8));
   1381             data += 2;
   1382           } else if (*data == 0xD3) {
   1383             data++;
   1384             int mod, regop, rm;
   1385             get_modrm(*data, &mod, &regop, &rm);
   1386             AppendToBuffer("psrlq %s,%s",
   1387                            NameOfXMMRegister(regop),
   1388                            NameOfXMMRegister(rm));
   1389             data++;
   1390           } else if (*data == 0x7F) {
   1391             AppendToBuffer("movdqa ");
   1392             data++;
   1393             int mod, regop, rm;
   1394             get_modrm(*data, &mod, &regop, &rm);
   1395             data += PrintRightXMMOperand(data);
   1396             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1397           } else if (*data == 0x7E) {
   1398             data++;
   1399             int mod, regop, rm;
   1400             get_modrm(*data, &mod, &regop, &rm);
   1401             AppendToBuffer("movd ");
   1402             data += PrintRightOperand(data);
   1403             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1404           } else if (*data == 0xDB) {
   1405             data++;
   1406             int mod, regop, rm;
   1407             get_modrm(*data, &mod, &regop, &rm);
   1408             AppendToBuffer("pand %s,%s",
   1409                            NameOfXMMRegister(regop),
   1410                            NameOfXMMRegister(rm));
   1411             data++;
   1412           } else if (*data == 0xE7) {
   1413             data++;
   1414             int mod, regop, rm;
   1415             get_modrm(*data, &mod, &regop, &rm);
   1416             if (mod == 3) {
   1417               AppendToBuffer("movntdq ");
   1418               data += PrintRightOperand(data);
   1419               AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1420             } else {
   1421               UnimplementedInstruction();
   1422             }
   1423           } else if (*data == 0xEF) {
   1424             data++;
   1425             int mod, regop, rm;
   1426             get_modrm(*data, &mod, &regop, &rm);
   1427             AppendToBuffer("pxor %s,%s",
   1428                            NameOfXMMRegister(regop),
   1429                            NameOfXMMRegister(rm));
   1430             data++;
   1431           } else if (*data == 0xEB) {
   1432             data++;
   1433             int mod, regop, rm;
   1434             get_modrm(*data, &mod, &regop, &rm);
   1435             AppendToBuffer("por %s,%s",
   1436                            NameOfXMMRegister(regop),
   1437                            NameOfXMMRegister(rm));
   1438             data++;
   1439           } else {
   1440             UnimplementedInstruction();
   1441           }
   1442         } else {
   1443           UnimplementedInstruction();
   1444         }
   1445         break;
   1446 
   1447       case 0xFE:
   1448         { data++;
   1449           int mod, regop, rm;
   1450           get_modrm(*data, &mod, &regop, &rm);
   1451           if (regop == ecx) {
   1452             AppendToBuffer("dec_b ");
   1453             data += PrintRightOperand(data);
   1454           } else {
   1455             UnimplementedInstruction();
   1456           }
   1457         }
   1458         break;
   1459 
   1460       case 0x68:
   1461         AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
   1462         data += 5;
   1463         break;
   1464 
   1465       case 0x6A:
   1466         AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
   1467         data += 2;
   1468         break;
   1469 
   1470       case 0xA8:
   1471         AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
   1472         data += 2;
   1473         break;
   1474 
   1475       case 0xA9:
   1476         AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
   1477         data += 5;
   1478         break;
   1479 
   1480       case 0xD1:  // fall through
   1481       case 0xD3:  // fall through
   1482       case 0xC1:
   1483         data += D1D3C1Instruction(data);
   1484         break;
   1485 
   1486       case 0xD8:  // fall through
   1487       case 0xD9:  // fall through
   1488       case 0xDA:  // fall through
   1489       case 0xDB:  // fall through
   1490       case 0xDC:  // fall through
   1491       case 0xDD:  // fall through
   1492       case 0xDE:  // fall through
   1493       case 0xDF:
   1494         data += FPUInstruction(data);
   1495         break;
   1496 
   1497       case 0xEB:
   1498         data += JumpShort(data);
   1499         break;
   1500 
   1501       case 0xF2:
   1502         if (*(data+1) == 0x0F) {
   1503           byte b2 = *(data+2);
   1504           if (b2 == 0x11) {
   1505             AppendToBuffer("movsd ");
   1506             data += 3;
   1507             int mod, regop, rm;
   1508             get_modrm(*data, &mod, &regop, &rm);
   1509             data += PrintRightXMMOperand(data);
   1510             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1511           } else if (b2 == 0x10) {
   1512             data += 3;
   1513             int mod, regop, rm;
   1514             get_modrm(*data, &mod, &regop, &rm);
   1515             AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
   1516             data += PrintRightXMMOperand(data);
   1517           } else  if (b2 == 0x5A) {
   1518             data += 3;
   1519             int mod, regop, rm;
   1520             get_modrm(*data, &mod, &regop, &rm);
   1521             AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
   1522             data += PrintRightXMMOperand(data);
   1523           } else {
   1524             const char* mnem = "?";
   1525             switch (b2) {
   1526               case 0x2A: mnem = "cvtsi2sd"; break;
   1527               case 0x2C: mnem = "cvttsd2si"; break;
   1528               case 0x2D: mnem = "cvtsd2si"; break;
   1529               case 0x51: mnem = "sqrtsd"; break;
   1530               case 0x58: mnem = "addsd"; break;
   1531               case 0x59: mnem = "mulsd"; break;
   1532               case 0x5C: mnem = "subsd"; break;
   1533               case 0x5E: mnem = "divsd"; break;
   1534             }
   1535             data += 3;
   1536             int mod, regop, rm;
   1537             get_modrm(*data, &mod, &regop, &rm);
   1538             if (b2 == 0x2A) {
   1539               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
   1540               data += PrintRightOperand(data);
   1541             } else if (b2 == 0x2C || b2 == 0x2D) {
   1542               AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
   1543               data += PrintRightXMMOperand(data);
   1544             } else if (b2 == 0xC2) {
   1545               // Intel manual 2A, Table 3-18.
   1546               const char* const pseudo_op[] = {
   1547                 "cmpeqsd",
   1548                 "cmpltsd",
   1549                 "cmplesd",
   1550                 "cmpunordsd",
   1551                 "cmpneqsd",
   1552                 "cmpnltsd",
   1553                 "cmpnlesd",
   1554                 "cmpordsd"
   1555               };
   1556               AppendToBuffer("%s %s,%s",
   1557                              pseudo_op[data[1]],
   1558                              NameOfXMMRegister(regop),
   1559                              NameOfXMMRegister(rm));
   1560               data += 2;
   1561             } else {
   1562               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
   1563               data += PrintRightXMMOperand(data);
   1564             }
   1565           }
   1566         } else {
   1567           UnimplementedInstruction();
   1568         }
   1569         break;
   1570 
   1571       case 0xF3:
   1572         if (*(data+1) == 0x0F) {
   1573           byte b2 = *(data+2);
   1574           if (b2 == 0x11) {
   1575             AppendToBuffer("movss ");
   1576             data += 3;
   1577             int mod, regop, rm;
   1578             get_modrm(*data, &mod, &regop, &rm);
   1579             data += PrintRightXMMOperand(data);
   1580             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1581           } else if (b2 == 0x10) {
   1582             data += 3;
   1583             int mod, regop, rm;
   1584             get_modrm(*data, &mod, &regop, &rm);
   1585             AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
   1586             data += PrintRightXMMOperand(data);
   1587           } else if (b2 == 0x2C) {
   1588             data += 3;
   1589             int mod, regop, rm;
   1590             get_modrm(*data, &mod, &regop, &rm);
   1591             AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
   1592             data += PrintRightXMMOperand(data);
   1593           } else if (b2 == 0x5A) {
   1594             data += 3;
   1595             int mod, regop, rm;
   1596             get_modrm(*data, &mod, &regop, &rm);
   1597             AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
   1598             data += PrintRightXMMOperand(data);
   1599           } else if (b2 == 0x6F) {
   1600             data += 3;
   1601             int mod, regop, rm;
   1602             get_modrm(*data, &mod, &regop, &rm);
   1603             AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
   1604             data += PrintRightXMMOperand(data);
   1605           } else if (b2 == 0x7F) {
   1606             AppendToBuffer("movdqu ");
   1607             data += 3;
   1608             int mod, regop, rm;
   1609             get_modrm(*data, &mod, &regop, &rm);
   1610             data += PrintRightXMMOperand(data);
   1611             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1612           } else {
   1613             UnimplementedInstruction();
   1614           }
   1615         } else if (*(data+1) == 0xA5) {
   1616           data += 2;
   1617           AppendToBuffer("rep_movs");
   1618         } else if (*(data+1) == 0xAB) {
   1619           data += 2;
   1620           AppendToBuffer("rep_stos");
   1621         } else {
   1622           UnimplementedInstruction();
   1623         }
   1624         break;
   1625 
   1626       case 0xF7:
   1627         data += F7Instruction(data);
   1628         break;
   1629 
   1630       default:
   1631         UnimplementedInstruction();
   1632     }
   1633   }
   1634 
   1635   if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
   1636     tmp_buffer_[tmp_buffer_pos_] = '\0';
   1637   }
   1638 
   1639   int instr_len = data - instr;
   1640   if (instr_len == 0) {
   1641     printf("%02x", *data);
   1642   }
   1643   ASSERT(instr_len > 0);  // Ensure progress.
   1644 
   1645   int outp = 0;
   1646   // Instruction bytes.
   1647   for (byte* bp = instr; bp < data; bp++) {
   1648     outp += v8::internal::SNPrintF(out_buffer + outp,
   1649                                    "%02x",
   1650                                    *bp);
   1651   }
   1652   for (int i = 6 - instr_len; i >= 0; i--) {
   1653     outp += v8::internal::SNPrintF(out_buffer + outp, "  ");
   1654   }
   1655 
   1656   outp += v8::internal::SNPrintF(out_buffer + outp,
   1657                                  " %s",
   1658                                  tmp_buffer_.start());
   1659   return instr_len;
   1660 }  // NOLINT (function is too long)
   1661 
   1662 
   1663 //------------------------------------------------------------------------------
   1664 
   1665 
   1666 static const char* cpu_regs[8] = {
   1667   "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
   1668 };
   1669 
   1670 
   1671 static const char* byte_cpu_regs[8] = {
   1672   "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
   1673 };
   1674 
   1675 
   1676 static const char* xmm_regs[8] = {
   1677   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
   1678 };
   1679 
   1680 
   1681 const char* NameConverter::NameOfAddress(byte* addr) const {
   1682   v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
   1683   return tmp_buffer_.start();
   1684 }
   1685 
   1686 
   1687 const char* NameConverter::NameOfConstant(byte* addr) const {
   1688   return NameOfAddress(addr);
   1689 }
   1690 
   1691 
   1692 const char* NameConverter::NameOfCPURegister(int reg) const {
   1693   if (0 <= reg && reg < 8) return cpu_regs[reg];
   1694   return "noreg";
   1695 }
   1696 
   1697 
   1698 const char* NameConverter::NameOfByteCPURegister(int reg) const {
   1699   if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
   1700   return "noreg";
   1701 }
   1702 
   1703 
   1704 const char* NameConverter::NameOfXMMRegister(int reg) const {
   1705   if (0 <= reg && reg < 8) return xmm_regs[reg];
   1706   return "noxmmreg";
   1707 }
   1708 
   1709 
   1710 const char* NameConverter::NameInCode(byte* addr) const {
   1711   // IA32 does not embed debug strings at the moment.
   1712   UNREACHABLE();
   1713   return "";
   1714 }
   1715 
   1716 
   1717 //------------------------------------------------------------------------------
   1718 
   1719 Disassembler::Disassembler(const NameConverter& converter)
   1720     : converter_(converter) {}
   1721 
   1722 
   1723 Disassembler::~Disassembler() {}
   1724 
   1725 
   1726 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
   1727                                     byte* instruction) {
   1728   DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
   1729   return d.InstructionDecode(buffer, instruction);
   1730 }
   1731 
   1732 
   1733 // The IA-32 assembler does not currently use constant pools.
   1734 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
   1735 
   1736 
   1737 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
   1738   NameConverter converter;
   1739   Disassembler d(converter);
   1740   for (byte* pc = begin; pc < end;) {
   1741     v8::internal::EmbeddedVector<char, 128> buffer;
   1742     buffer[0] = '\0';
   1743     byte* prev_pc = pc;
   1744     pc += d.InstructionDecode(buffer, pc);
   1745     fprintf(f, "%p", prev_pc);
   1746     fprintf(f, "    ");
   1747 
   1748     for (byte* bp = prev_pc; bp < pc; bp++) {
   1749       fprintf(f, "%02x",  *bp);
   1750     }
   1751     for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
   1752       fprintf(f, "  ");
   1753     }
   1754     fprintf(f, "  %s\n", buffer.start());
   1755   }
   1756 }
   1757 
   1758 
   1759 }  // namespace disasm
   1760 
   1761 #endif  // V8_TARGET_ARCH_IA32
   1762