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