Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / v8 / src / x87 / disasm-x87.cc
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