Home | History | Annotate | Download | only in x87
      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 <stdarg.h>
      7 #include <stdio.h>
      8 
      9 #include "src/v8.h"
     10 
     11 #if V8_TARGET_ARCH_X87
     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     DCHECK_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     DCHECK_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     DCHECK_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 X87 disassembler implementation.
    244 class DisassemblerX87 {
    245  public:
    246   DisassemblerX87(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 ~DisassemblerX87() {}
    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* (DisassemblerX87::*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 DisassemblerX87::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 DisassemblerX87::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       &DisassemblerX87::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 DisassemblerX87::PrintRightOperand(byte* modrmp) {
    454   return PrintRightOperandHelper(modrmp, &DisassemblerX87::NameOfCPURegister);
    455 }
    456 
    457 
    458 int DisassemblerX87::PrintRightByteOperand(byte* modrmp) {
    459   return PrintRightOperandHelper(modrmp,
    460                                  &DisassemblerX87::NameOfByteCPURegister);
    461 }
    462 
    463 
    464 int DisassemblerX87::PrintRightXMMOperand(byte* modrmp) {
    465   return PrintRightOperandHelper(modrmp,
    466                                  &DisassemblerX87::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 DisassemblerX87::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 DisassemblerX87::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 DisassemblerX87::F7Instruction(byte* data) {
    531   DCHECK_EQ(0xF7, *data);
    532   byte modrm = *++data;
    533   int mod, regop, rm;
    534   get_modrm(modrm, &mod, &regop, &rm);
    535   const char* mnem = NULL;
    536   switch (regop) {
    537     case 0:
    538       mnem = "test";
    539       break;
    540     case 2:
    541       mnem = "not";
    542       break;
    543     case 3:
    544       mnem = "neg";
    545       break;
    546     case 4:
    547       mnem = "mul";
    548       break;
    549     case 5:
    550       mnem = "imul";
    551       break;
    552     case 6:
    553       mnem = "div";
    554       break;
    555     case 7:
    556       mnem = "idiv";
    557       break;
    558     default:
    559       UnimplementedInstruction();
    560   }
    561   AppendToBuffer("%s ", mnem);
    562   int count = PrintRightOperand(data);
    563   if (regop == 0) {
    564     AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
    565     count += 4;
    566   }
    567   return 1 + count;
    568 }
    569 
    570 
    571 int DisassemblerX87::D1D3C1Instruction(byte* data) {
    572   byte op = *data;
    573   DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
    574   byte modrm = *++data;
    575   int mod, regop, rm;
    576   get_modrm(modrm, &mod, &regop, &rm);
    577   int imm8 = -1;
    578   const char* mnem = NULL;
    579   switch (regop) {
    580     case kROL:
    581       mnem = "rol";
    582       break;
    583     case kROR:
    584       mnem = "ror";
    585       break;
    586     case kRCL:
    587       mnem = "rcl";
    588       break;
    589     case kRCR:
    590       mnem = "rcr";
    591       break;
    592     case kSHL:
    593       mnem = "shl";
    594       break;
    595     case KSHR:
    596       mnem = "shr";
    597       break;
    598     case kSAR:
    599       mnem = "sar";
    600       break;
    601     default:
    602       UnimplementedInstruction();
    603   }
    604   AppendToBuffer("%s ", mnem);
    605   int count = PrintRightOperand(data);
    606   if (op == 0xD1) {
    607     imm8 = 1;
    608   } else if (op == 0xC1) {
    609     imm8 = *(data + 1);
    610     count++;
    611   } else if (op == 0xD3) {
    612     // Shift/rotate by cl.
    613   }
    614   if (imm8 >= 0) {
    615     AppendToBuffer(",%d", imm8);
    616   } else {
    617     AppendToBuffer(",cl");
    618   }
    619   return 1 + count;
    620 }
    621 
    622 
    623 // Returns number of bytes used, including *data.
    624 int DisassemblerX87::JumpShort(byte* data) {
    625   DCHECK_EQ(0xEB, *data);
    626   byte b = *(data+1);
    627   byte* dest = data + static_cast<int8_t>(b) + 2;
    628   AppendToBuffer("jmp %s", NameOfAddress(dest));
    629   return 2;
    630 }
    631 
    632 
    633 // Returns number of bytes used, including *data.
    634 int DisassemblerX87::JumpConditional(byte* data, const char* comment) {
    635   DCHECK_EQ(0x0F, *data);
    636   byte cond = *(data+1) & 0x0F;
    637   byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
    638   const char* mnem = jump_conditional_mnem[cond];
    639   AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
    640   if (comment != NULL) {
    641     AppendToBuffer(", %s", comment);
    642   }
    643   return 6;  // includes 0x0F
    644 }
    645 
    646 
    647 // Returns number of bytes used, including *data.
    648 int DisassemblerX87::JumpConditionalShort(byte* data, const char* comment) {
    649   byte cond = *data & 0x0F;
    650   byte b = *(data+1);
    651   byte* dest = data + static_cast<int8_t>(b) + 2;
    652   const char* mnem = jump_conditional_mnem[cond];
    653   AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
    654   if (comment != NULL) {
    655     AppendToBuffer(", %s", comment);
    656   }
    657   return 2;
    658 }
    659 
    660 
    661 // Returns number of bytes used, including *data.
    662 int DisassemblerX87::SetCC(byte* data) {
    663   DCHECK_EQ(0x0F, *data);
    664   byte cond = *(data+1) & 0x0F;
    665   const char* mnem = set_conditional_mnem[cond];
    666   AppendToBuffer("%s ", mnem);
    667   PrintRightByteOperand(data+2);
    668   return 3;  // Includes 0x0F.
    669 }
    670 
    671 
    672 // Returns number of bytes used, including *data.
    673 int DisassemblerX87::CMov(byte* data) {
    674   DCHECK_EQ(0x0F, *data);
    675   byte cond = *(data + 1) & 0x0F;
    676   const char* mnem = conditional_move_mnem[cond];
    677   int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
    678   return 2 + op_size;  // includes 0x0F
    679 }
    680 
    681 
    682 // Returns number of bytes used, including *data.
    683 int DisassemblerX87::FPUInstruction(byte* data) {
    684   byte escape_opcode = *data;
    685   DCHECK_EQ(0xD8, escape_opcode & 0xF8);
    686   byte modrm_byte = *(data+1);
    687 
    688   if (modrm_byte >= 0xC0) {
    689     return RegisterFPUInstruction(escape_opcode, modrm_byte);
    690   } else {
    691     return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
    692   }
    693 }
    694 
    695 int DisassemblerX87::MemoryFPUInstruction(int escape_opcode,
    696                                            int modrm_byte,
    697                                            byte* modrm_start) {
    698   const char* mnem = "?";
    699   int regop = (modrm_byte >> 3) & 0x7;  // reg/op field of modrm byte.
    700   switch (escape_opcode) {
    701     case 0xD9: switch (regop) {
    702         case 0: mnem = "fld_s"; break;
    703         case 2: mnem = "fst_s"; break;
    704         case 3: mnem = "fstp_s"; break;
    705         case 5:
    706           mnem = "fldcw";
    707           break;
    708         case 7:
    709           mnem = "fnstcw";
    710           break;
    711         default: UnimplementedInstruction();
    712       }
    713       break;
    714 
    715     case 0xDB: switch (regop) {
    716         case 0: mnem = "fild_s"; break;
    717         case 1: mnem = "fisttp_s"; break;
    718         case 2: mnem = "fist_s"; break;
    719         case 3: mnem = "fistp_s"; break;
    720         default: UnimplementedInstruction();
    721       }
    722       break;
    723 
    724     case 0xDC:
    725       switch (regop) {
    726         case 0:
    727           mnem = "fadd_d";
    728           break;
    729         default:
    730           UnimplementedInstruction();
    731       }
    732       break;
    733 
    734     case 0xDD: switch (regop) {
    735         case 0: mnem = "fld_d"; break;
    736         case 1: mnem = "fisttp_d"; break;
    737         case 2: mnem = "fst_d"; break;
    738         case 3: mnem = "fstp_d"; break;
    739         case 4:
    740           mnem = "frstor";
    741           break;
    742         case 6:
    743           mnem = "fnsave";
    744           break;
    745         default: UnimplementedInstruction();
    746       }
    747       break;
    748 
    749     case 0xDF: switch (regop) {
    750         case 5: mnem = "fild_d"; break;
    751         case 7: mnem = "fistp_d"; break;
    752         default: UnimplementedInstruction();
    753       }
    754       break;
    755 
    756     default: UnimplementedInstruction();
    757   }
    758   AppendToBuffer("%s ", mnem);
    759   int count = PrintRightOperand(modrm_start);
    760   return count + 1;
    761 }
    762 
    763 int DisassemblerX87::RegisterFPUInstruction(int escape_opcode,
    764                                              byte modrm_byte) {
    765   bool has_register = false;  // Is the FPU register encoded in modrm_byte?
    766   const char* mnem = "?";
    767 
    768   switch (escape_opcode) {
    769     case 0xD8:
    770       has_register = true;
    771       switch (modrm_byte & 0xF8) {
    772         case 0xC0: mnem = "fadd_i"; break;
    773         case 0xE0: mnem = "fsub_i"; break;
    774         case 0xC8: mnem = "fmul_i"; break;
    775         case 0xF0: mnem = "fdiv_i"; break;
    776         default: UnimplementedInstruction();
    777       }
    778       break;
    779 
    780     case 0xD9:
    781       switch (modrm_byte & 0xF8) {
    782         case 0xC0:
    783           mnem = "fld";
    784           has_register = true;
    785           break;
    786         case 0xC8:
    787           mnem = "fxch";
    788           has_register = true;
    789           break;
    790         default:
    791           switch (modrm_byte) {
    792             case 0xE0: mnem = "fchs"; break;
    793             case 0xE1: mnem = "fabs"; break;
    794             case 0xE4: mnem = "ftst"; break;
    795             case 0xE8: mnem = "fld1"; break;
    796             case 0xEB: mnem = "fldpi"; break;
    797             case 0xED: mnem = "fldln2"; break;
    798             case 0xEE: mnem = "fldz"; break;
    799             case 0xF0: mnem = "f2xm1"; break;
    800             case 0xF1: mnem = "fyl2x"; break;
    801             case 0xF4: mnem = "fxtract"; break;
    802             case 0xF5: mnem = "fprem1"; break;
    803             case 0xF7: mnem = "fincstp"; break;
    804             case 0xF8: mnem = "fprem"; break;
    805             case 0xFC: mnem = "frndint"; break;
    806             case 0xFD: mnem = "fscale"; break;
    807             case 0xFE: mnem = "fsin"; break;
    808             case 0xFF: mnem = "fcos"; break;
    809             default: UnimplementedInstruction();
    810           }
    811       }
    812       break;
    813 
    814     case 0xDA:
    815       if (modrm_byte == 0xE9) {
    816         mnem = "fucompp";
    817       } else {
    818         UnimplementedInstruction();
    819       }
    820       break;
    821 
    822     case 0xDB:
    823       if ((modrm_byte & 0xF8) == 0xE8) {
    824         mnem = "fucomi";
    825         has_register = true;
    826       } else if (modrm_byte  == 0xE2) {
    827         mnem = "fclex";
    828       } else if (modrm_byte == 0xE3) {
    829         mnem = "fninit";
    830       } else {
    831         UnimplementedInstruction();
    832       }
    833       break;
    834 
    835     case 0xDC:
    836       has_register = true;
    837       switch (modrm_byte & 0xF8) {
    838         case 0xC0: mnem = "fadd"; break;
    839         case 0xE8: mnem = "fsub"; break;
    840         case 0xC8: mnem = "fmul"; break;
    841         case 0xF8: mnem = "fdiv"; break;
    842         default: UnimplementedInstruction();
    843       }
    844       break;
    845 
    846     case 0xDD:
    847       has_register = true;
    848       switch (modrm_byte & 0xF8) {
    849         case 0xC0: mnem = "ffree"; break;
    850         case 0xD0: mnem = "fst"; break;
    851         case 0xD8: mnem = "fstp"; break;
    852         default: UnimplementedInstruction();
    853       }
    854       break;
    855 
    856     case 0xDE:
    857       if (modrm_byte  == 0xD9) {
    858         mnem = "fcompp";
    859       } else {
    860         has_register = true;
    861         switch (modrm_byte & 0xF8) {
    862           case 0xC0: mnem = "faddp"; break;
    863           case 0xE8: mnem = "fsubp"; break;
    864           case 0xC8: mnem = "fmulp"; break;
    865           case 0xF8: mnem = "fdivp"; break;
    866           default: UnimplementedInstruction();
    867         }
    868       }
    869       break;
    870 
    871     case 0xDF:
    872       if (modrm_byte == 0xE0) {
    873         mnem = "fnstsw_ax";
    874       } else if ((modrm_byte & 0xF8) == 0xE8) {
    875         mnem = "fucomip";
    876         has_register = true;
    877       }
    878       break;
    879 
    880     default: UnimplementedInstruction();
    881   }
    882 
    883   if (has_register) {
    884     AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
    885   } else {
    886     AppendToBuffer("%s", mnem);
    887   }
    888   return 2;
    889 }
    890 
    891 
    892 // Mnemonics for instructions 0xF0 byte.
    893 // Returns NULL if the instruction is not handled here.
    894 static const char* F0Mnem(byte f0byte) {
    895   switch (f0byte) {
    896     case 0x18: return "prefetch";
    897     case 0xA2: return "cpuid";
    898     case 0xBE: return "movsx_b";
    899     case 0xBF: return "movsx_w";
    900     case 0xB6: return "movzx_b";
    901     case 0xB7: return "movzx_w";
    902     case 0xAF: return "imul";
    903     case 0xA5: return "shld";
    904     case 0xAD: return "shrd";
    905     case 0xAC: return "shrd";  // 3-operand version.
    906     case 0xAB: return "bts";
    907     case 0xBD: return "bsr";
    908     default: return NULL;
    909   }
    910 }
    911 
    912 
    913 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
    914 int DisassemblerX87::InstructionDecode(v8::internal::Vector<char> out_buffer,
    915                                         byte* instr) {
    916   tmp_buffer_pos_ = 0;  // starting to write as position 0
    917   byte* data = instr;
    918   // Check for hints.
    919   const char* branch_hint = NULL;
    920   // We use these two prefixes only with branch prediction
    921   if (*data == 0x3E /*ds*/) {
    922     branch_hint = "predicted taken";
    923     data++;
    924   } else if (*data == 0x2E /*cs*/) {
    925     branch_hint = "predicted not taken";
    926     data++;
    927   }
    928   bool processed = true;  // Will be set to false if the current instruction
    929                           // is not in 'instructions' table.
    930   const InstructionDesc& idesc = instruction_table_->Get(*data);
    931   switch (idesc.type) {
    932     case ZERO_OPERANDS_INSTR:
    933       AppendToBuffer(idesc.mnem);
    934       data++;
    935       break;
    936 
    937     case TWO_OPERANDS_INSTR:
    938       data++;
    939       data += PrintOperands(idesc.mnem, idesc.op_order_, data);
    940       break;
    941 
    942     case JUMP_CONDITIONAL_SHORT_INSTR:
    943       data += JumpConditionalShort(data, branch_hint);
    944       break;
    945 
    946     case REGISTER_INSTR:
    947       AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
    948       data++;
    949       break;
    950 
    951     case MOVE_REG_INSTR: {
    952       byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
    953       AppendToBuffer("mov %s,%s",
    954                      NameOfCPURegister(*data & 0x07),
    955                      NameOfAddress(addr));
    956       data += 5;
    957       break;
    958     }
    959 
    960     case CALL_JUMP_INSTR: {
    961       byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
    962       AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
    963       data += 5;
    964       break;
    965     }
    966 
    967     case SHORT_IMMEDIATE_INSTR: {
    968       byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
    969       AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
    970       data += 5;
    971       break;
    972     }
    973 
    974     case BYTE_IMMEDIATE_INSTR: {
    975       AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
    976       data += 2;
    977       break;
    978     }
    979 
    980     case NO_INSTR:
    981       processed = false;
    982       break;
    983 
    984     default:
    985       UNIMPLEMENTED();  // This type is not implemented.
    986   }
    987   //----------------------------
    988   if (!processed) {
    989     switch (*data) {
    990       case 0xC2:
    991         AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
    992         data += 3;
    993         break;
    994 
    995       case 0x6B: {
    996         data++;
    997         data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
    998         AppendToBuffer(",%d", *data);
    999         data++;
   1000       } break;
   1001 
   1002       case 0x69: {
   1003         data++;
   1004         data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
   1005         AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
   1006         data += 4;
   1007         }
   1008         break;
   1009 
   1010       case 0xF6:
   1011         { data++;
   1012           int mod, regop, rm;
   1013           get_modrm(*data, &mod, &regop, &rm);
   1014           if (regop == eax) {
   1015             AppendToBuffer("test_b ");
   1016             data += PrintRightByteOperand(data);
   1017             int32_t imm = *data;
   1018             AppendToBuffer(",0x%x", imm);
   1019             data++;
   1020           } else {
   1021             UnimplementedInstruction();
   1022           }
   1023         }
   1024         break;
   1025 
   1026       case 0x81:  // fall through
   1027       case 0x83:  // 0x81 with sign extension bit set
   1028         data += PrintImmediateOp(data);
   1029         break;
   1030 
   1031       case 0x0F:
   1032         { byte f0byte = data[1];
   1033           const char* f0mnem = F0Mnem(f0byte);
   1034           if (f0byte == 0x18) {
   1035             data += 2;
   1036             int mod, regop, rm;
   1037             get_modrm(*data, &mod, &regop, &rm);
   1038             const char* suffix[] = {"nta", "1", "2", "3"};
   1039             AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
   1040             data += PrintRightOperand(data);
   1041           } else if (f0byte == 0x1F && data[2] == 0) {
   1042             AppendToBuffer("nop");  // 3 byte nop.
   1043             data += 3;
   1044           } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
   1045             AppendToBuffer("nop");  // 4 byte nop.
   1046             data += 4;
   1047           } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
   1048                      data[4] == 0) {
   1049             AppendToBuffer("nop");  // 5 byte nop.
   1050             data += 5;
   1051           } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
   1052                      data[4] == 0 && data[5] == 0 && data[6] == 0) {
   1053             AppendToBuffer("nop");  // 7 byte nop.
   1054             data += 7;
   1055           } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
   1056                      data[4] == 0 && data[5] == 0 && data[6] == 0 &&
   1057                      data[7] == 0) {
   1058             AppendToBuffer("nop");  // 8 byte nop.
   1059             data += 8;
   1060           } else if (f0byte == 0xA2 || f0byte == 0x31) {
   1061             AppendToBuffer("%s", f0mnem);
   1062             data += 2;
   1063           } else if (f0byte == 0x28) {
   1064             data += 2;
   1065             int mod, regop, rm;
   1066             get_modrm(*data, &mod, &regop, &rm);
   1067             AppendToBuffer("movaps %s,%s",
   1068                            NameOfXMMRegister(regop),
   1069                            NameOfXMMRegister(rm));
   1070             data++;
   1071           } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
   1072             const char* const pseudo_op[] = {
   1073               "rcpps",
   1074               "andps",
   1075               "andnps",
   1076               "orps",
   1077               "xorps",
   1078               "addps",
   1079               "mulps",
   1080               "cvtps2pd",
   1081               "cvtdq2ps",
   1082               "subps",
   1083               "minps",
   1084               "divps",
   1085               "maxps",
   1086             };
   1087 
   1088             data += 2;
   1089             int mod, regop, rm;
   1090             get_modrm(*data, &mod, &regop, &rm);
   1091             AppendToBuffer("%s %s,",
   1092                            pseudo_op[f0byte - 0x53],
   1093                            NameOfXMMRegister(regop));
   1094             data += PrintRightXMMOperand(data);
   1095           } else if (f0byte == 0x50) {
   1096             data += 2;
   1097             int mod, regop, rm;
   1098             get_modrm(*data, &mod, &regop, &rm);
   1099             AppendToBuffer("movmskps %s,%s",
   1100                            NameOfCPURegister(regop),
   1101                            NameOfXMMRegister(rm));
   1102             data++;
   1103           } else if (f0byte== 0xC6) {
   1104             // shufps xmm, xmm/m128, imm8
   1105             data += 2;
   1106             int mod, regop, rm;
   1107             get_modrm(*data, &mod, &regop, &rm);
   1108             int8_t imm8 = static_cast<int8_t>(data[1]);
   1109             AppendToBuffer("shufps %s,%s,%d",
   1110                             NameOfXMMRegister(rm),
   1111                             NameOfXMMRegister(regop),
   1112                             static_cast<int>(imm8));
   1113             data += 2;
   1114           } else if ((f0byte & 0xF0) == 0x80) {
   1115             data += JumpConditional(data, branch_hint);
   1116           } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
   1117                      f0byte == 0xB7 || f0byte == 0xAF) {
   1118             data += 2;
   1119             data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
   1120           } else if ((f0byte & 0xF0) == 0x90) {
   1121             data += SetCC(data);
   1122           } else if ((f0byte & 0xF0) == 0x40) {
   1123             data += CMov(data);
   1124           } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
   1125             // shrd, shld, bts
   1126             data += 2;
   1127             AppendToBuffer("%s ", f0mnem);
   1128             int mod, regop, rm;
   1129             get_modrm(*data, &mod, &regop, &rm);
   1130             data += PrintRightOperand(data);
   1131             if (f0byte == 0xAB) {
   1132               AppendToBuffer(",%s", NameOfCPURegister(regop));
   1133             } else {
   1134               AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
   1135             }
   1136           } else if (f0byte == 0xBD) {
   1137             data += 2;
   1138             int mod, regop, rm;
   1139             get_modrm(*data, &mod, &regop, &rm);
   1140             AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
   1141             data += PrintRightOperand(data);
   1142           } else {
   1143             UnimplementedInstruction();
   1144           }
   1145         }
   1146         break;
   1147 
   1148       case 0x8F:
   1149         { data++;
   1150           int mod, regop, rm;
   1151           get_modrm(*data, &mod, &regop, &rm);
   1152           if (regop == eax) {
   1153             AppendToBuffer("pop ");
   1154             data += PrintRightOperand(data);
   1155           }
   1156         }
   1157         break;
   1158 
   1159       case 0xFF:
   1160         { data++;
   1161           int mod, regop, rm;
   1162           get_modrm(*data, &mod, &regop, &rm);
   1163           const char* mnem = NULL;
   1164           switch (regop) {
   1165             case esi: mnem = "push"; break;
   1166             case eax: mnem = "inc"; break;
   1167             case ecx: mnem = "dec"; break;
   1168             case edx: mnem = "call"; break;
   1169             case esp: mnem = "jmp"; break;
   1170             default: mnem = "???";
   1171           }
   1172           AppendToBuffer("%s ", mnem);
   1173           data += PrintRightOperand(data);
   1174         }
   1175         break;
   1176 
   1177       case 0xC7:  // imm32, fall through
   1178       case 0xC6:  // imm8
   1179         { bool is_byte = *data == 0xC6;
   1180           data++;
   1181           if (is_byte) {
   1182             AppendToBuffer("%s ", "mov_b");
   1183             data += PrintRightByteOperand(data);
   1184             int32_t imm = *data;
   1185             AppendToBuffer(",0x%x", imm);
   1186             data++;
   1187           } else {
   1188             AppendToBuffer("%s ", "mov");
   1189             data += PrintRightOperand(data);
   1190             int32_t imm = *reinterpret_cast<int32_t*>(data);
   1191             AppendToBuffer(",0x%x", imm);
   1192             data += 4;
   1193           }
   1194         }
   1195         break;
   1196 
   1197       case 0x80:
   1198         { data++;
   1199           int mod, regop, rm;
   1200           get_modrm(*data, &mod, &regop, &rm);
   1201           const char* mnem = NULL;
   1202           switch (regop) {
   1203             case 5:  mnem = "subb"; break;
   1204             case 7:  mnem = "cmpb"; break;
   1205             default: UnimplementedInstruction();
   1206           }
   1207           AppendToBuffer("%s ", mnem);
   1208           data += PrintRightByteOperand(data);
   1209           int32_t imm = *data;
   1210           AppendToBuffer(",0x%x", imm);
   1211           data++;
   1212         }
   1213         break;
   1214 
   1215       case 0x88:  // 8bit, fall through
   1216       case 0x89:  // 32bit
   1217         { bool is_byte = *data == 0x88;
   1218           int mod, regop, rm;
   1219           data++;
   1220           get_modrm(*data, &mod, &regop, &rm);
   1221           if (is_byte) {
   1222             AppendToBuffer("%s ", "mov_b");
   1223             data += PrintRightByteOperand(data);
   1224             AppendToBuffer(",%s", NameOfByteCPURegister(regop));
   1225           } else {
   1226             AppendToBuffer("%s ", "mov");
   1227             data += PrintRightOperand(data);
   1228             AppendToBuffer(",%s", NameOfCPURegister(regop));
   1229           }
   1230         }
   1231         break;
   1232 
   1233       case 0x66:  // prefix
   1234         while (*data == 0x66) data++;
   1235         if (*data == 0xf && data[1] == 0x1f) {
   1236           AppendToBuffer("nop");  // 0x66 prefix
   1237         } else if (*data == 0x90) {
   1238           AppendToBuffer("nop");  // 0x66 prefix
   1239         } else if (*data == 0x8B) {
   1240           data++;
   1241           data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
   1242         } else if (*data == 0x89) {
   1243           data++;
   1244           int mod, regop, rm;
   1245           get_modrm(*data, &mod, &regop, &rm);
   1246           AppendToBuffer("mov_w ");
   1247           data += PrintRightOperand(data);
   1248           AppendToBuffer(",%s", NameOfCPURegister(regop));
   1249         } else if (*data == 0xC7) {
   1250           data++;
   1251           AppendToBuffer("%s ", "mov_w");
   1252           data += PrintRightOperand(data);
   1253           int imm = *reinterpret_cast<int16_t*>(data);
   1254           AppendToBuffer(",0x%x", imm);
   1255           data += 2;
   1256         } else if (*data == 0x0F) {
   1257           data++;
   1258           if (*data == 0x38) {
   1259             data++;
   1260             if (*data == 0x17) {
   1261               data++;
   1262               int mod, regop, rm;
   1263               get_modrm(*data, &mod, &regop, &rm);
   1264               AppendToBuffer("ptest %s,%s",
   1265                              NameOfXMMRegister(regop),
   1266                              NameOfXMMRegister(rm));
   1267               data++;
   1268             } else if (*data == 0x2A) {
   1269               // movntdqa
   1270               data++;
   1271               int mod, regop, rm;
   1272               get_modrm(*data, &mod, &regop, &rm);
   1273               AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
   1274               data += PrintRightOperand(data);
   1275             } else {
   1276               UnimplementedInstruction();
   1277             }
   1278           } else if (*data == 0x3A) {
   1279             data++;
   1280             if (*data == 0x0B) {
   1281               data++;
   1282               int mod, regop, rm;
   1283               get_modrm(*data, &mod, &regop, &rm);
   1284               int8_t imm8 = static_cast<int8_t>(data[1]);
   1285               AppendToBuffer("roundsd %s,%s,%d",
   1286                              NameOfXMMRegister(regop),
   1287                              NameOfXMMRegister(rm),
   1288                              static_cast<int>(imm8));
   1289               data += 2;
   1290             } else if (*data == 0x16) {
   1291               data++;
   1292               int mod, regop, rm;
   1293               get_modrm(*data, &mod, &regop, &rm);
   1294               int8_t imm8 = static_cast<int8_t>(data[1]);
   1295               AppendToBuffer("pextrd %s,%s,%d",
   1296                              NameOfCPURegister(regop),
   1297                              NameOfXMMRegister(rm),
   1298                              static_cast<int>(imm8));
   1299               data += 2;
   1300             } else if (*data == 0x17) {
   1301               data++;
   1302               int mod, regop, rm;
   1303               get_modrm(*data, &mod, &regop, &rm);
   1304               int8_t imm8 = static_cast<int8_t>(data[1]);
   1305               AppendToBuffer("extractps %s,%s,%d",
   1306                              NameOfCPURegister(rm),
   1307                              NameOfXMMRegister(regop),
   1308                              static_cast<int>(imm8));
   1309               data += 2;
   1310             } else if (*data == 0x22) {
   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               AppendToBuffer("pinsrd %s,%s,%d",
   1316                              NameOfXMMRegister(regop),
   1317                              NameOfCPURegister(rm),
   1318                              static_cast<int>(imm8));
   1319               data += 2;
   1320             } else {
   1321               UnimplementedInstruction();
   1322             }
   1323           } else if (*data == 0x2E || *data == 0x2F) {
   1324             const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
   1325             data++;
   1326             int mod, regop, rm;
   1327             get_modrm(*data, &mod, &regop, &rm);
   1328             if (mod == 0x3) {
   1329               AppendToBuffer("%s %s,%s", mnem,
   1330                              NameOfXMMRegister(regop),
   1331                              NameOfXMMRegister(rm));
   1332               data++;
   1333             } else {
   1334               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
   1335               data += PrintRightOperand(data);
   1336             }
   1337           } else if (*data == 0x50) {
   1338             data++;
   1339             int mod, regop, rm;
   1340             get_modrm(*data, &mod, &regop, &rm);
   1341             AppendToBuffer("movmskpd %s,%s",
   1342                            NameOfCPURegister(regop),
   1343                            NameOfXMMRegister(rm));
   1344             data++;
   1345           } else if (*data == 0x54) {
   1346             data++;
   1347             int mod, regop, rm;
   1348             get_modrm(*data, &mod, &regop, &rm);
   1349             AppendToBuffer("andpd %s,%s",
   1350                            NameOfXMMRegister(regop),
   1351                            NameOfXMMRegister(rm));
   1352             data++;
   1353           } else if (*data == 0x56) {
   1354             data++;
   1355             int mod, regop, rm;
   1356             get_modrm(*data, &mod, &regop, &rm);
   1357             AppendToBuffer("orpd %s,%s",
   1358                            NameOfXMMRegister(regop),
   1359                            NameOfXMMRegister(rm));
   1360             data++;
   1361           } else if (*data == 0x57) {
   1362             data++;
   1363             int mod, regop, rm;
   1364             get_modrm(*data, &mod, &regop, &rm);
   1365             AppendToBuffer("xorpd %s,%s",
   1366                            NameOfXMMRegister(regop),
   1367                            NameOfXMMRegister(rm));
   1368             data++;
   1369           } else if (*data == 0x6E) {
   1370             data++;
   1371             int mod, regop, rm;
   1372             get_modrm(*data, &mod, &regop, &rm);
   1373             AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
   1374             data += PrintRightOperand(data);
   1375           } else if (*data == 0x6F) {
   1376             data++;
   1377             int mod, regop, rm;
   1378             get_modrm(*data, &mod, &regop, &rm);
   1379             AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
   1380             data += PrintRightXMMOperand(data);
   1381           } else if (*data == 0x70) {
   1382             data++;
   1383             int mod, regop, rm;
   1384             get_modrm(*data, &mod, &regop, &rm);
   1385             int8_t imm8 = static_cast<int8_t>(data[1]);
   1386             AppendToBuffer("pshufd %s,%s,%d",
   1387                            NameOfXMMRegister(regop),
   1388                            NameOfXMMRegister(rm),
   1389                            static_cast<int>(imm8));
   1390             data += 2;
   1391           } else if (*data == 0x76) {
   1392             data++;
   1393             int mod, regop, rm;
   1394             get_modrm(*data, &mod, &regop, &rm);
   1395             AppendToBuffer("pcmpeqd %s,%s",
   1396                            NameOfXMMRegister(regop),
   1397                            NameOfXMMRegister(rm));
   1398             data++;
   1399           } else if (*data == 0x90) {
   1400             data++;
   1401             AppendToBuffer("nop");  // 2 byte nop.
   1402           } else if (*data == 0xF3) {
   1403             data++;
   1404             int mod, regop, rm;
   1405             get_modrm(*data, &mod, &regop, &rm);
   1406             AppendToBuffer("psllq %s,%s",
   1407                            NameOfXMMRegister(regop),
   1408                            NameOfXMMRegister(rm));
   1409             data++;
   1410           } else if (*data == 0x73) {
   1411             data++;
   1412             int mod, regop, rm;
   1413             get_modrm(*data, &mod, &regop, &rm);
   1414             int8_t imm8 = static_cast<int8_t>(data[1]);
   1415             DCHECK(regop == esi || regop == edx);
   1416             AppendToBuffer("%s %s,%d",
   1417                            (regop == esi) ? "psllq" : "psrlq",
   1418                            NameOfXMMRegister(rm),
   1419                            static_cast<int>(imm8));
   1420             data += 2;
   1421           } else if (*data == 0xD3) {
   1422             data++;
   1423             int mod, regop, rm;
   1424             get_modrm(*data, &mod, &regop, &rm);
   1425             AppendToBuffer("psrlq %s,%s",
   1426                            NameOfXMMRegister(regop),
   1427                            NameOfXMMRegister(rm));
   1428             data++;
   1429           } else if (*data == 0x7F) {
   1430             AppendToBuffer("movdqa ");
   1431             data++;
   1432             int mod, regop, rm;
   1433             get_modrm(*data, &mod, &regop, &rm);
   1434             data += PrintRightXMMOperand(data);
   1435             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1436           } else if (*data == 0x7E) {
   1437             data++;
   1438             int mod, regop, rm;
   1439             get_modrm(*data, &mod, &regop, &rm);
   1440             AppendToBuffer("movd ");
   1441             data += PrintRightOperand(data);
   1442             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1443           } else if (*data == 0xDB) {
   1444             data++;
   1445             int mod, regop, rm;
   1446             get_modrm(*data, &mod, &regop, &rm);
   1447             AppendToBuffer("pand %s,%s",
   1448                            NameOfXMMRegister(regop),
   1449                            NameOfXMMRegister(rm));
   1450             data++;
   1451           } else if (*data == 0xE7) {
   1452             data++;
   1453             int mod, regop, rm;
   1454             get_modrm(*data, &mod, &regop, &rm);
   1455             if (mod == 3) {
   1456               AppendToBuffer("movntdq ");
   1457               data += PrintRightOperand(data);
   1458               AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1459             } else {
   1460               UnimplementedInstruction();
   1461             }
   1462           } else if (*data == 0xEF) {
   1463             data++;
   1464             int mod, regop, rm;
   1465             get_modrm(*data, &mod, &regop, &rm);
   1466             AppendToBuffer("pxor %s,%s",
   1467                            NameOfXMMRegister(regop),
   1468                            NameOfXMMRegister(rm));
   1469             data++;
   1470           } else if (*data == 0xEB) {
   1471             data++;
   1472             int mod, regop, rm;
   1473             get_modrm(*data, &mod, &regop, &rm);
   1474             AppendToBuffer("por %s,%s",
   1475                            NameOfXMMRegister(regop),
   1476                            NameOfXMMRegister(rm));
   1477             data++;
   1478           } else {
   1479             UnimplementedInstruction();
   1480           }
   1481         } else {
   1482           UnimplementedInstruction();
   1483         }
   1484         break;
   1485 
   1486       case 0xFE:
   1487         { data++;
   1488           int mod, regop, rm;
   1489           get_modrm(*data, &mod, &regop, &rm);
   1490           if (regop == ecx) {
   1491             AppendToBuffer("dec_b ");
   1492             data += PrintRightOperand(data);
   1493           } else {
   1494             UnimplementedInstruction();
   1495           }
   1496         }
   1497         break;
   1498 
   1499       case 0x68:
   1500         AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
   1501         data += 5;
   1502         break;
   1503 
   1504       case 0x6A:
   1505         AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
   1506         data += 2;
   1507         break;
   1508 
   1509       case 0xA8:
   1510         AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
   1511         data += 2;
   1512         break;
   1513 
   1514       case 0xA9:
   1515         AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
   1516         data += 5;
   1517         break;
   1518 
   1519       case 0xD1:  // fall through
   1520       case 0xD3:  // fall through
   1521       case 0xC1:
   1522         data += D1D3C1Instruction(data);
   1523         break;
   1524 
   1525       case 0xD8:  // fall through
   1526       case 0xD9:  // fall through
   1527       case 0xDA:  // fall through
   1528       case 0xDB:  // fall through
   1529       case 0xDC:  // fall through
   1530       case 0xDD:  // fall through
   1531       case 0xDE:  // fall through
   1532       case 0xDF:
   1533         data += FPUInstruction(data);
   1534         break;
   1535 
   1536       case 0xEB:
   1537         data += JumpShort(data);
   1538         break;
   1539 
   1540       case 0xF2:
   1541         if (*(data+1) == 0x0F) {
   1542           byte b2 = *(data+2);
   1543           if (b2 == 0x11) {
   1544             AppendToBuffer("movsd ");
   1545             data += 3;
   1546             int mod, regop, rm;
   1547             get_modrm(*data, &mod, &regop, &rm);
   1548             data += PrintRightXMMOperand(data);
   1549             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1550           } else if (b2 == 0x10) {
   1551             data += 3;
   1552             int mod, regop, rm;
   1553             get_modrm(*data, &mod, &regop, &rm);
   1554             AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
   1555             data += PrintRightXMMOperand(data);
   1556           } else  if (b2 == 0x5A) {
   1557             data += 3;
   1558             int mod, regop, rm;
   1559             get_modrm(*data, &mod, &regop, &rm);
   1560             AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
   1561             data += PrintRightXMMOperand(data);
   1562           } else {
   1563             const char* mnem = "?";
   1564             switch (b2) {
   1565               case 0x2A: mnem = "cvtsi2sd"; break;
   1566               case 0x2C: mnem = "cvttsd2si"; break;
   1567               case 0x2D: mnem = "cvtsd2si"; break;
   1568               case 0x51: mnem = "sqrtsd"; break;
   1569               case 0x58: mnem = "addsd"; break;
   1570               case 0x59: mnem = "mulsd"; break;
   1571               case 0x5C: mnem = "subsd"; break;
   1572               case 0x5E: mnem = "divsd"; break;
   1573             }
   1574             data += 3;
   1575             int mod, regop, rm;
   1576             get_modrm(*data, &mod, &regop, &rm);
   1577             if (b2 == 0x2A) {
   1578               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
   1579               data += PrintRightOperand(data);
   1580             } else if (b2 == 0x2C || b2 == 0x2D) {
   1581               AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
   1582               data += PrintRightXMMOperand(data);
   1583             } else if (b2 == 0xC2) {
   1584               // Intel manual 2A, Table 3-18.
   1585               const char* const pseudo_op[] = {
   1586                 "cmpeqsd",
   1587                 "cmpltsd",
   1588                 "cmplesd",
   1589                 "cmpunordsd",
   1590                 "cmpneqsd",
   1591                 "cmpnltsd",
   1592                 "cmpnlesd",
   1593                 "cmpordsd"
   1594               };
   1595               AppendToBuffer("%s %s,%s",
   1596                              pseudo_op[data[1]],
   1597                              NameOfXMMRegister(regop),
   1598                              NameOfXMMRegister(rm));
   1599               data += 2;
   1600             } else {
   1601               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
   1602               data += PrintRightXMMOperand(data);
   1603             }
   1604           }
   1605         } else {
   1606           UnimplementedInstruction();
   1607         }
   1608         break;
   1609 
   1610       case 0xF3:
   1611         if (*(data+1) == 0x0F) {
   1612           byte b2 = *(data+2);
   1613           if (b2 == 0x11) {
   1614             AppendToBuffer("movss ");
   1615             data += 3;
   1616             int mod, regop, rm;
   1617             get_modrm(*data, &mod, &regop, &rm);
   1618             data += PrintRightXMMOperand(data);
   1619             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1620           } else if (b2 == 0x10) {
   1621             data += 3;
   1622             int mod, regop, rm;
   1623             get_modrm(*data, &mod, &regop, &rm);
   1624             AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
   1625             data += PrintRightXMMOperand(data);
   1626           } else if (b2 == 0x2C) {
   1627             data += 3;
   1628             int mod, regop, rm;
   1629             get_modrm(*data, &mod, &regop, &rm);
   1630             AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
   1631             data += PrintRightXMMOperand(data);
   1632           } else if (b2 == 0x5A) {
   1633             data += 3;
   1634             int mod, regop, rm;
   1635             get_modrm(*data, &mod, &regop, &rm);
   1636             AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
   1637             data += PrintRightXMMOperand(data);
   1638           } else if (b2 == 0x6F) {
   1639             data += 3;
   1640             int mod, regop, rm;
   1641             get_modrm(*data, &mod, &regop, &rm);
   1642             AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
   1643             data += PrintRightXMMOperand(data);
   1644           } else if (b2 == 0x7F) {
   1645             AppendToBuffer("movdqu ");
   1646             data += 3;
   1647             int mod, regop, rm;
   1648             get_modrm(*data, &mod, &regop, &rm);
   1649             data += PrintRightXMMOperand(data);
   1650             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1651           } else {
   1652             UnimplementedInstruction();
   1653           }
   1654         } else if (*(data+1) == 0xA5) {
   1655           data += 2;
   1656           AppendToBuffer("rep_movs");
   1657         } else if (*(data+1) == 0xAB) {
   1658           data += 2;
   1659           AppendToBuffer("rep_stos");
   1660         } else {
   1661           UnimplementedInstruction();
   1662         }
   1663         break;
   1664 
   1665       case 0xF7:
   1666         data += F7Instruction(data);
   1667         break;
   1668 
   1669       default:
   1670         UnimplementedInstruction();
   1671     }
   1672   }
   1673 
   1674   if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
   1675     tmp_buffer_[tmp_buffer_pos_] = '\0';
   1676   }
   1677 
   1678   int instr_len = data - instr;
   1679   if (instr_len == 0) {
   1680     printf("%02x", *data);
   1681   }
   1682   DCHECK(instr_len > 0);  // Ensure progress.
   1683 
   1684   int outp = 0;
   1685   // Instruction bytes.
   1686   for (byte* bp = instr; bp < data; bp++) {
   1687     outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
   1688   }
   1689   for (int i = 6 - instr_len; i >= 0; i--) {
   1690     outp += v8::internal::SNPrintF(out_buffer + outp, "  ");
   1691   }
   1692 
   1693   outp += v8::internal::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.start());
   1694   return instr_len;
   1695 }  // NOLINT (function is too long)
   1696 
   1697 
   1698 //------------------------------------------------------------------------------
   1699 
   1700 
   1701 static const char* cpu_regs[8] = {
   1702   "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
   1703 };
   1704 
   1705 
   1706 static const char* byte_cpu_regs[8] = {
   1707   "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
   1708 };
   1709 
   1710 
   1711 static const char* xmm_regs[8] = {
   1712   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
   1713 };
   1714 
   1715 
   1716 const char* NameConverter::NameOfAddress(byte* addr) const {
   1717   v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
   1718   return tmp_buffer_.start();
   1719 }
   1720 
   1721 
   1722 const char* NameConverter::NameOfConstant(byte* addr) const {
   1723   return NameOfAddress(addr);
   1724 }
   1725 
   1726 
   1727 const char* NameConverter::NameOfCPURegister(int reg) const {
   1728   if (0 <= reg && reg < 8) return cpu_regs[reg];
   1729   return "noreg";
   1730 }
   1731 
   1732 
   1733 const char* NameConverter::NameOfByteCPURegister(int reg) const {
   1734   if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
   1735   return "noreg";
   1736 }
   1737 
   1738 
   1739 const char* NameConverter::NameOfXMMRegister(int reg) const {
   1740   if (0 <= reg && reg < 8) return xmm_regs[reg];
   1741   return "noxmmreg";
   1742 }
   1743 
   1744 
   1745 const char* NameConverter::NameInCode(byte* addr) const {
   1746   // X87 does not embed debug strings at the moment.
   1747   UNREACHABLE();
   1748   return "";
   1749 }
   1750 
   1751 
   1752 //------------------------------------------------------------------------------
   1753 
   1754 Disassembler::Disassembler(const NameConverter& converter)
   1755     : converter_(converter) {}
   1756 
   1757 
   1758 Disassembler::~Disassembler() {}
   1759 
   1760 
   1761 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
   1762                                     byte* instruction) {
   1763   DisassemblerX87 d(converter_, false /*do not crash if unimplemented*/);
   1764   return d.InstructionDecode(buffer, instruction);
   1765 }
   1766 
   1767 
   1768 // The IA-32 assembler does not currently use constant pools.
   1769 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
   1770 
   1771 
   1772 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
   1773   NameConverter converter;
   1774   Disassembler d(converter);
   1775   for (byte* pc = begin; pc < end;) {
   1776     v8::internal::EmbeddedVector<char, 128> buffer;
   1777     buffer[0] = '\0';
   1778     byte* prev_pc = pc;
   1779     pc += d.InstructionDecode(buffer, pc);
   1780     fprintf(f, "%p", prev_pc);
   1781     fprintf(f, "    ");
   1782 
   1783     for (byte* bp = prev_pc; bp < pc; bp++) {
   1784       fprintf(f, "%02x",  *bp);
   1785     }
   1786     for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
   1787       fprintf(f, "  ");
   1788     }
   1789     fprintf(f, "  %s\n", buffer.start());
   1790   }
   1791 }
   1792 
   1793 
   1794 }  // namespace disasm
   1795 
   1796 #endif  // V8_TARGET_ARCH_X87
   1797