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