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