Upstream version 9.38.207.0
[platform/framework/web/crosswalk.git] / src / v8 / src / ia32 / disasm-ia32.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_IA32
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 IA32 disassembler implementation.
244 class DisassemblerIA32 {
245  public:
246   DisassemblerIA32(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 ~DisassemblerIA32() {}
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* (DisassemblerIA32::*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 DisassemblerIA32::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 DisassemblerIA32::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       &DisassemblerIA32::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 DisassemblerIA32::PrintRightOperand(byte* modrmp) {
454   return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
455 }
456
457
458 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
459   return PrintRightOperandHelper(modrmp,
460                                  &DisassemblerIA32::NameOfByteCPURegister);
461 }
462
463
464 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
465   return PrintRightOperandHelper(modrmp,
466                                  &DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 == 0x10) {
1051             data += 2;
1052             int mod, regop, rm;
1053             get_modrm(*data, &mod, &regop, &rm);
1054             AppendToBuffer("movups %s,", NameOfXMMRegister(regop));
1055             data += PrintRightXMMOperand(data);
1056           } else if (f0byte == 0x11) {
1057             AppendToBuffer("movups ");
1058             data += 2;
1059             int mod, regop, rm;
1060             get_modrm(*data, &mod, &regop, &rm);
1061             data += PrintRightXMMOperand(data);
1062             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1063           } else if (f0byte >= 0x51 && f0byte <= 0x5F) {
1064             const char* const pseudo_op[] = {
1065               "sqrtps",
1066               "rsqrtps",
1067               "rcpps",
1068               "andps",
1069               "andnps",
1070               "orps",
1071               "xorps",
1072               "addps",
1073               "mulps",
1074               "cvtps2pd",
1075               "cvtdq2ps",
1076               "subps",
1077               "minps",
1078               "divps",
1079               "maxps"
1080             };
1081
1082             data += 2;
1083             int mod, regop, rm;
1084             get_modrm(*data, &mod, &regop, &rm);
1085             AppendToBuffer("%s %s,",
1086                            pseudo_op[f0byte - 0x51],
1087                            NameOfXMMRegister(regop));
1088             data += PrintRightXMMOperand(data);
1089           } else if (f0byte == 0x50) {
1090             data += 2;
1091             int mod, regop, rm;
1092             get_modrm(*data, &mod, &regop, &rm);
1093             AppendToBuffer("movmskps %s,%s",
1094                            NameOfCPURegister(regop),
1095                            NameOfXMMRegister(rm));
1096             data++;
1097           } else if (f0byte == 0xC2) {
1098             // Intel manual 2A, Table 3-11.
1099             data += 2;
1100             int mod, regop, rm;
1101             get_modrm(*data, &mod, &regop, &rm);
1102             const char* const pseudo_op[] = {
1103               "cmpeqps",
1104               "cmpltps",
1105               "cmpleps",
1106               "cmpunordps",
1107               "cmpneqps",
1108               "cmpnltps",
1109               "cmpnleps",
1110               "cmpordps"
1111             };
1112             AppendToBuffer("%s %s,%s",
1113                            pseudo_op[data[1]],
1114                            NameOfXMMRegister(regop),
1115                            NameOfXMMRegister(rm));
1116             data += 2;
1117           } else if (f0byte== 0xC6) {
1118             // shufps xmm, xmm/m128, imm8
1119             data += 2;
1120             int mod, regop, rm;
1121             get_modrm(*data, &mod, &regop, &rm);
1122             int8_t imm8 = static_cast<int8_t>(data[1]);
1123             AppendToBuffer("shufps %s,%s,%d",
1124                             NameOfXMMRegister(rm),
1125                             NameOfXMMRegister(regop),
1126                             static_cast<int>(imm8));
1127             data += 2;
1128           } else if (f0byte== 0x5B) {
1129             data += 2;
1130             int mod, regop, rm;
1131             get_modrm(*data, &mod, &regop, &rm);
1132             AppendToBuffer("cvtdq2ps %s,",
1133                             NameOfXMMRegister(rm));
1134             data += PrintRightXMMOperand(data);
1135           } else if ((f0byte & 0xF0) == 0x80) {
1136             data += JumpConditional(data, branch_hint);
1137           } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1138                      f0byte == 0xB7 || f0byte == 0xAF) {
1139             data += 2;
1140             data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1141           } else if ((f0byte & 0xF0) == 0x90) {
1142             data += SetCC(data);
1143           } else if ((f0byte & 0xF0) == 0x40) {
1144             data += CMov(data);
1145           } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1146             // shrd, shld, bts
1147             data += 2;
1148             AppendToBuffer("%s ", f0mnem);
1149             int mod, regop, rm;
1150             get_modrm(*data, &mod, &regop, &rm);
1151             data += PrintRightOperand(data);
1152             if (f0byte == 0xAB) {
1153               AppendToBuffer(",%s", NameOfCPURegister(regop));
1154             } else {
1155               AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1156             }
1157           } else if (f0byte == 0xBD) {
1158             data += 2;
1159             int mod, regop, rm;
1160             get_modrm(*data, &mod, &regop, &rm);
1161             AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1162             data += PrintRightOperand(data);
1163           } else {
1164             UnimplementedInstruction();
1165           }
1166         }
1167         break;
1168
1169       case 0x8F:
1170         { data++;
1171           int mod, regop, rm;
1172           get_modrm(*data, &mod, &regop, &rm);
1173           if (regop == eax) {
1174             AppendToBuffer("pop ");
1175             data += PrintRightOperand(data);
1176           }
1177         }
1178         break;
1179
1180       case 0xFF:
1181         { data++;
1182           int mod, regop, rm;
1183           get_modrm(*data, &mod, &regop, &rm);
1184           const char* mnem = NULL;
1185           switch (regop) {
1186             case esi: mnem = "push"; break;
1187             case eax: mnem = "inc"; break;
1188             case ecx: mnem = "dec"; break;
1189             case edx: mnem = "call"; break;
1190             case esp: mnem = "jmp"; break;
1191             default: mnem = "???";
1192           }
1193           AppendToBuffer("%s ", mnem);
1194           data += PrintRightOperand(data);
1195         }
1196         break;
1197
1198       case 0xC7:  // imm32, fall through
1199       case 0xC6:  // imm8
1200         { bool is_byte = *data == 0xC6;
1201           data++;
1202           if (is_byte) {
1203             AppendToBuffer("%s ", "mov_b");
1204             data += PrintRightByteOperand(data);
1205             int32_t imm = *data;
1206             AppendToBuffer(",0x%x", imm);
1207             data++;
1208           } else {
1209             AppendToBuffer("%s ", "mov");
1210             data += PrintRightOperand(data);
1211             int32_t imm = *reinterpret_cast<int32_t*>(data);
1212             AppendToBuffer(",0x%x", imm);
1213             data += 4;
1214           }
1215         }
1216         break;
1217
1218       case 0x80:
1219         { data++;
1220           int mod, regop, rm;
1221           get_modrm(*data, &mod, &regop, &rm);
1222           const char* mnem = NULL;
1223           switch (regop) {
1224             case 5:  mnem = "subb"; break;
1225             case 7:  mnem = "cmpb"; break;
1226             default: UnimplementedInstruction();
1227           }
1228           AppendToBuffer("%s ", mnem);
1229           data += PrintRightByteOperand(data);
1230           int32_t imm = *data;
1231           AppendToBuffer(",0x%x", imm);
1232           data++;
1233         }
1234         break;
1235
1236       case 0x88:  // 8bit, fall through
1237       case 0x89:  // 32bit
1238         { bool is_byte = *data == 0x88;
1239           int mod, regop, rm;
1240           data++;
1241           get_modrm(*data, &mod, &regop, &rm);
1242           if (is_byte) {
1243             AppendToBuffer("%s ", "mov_b");
1244             data += PrintRightByteOperand(data);
1245             AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1246           } else {
1247             AppendToBuffer("%s ", "mov");
1248             data += PrintRightOperand(data);
1249             AppendToBuffer(",%s", NameOfCPURegister(regop));
1250           }
1251         }
1252         break;
1253
1254       case 0x66:  // prefix
1255         while (*data == 0x66) data++;
1256         if (*data == 0xf && data[1] == 0x1f) {
1257           AppendToBuffer("nop");  // 0x66 prefix
1258         } else if (*data == 0x90) {
1259           AppendToBuffer("nop");  // 0x66 prefix
1260         } else if (*data == 0x8B) {
1261           data++;
1262           data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1263         } else if (*data == 0x89) {
1264           data++;
1265           int mod, regop, rm;
1266           get_modrm(*data, &mod, &regop, &rm);
1267           AppendToBuffer("mov_w ");
1268           data += PrintRightOperand(data);
1269           AppendToBuffer(",%s", NameOfCPURegister(regop));
1270         } else if (*data == 0xC7) {
1271           data++;
1272           AppendToBuffer("%s ", "mov_w");
1273           data += PrintRightOperand(data);
1274           int imm = *reinterpret_cast<int16_t*>(data);
1275           AppendToBuffer(",0x%x", imm);
1276           data += 2;
1277         } else if (*data == 0x0F) {
1278           data++;
1279           if (*data == 0x38) {
1280             data++;
1281             if (*data == 0x17) {
1282               data++;
1283               int mod, regop, rm;
1284               get_modrm(*data, &mod, &regop, &rm);
1285               AppendToBuffer("ptest %s,%s",
1286                              NameOfXMMRegister(regop),
1287                              NameOfXMMRegister(rm));
1288               data++;
1289             } else if (*data == 0x40) {
1290               data++;
1291               int mod, regop, rm;
1292               get_modrm(*data, &mod, &regop, &rm);
1293               AppendToBuffer("pmulld %s,%s",
1294                              NameOfXMMRegister(regop));
1295               data += PrintRightXMMOperand(data);
1296             } else if (*data == 0x2A) {
1297               // movntdqa
1298               data++;
1299               int mod, regop, rm;
1300               get_modrm(*data, &mod, &regop, &rm);
1301               AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1302               data += PrintRightOperand(data);
1303             } else {
1304               UnimplementedInstruction();
1305             }
1306           } else if (*data == 0x3A) {
1307             data++;
1308             if (*data == 0x0B) {
1309               data++;
1310               int mod, regop, rm;
1311               get_modrm(*data, &mod, &regop, &rm);
1312               int8_t imm8 = static_cast<int8_t>(data[1]);
1313               AppendToBuffer("roundsd %s,%s,%d",
1314                              NameOfXMMRegister(regop),
1315                              NameOfXMMRegister(rm),
1316                              static_cast<int>(imm8));
1317               data += 2;
1318             } else if (*data == 0x16) {
1319               data++;
1320               int mod, regop, rm;
1321               get_modrm(*data, &mod, &regop, &rm);
1322               int8_t imm8 = static_cast<int8_t>(data[1]);
1323               AppendToBuffer("pextrd %s,%s,%d",
1324                              NameOfCPURegister(regop),
1325                              NameOfXMMRegister(rm),
1326                              static_cast<int>(imm8));
1327               data += 2;
1328             } else if (*data == 0x21) {
1329               data++;
1330               int mod, regop, rm;
1331               get_modrm(*data, &mod, &regop, &rm);
1332               int8_t imm8 = static_cast<int8_t>(data[1]);
1333               AppendToBuffer("insertps %s,%s,%d",
1334                              NameOfXMMRegister(regop),
1335                              NameOfXMMRegister(rm),
1336                              static_cast<int>(imm8));
1337               data += 2;
1338             } else if (*data == 0x17) {
1339               data++;
1340               int mod, regop, rm;
1341               get_modrm(*data, &mod, &regop, &rm);
1342               int8_t imm8 = static_cast<int8_t>(data[1]);
1343               AppendToBuffer("extractps %s,%s,%d",
1344                              NameOfCPURegister(rm),
1345                              NameOfXMMRegister(regop),
1346                              static_cast<int>(imm8));
1347               data += 2;
1348             } else if (*data == 0x22) {
1349               data++;
1350               int mod, regop, rm;
1351               get_modrm(*data, &mod, &regop, &rm);
1352               int8_t imm8 = static_cast<int8_t>(data[1]);
1353               AppendToBuffer("pinsrd %s,%s,%d",
1354                              NameOfXMMRegister(regop),
1355                              NameOfCPURegister(rm),
1356                              static_cast<int>(imm8));
1357               data += 2;
1358             } else {
1359               UnimplementedInstruction();
1360             }
1361           } else if (*data == 0x2E || *data == 0x2F) {
1362             const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
1363             data++;
1364             int mod, regop, rm;
1365             get_modrm(*data, &mod, &regop, &rm);
1366             if (mod == 0x3) {
1367               AppendToBuffer("%s %s,%s", mnem,
1368                              NameOfXMMRegister(regop),
1369                              NameOfXMMRegister(rm));
1370               data++;
1371             } else {
1372               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1373               data += PrintRightOperand(data);
1374             }
1375           } else if (*data == 0x50) {
1376             data++;
1377             int mod, regop, rm;
1378             get_modrm(*data, &mod, &regop, &rm);
1379             AppendToBuffer("movmskpd %s,%s",
1380                            NameOfCPURegister(regop),
1381                            NameOfXMMRegister(rm));
1382             data++;
1383           } else if (*data == 0x51) {
1384             data++;
1385             int mod, regop, rm;
1386             get_modrm(*data, &mod, &regop, &rm);
1387             AppendToBuffer("sqrtpd %s,%s",
1388                            NameOfXMMRegister(regop),
1389                            NameOfXMMRegister(rm));
1390             data++;
1391           } else if (*data == 0x54) {
1392             data++;
1393             int mod, regop, rm;
1394             get_modrm(*data, &mod, &regop, &rm);
1395             AppendToBuffer("andpd %s,%s",
1396                            NameOfXMMRegister(regop),
1397                            NameOfXMMRegister(rm));
1398             data++;
1399           } else if (*data == 0x56) {
1400             data++;
1401             int mod, regop, rm;
1402             get_modrm(*data, &mod, &regop, &rm);
1403             AppendToBuffer("orpd %s,%s",
1404                            NameOfXMMRegister(regop),
1405                            NameOfXMMRegister(rm));
1406             data++;
1407           } else if (*data == 0x57) {
1408             data++;
1409             int mod, regop, rm;
1410             get_modrm(*data, &mod, &regop, &rm);
1411             AppendToBuffer("xorpd %s,",
1412                            NameOfXMMRegister(regop));
1413             data += PrintRightXMMOperand(data);
1414           } else if (*data == 0x58) {
1415             data++;
1416             int mod, regop, rm;
1417             get_modrm(*data, &mod, &regop, &rm);
1418             AppendToBuffer("addpd %s,",
1419                            NameOfXMMRegister(regop));
1420             data += PrintRightXMMOperand(data);
1421           } else if (*data == 0x59) {
1422             data++;
1423             int mod, regop, rm;
1424             get_modrm(*data, &mod, &regop, &rm);
1425             AppendToBuffer("mulpd %s,",
1426                            NameOfXMMRegister(regop));
1427             data += PrintRightXMMOperand(data);
1428           } else if (*data == 0x5B) {
1429             data++;
1430             int mod, regop, rm;
1431             get_modrm(*data, &mod, &regop, &rm);
1432             AppendToBuffer("cvtps2dq %s,",
1433                            NameOfXMMRegister(regop));
1434             data += PrintRightXMMOperand(data);
1435           } else if (*data == 0x5C) {
1436             data++;
1437             int mod, regop, rm;
1438             get_modrm(*data, &mod, &regop, &rm);
1439             AppendToBuffer("subpd %s,",
1440                            NameOfXMMRegister(regop));
1441             data += PrintRightXMMOperand(data);
1442           } else if (*data == 0x5D) {
1443             data++;
1444             int mod, regop, rm;
1445             get_modrm(*data, &mod, &regop, &rm);
1446             AppendToBuffer("minpd %s,",
1447                            NameOfXMMRegister(regop));
1448             data += PrintRightXMMOperand(data);
1449           } else if (*data == 0x5E) {
1450             data++;
1451             int mod, regop, rm;
1452             get_modrm(*data, &mod, &regop, &rm);
1453             AppendToBuffer("divpd %s,",
1454                            NameOfXMMRegister(regop));
1455             data += PrintRightXMMOperand(data);
1456           } else if (*data == 0x5F) {
1457             data++;
1458             int mod, regop, rm;
1459             get_modrm(*data, &mod, &regop, &rm);
1460             AppendToBuffer("maxpd %s,",
1461                            NameOfXMMRegister(regop));
1462             data += PrintRightXMMOperand(data);
1463           } else if (*data == 0x62) {
1464             data++;
1465             int mod, regop, rm;
1466             get_modrm(*data, &mod, &regop, &rm);
1467             AppendToBuffer("punpackldq %s,",
1468                             NameOfXMMRegister(regop));
1469             data += PrintRightXMMOperand(data);
1470           } else if (*data == 0xF4) {
1471             data++;
1472             int mod, regop, rm;
1473             get_modrm(*data, &mod, &regop, &rm);
1474             AppendToBuffer("pmuludq %s,",
1475                             NameOfXMMRegister(regop));
1476             data += PrintRightXMMOperand(data);
1477           } else if (*data == 0xFA) {
1478             data++;
1479             int mod, regop, rm;
1480             get_modrm(*data, &mod, &regop, &rm);
1481             AppendToBuffer("psubd %s,",
1482                             NameOfXMMRegister(regop));
1483             data += PrintRightXMMOperand(data);
1484           } else if (*data == 0xFE) {
1485             data++;
1486             int mod, regop, rm;
1487             get_modrm(*data, &mod, &regop, &rm);
1488             AppendToBuffer("paddd %s,",
1489                             NameOfXMMRegister(regop));
1490             data += PrintRightXMMOperand(data);
1491           } else if (*data == 0x6E) {
1492             data++;
1493             int mod, regop, rm;
1494             get_modrm(*data, &mod, &regop, &rm);
1495             AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1496             data += PrintRightOperand(data);
1497           } else if (*data == 0x6F) {
1498             data++;
1499             int mod, regop, rm;
1500             get_modrm(*data, &mod, &regop, &rm);
1501             AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1502             data += PrintRightXMMOperand(data);
1503           } else if (*data == 0x70) {
1504             data++;
1505             int mod, regop, rm;
1506             get_modrm(*data, &mod, &regop, &rm);
1507             int8_t imm8 = static_cast<int8_t>(data[1]);
1508             AppendToBuffer("pshufd %s,%s,%d",
1509                            NameOfXMMRegister(regop),
1510                            NameOfXMMRegister(rm),
1511                            static_cast<int>(imm8));
1512             data += 2;
1513           } else if (*data == 0x66) {
1514             data++;
1515             int mod, regop, rm;
1516             get_modrm(*data, &mod, &regop, &rm);
1517             AppendToBuffer("pcmpgtd %s,%s",
1518                            NameOfXMMRegister(regop),
1519                            NameOfXMMRegister(rm));
1520             data++;
1521           } else if (*data == 0x76) {
1522             data++;
1523             int mod, regop, rm;
1524             get_modrm(*data, &mod, &regop, &rm);
1525             AppendToBuffer("pcmpeqd %s,%s",
1526                            NameOfXMMRegister(regop),
1527                            NameOfXMMRegister(rm));
1528             data++;
1529           } else if (*data == 0x90) {
1530             data++;
1531             AppendToBuffer("nop");  // 2 byte nop.
1532           } else if (*data == 0xF3) {
1533             data++;
1534             int mod, regop, rm;
1535             get_modrm(*data, &mod, &regop, &rm);
1536             AppendToBuffer("psllq %s,%s",
1537                            NameOfXMMRegister(regop),
1538                            NameOfXMMRegister(rm));
1539             data++;
1540           } else if (*data == 0x73) {
1541             data++;
1542             int mod, regop, rm;
1543             get_modrm(*data, &mod, &regop, &rm);
1544             int8_t imm8 = static_cast<int8_t>(data[1]);
1545             DCHECK(regop == esi || regop == edx);
1546             AppendToBuffer("%s %s,%d",
1547                            (regop == esi) ? "psllq" : "psrlq",
1548                            NameOfXMMRegister(rm),
1549                            static_cast<int>(imm8));
1550             data += 2;
1551           } else if (*data == 0xF2) {
1552             data++;
1553             int mod, regop, rm;
1554             get_modrm(*data, &mod, &regop, &rm);
1555             AppendToBuffer("pslld %s,%s",
1556                            NameOfXMMRegister(regop),
1557                            NameOfXMMRegister(rm));
1558             data++;
1559           } else if (*data == 0x72) {
1560             data++;
1561             int mod, regop, rm;
1562             get_modrm(*data, &mod, &regop, &rm);
1563             int8_t imm8 = static_cast<int8_t>(data[1]);
1564             DCHECK(regop == esi || regop == edx);
1565             AppendToBuffer("%s %s,%d",
1566                            (regop == esi) ? "pslld"
1567                            : ((regop == edx) ? "psrld" : "psrad"),
1568                            NameOfXMMRegister(rm),
1569                            static_cast<int>(imm8));
1570             data += 2;
1571           } else if (*data == 0xC6) {
1572             data++;
1573             int mod, regop, rm;
1574             get_modrm(*data, &mod, &regop, &rm);
1575             int8_t imm8 = static_cast<int8_t>(data[1]);
1576             AppendToBuffer("shufpd %s,%s,%d",
1577                            NameOfXMMRegister(regop),
1578                            NameOfXMMRegister(rm),
1579                            static_cast<int>(imm8));
1580             data += 2;
1581           } else if (*data == 0xD2) {
1582             data++;
1583             int mod, regop, rm;
1584             get_modrm(*data, &mod, &regop, &rm);
1585             AppendToBuffer("psrld %s,%s",
1586                            NameOfXMMRegister(regop),
1587                            NameOfXMMRegister(rm));
1588             data++;
1589           } else if (*data == 0xD3) {
1590             data++;
1591             int mod, regop, rm;
1592             get_modrm(*data, &mod, &regop, &rm);
1593             AppendToBuffer("psrlq %s,%s",
1594                            NameOfXMMRegister(regop),
1595                            NameOfXMMRegister(rm));
1596             data++;
1597           } else if (*data == 0xE2) {
1598             data++;
1599             int mod, regop, rm;
1600             get_modrm(*data, &mod, &regop, &rm);
1601             AppendToBuffer("psrad %s,%s",
1602                            NameOfXMMRegister(regop),
1603                            NameOfXMMRegister(rm));
1604             data++;
1605           } else if (*data == 0x7F) {
1606             AppendToBuffer("movdqa ");
1607             data++;
1608             int mod, regop, rm;
1609             get_modrm(*data, &mod, &regop, &rm);
1610             data += PrintRightXMMOperand(data);
1611             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1612           } else if (*data == 0x7E) {
1613             data++;
1614             int mod, regop, rm;
1615             get_modrm(*data, &mod, &regop, &rm);
1616             AppendToBuffer("movd ");
1617             data += PrintRightOperand(data);
1618             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1619           } else if (*data == 0xDB) {
1620             data++;
1621             int mod, regop, rm;
1622             get_modrm(*data, &mod, &regop, &rm);
1623             AppendToBuffer("pand %s,%s",
1624                            NameOfXMMRegister(regop),
1625                            NameOfXMMRegister(rm));
1626             data++;
1627           } else if (*data == 0xE7) {
1628             data++;
1629             int mod, regop, rm;
1630             get_modrm(*data, &mod, &regop, &rm);
1631             if (mod == 3) {
1632               AppendToBuffer("movntdq ");
1633               data += PrintRightOperand(data);
1634               AppendToBuffer(",%s", NameOfXMMRegister(regop));
1635             } else {
1636               UnimplementedInstruction();
1637             }
1638           } else if (*data == 0xEF) {
1639             data++;
1640             int mod, regop, rm;
1641             get_modrm(*data, &mod, &regop, &rm);
1642             AppendToBuffer("pxor %s,%s",
1643                            NameOfXMMRegister(regop),
1644                            NameOfXMMRegister(rm));
1645             data++;
1646           } else if (*data == 0xEB) {
1647             data++;
1648             int mod, regop, rm;
1649             get_modrm(*data, &mod, &regop, &rm);
1650             AppendToBuffer("por %s,%s",
1651                            NameOfXMMRegister(regop),
1652                            NameOfXMMRegister(rm));
1653             data++;
1654           } else {
1655             UnimplementedInstruction();
1656           }
1657         } else {
1658           UnimplementedInstruction();
1659         }
1660         break;
1661
1662       case 0xFE:
1663         { data++;
1664           int mod, regop, rm;
1665           get_modrm(*data, &mod, &regop, &rm);
1666           if (regop == ecx) {
1667             AppendToBuffer("dec_b ");
1668             data += PrintRightOperand(data);
1669           } else {
1670             UnimplementedInstruction();
1671           }
1672         }
1673         break;
1674
1675       case 0x68:
1676         AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1677         data += 5;
1678         break;
1679
1680       case 0x6A:
1681         AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1682         data += 2;
1683         break;
1684
1685       case 0xA8:
1686         AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1687         data += 2;
1688         break;
1689
1690       case 0xA9:
1691         AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1692         data += 5;
1693         break;
1694
1695       case 0xD1:  // fall through
1696       case 0xD3:  // fall through
1697       case 0xC1:
1698         data += D1D3C1Instruction(data);
1699         break;
1700
1701       case 0xD8:  // fall through
1702       case 0xD9:  // fall through
1703       case 0xDA:  // fall through
1704       case 0xDB:  // fall through
1705       case 0xDC:  // fall through
1706       case 0xDD:  // fall through
1707       case 0xDE:  // fall through
1708       case 0xDF:
1709         data += FPUInstruction(data);
1710         break;
1711
1712       case 0xEB:
1713         data += JumpShort(data);
1714         break;
1715
1716       case 0xF2:
1717         if (*(data+1) == 0x0F) {
1718           byte b2 = *(data+2);
1719           if (b2 == 0x11) {
1720             AppendToBuffer("movsd ");
1721             data += 3;
1722             int mod, regop, rm;
1723             get_modrm(*data, &mod, &regop, &rm);
1724             data += PrintRightXMMOperand(data);
1725             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1726           } else if (b2 == 0x10) {
1727             data += 3;
1728             int mod, regop, rm;
1729             get_modrm(*data, &mod, &regop, &rm);
1730             AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1731             data += PrintRightXMMOperand(data);
1732           } else  if (b2 == 0x5A) {
1733             data += 3;
1734             int mod, regop, rm;
1735             get_modrm(*data, &mod, &regop, &rm);
1736             AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1737             data += PrintRightXMMOperand(data);
1738           } else {
1739             const char* mnem = "?";
1740             switch (b2) {
1741               case 0x2A: mnem = "cvtsi2sd"; break;
1742               case 0x2C: mnem = "cvttsd2si"; break;
1743               case 0x2D: mnem = "cvtsd2si"; break;
1744               case 0x51: mnem = "sqrtsd"; break;
1745               case 0x58: mnem = "addsd"; break;
1746               case 0x59: mnem = "mulsd"; break;
1747               case 0x5C: mnem = "subsd"; break;
1748               case 0x5E: mnem = "divsd"; break;
1749             }
1750             data += 3;
1751             int mod, regop, rm;
1752             get_modrm(*data, &mod, &regop, &rm);
1753             if (b2 == 0x2A) {
1754               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1755               data += PrintRightOperand(data);
1756             } else if (b2 == 0x2C || b2 == 0x2D) {
1757               AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1758               data += PrintRightXMMOperand(data);
1759             } else if (b2 == 0xC2) {
1760               // Intel manual 2A, Table 3-18.
1761               const char* const pseudo_op[] = {
1762                 "cmpeqsd",
1763                 "cmpltsd",
1764                 "cmplesd",
1765                 "cmpunordsd",
1766                 "cmpneqsd",
1767                 "cmpnltsd",
1768                 "cmpnlesd",
1769                 "cmpordsd"
1770               };
1771               AppendToBuffer("%s %s,%s",
1772                              pseudo_op[data[1]],
1773                              NameOfXMMRegister(regop),
1774                              NameOfXMMRegister(rm));
1775               data += 2;
1776             } else {
1777               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1778               data += PrintRightXMMOperand(data);
1779             }
1780           }
1781         } else {
1782           UnimplementedInstruction();
1783         }
1784         break;
1785
1786       case 0xF3:
1787         if (*(data+1) == 0x0F) {
1788           byte b2 = *(data+2);
1789           if (b2 == 0x11) {
1790             AppendToBuffer("movss ");
1791             data += 3;
1792             int mod, regop, rm;
1793             get_modrm(*data, &mod, &regop, &rm);
1794             data += PrintRightXMMOperand(data);
1795             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1796           } else if (b2 == 0x10) {
1797             data += 3;
1798             int mod, regop, rm;
1799             get_modrm(*data, &mod, &regop, &rm);
1800             AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1801             data += PrintRightXMMOperand(data);
1802           } else if (b2 == 0x2C) {
1803             data += 3;
1804             int mod, regop, rm;
1805             get_modrm(*data, &mod, &regop, &rm);
1806             AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1807             data += PrintRightXMMOperand(data);
1808           } else if (b2 == 0x5A) {
1809             data += 3;
1810             int mod, regop, rm;
1811             get_modrm(*data, &mod, &regop, &rm);
1812             AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1813             data += PrintRightXMMOperand(data);
1814           } else if (b2 == 0x6F) {
1815             data += 3;
1816             int mod, regop, rm;
1817             get_modrm(*data, &mod, &regop, &rm);
1818             AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1819             data += PrintRightXMMOperand(data);
1820           } else if (b2 == 0x7F) {
1821             AppendToBuffer("movdqu ");
1822             data += 3;
1823             int mod, regop, rm;
1824             get_modrm(*data, &mod, &regop, &rm);
1825             data += PrintRightXMMOperand(data);
1826             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1827           } else {
1828             UnimplementedInstruction();
1829           }
1830         } else if (*(data+1) == 0xA5) {
1831           data += 2;
1832           AppendToBuffer("rep_movs");
1833         } else if (*(data+1) == 0xAB) {
1834           data += 2;
1835           AppendToBuffer("rep_stos");
1836         } else {
1837           UnimplementedInstruction();
1838         }
1839         break;
1840
1841       case 0xF7:
1842         data += F7Instruction(data);
1843         break;
1844
1845       default:
1846         UnimplementedInstruction();
1847     }
1848   }
1849
1850   if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1851     tmp_buffer_[tmp_buffer_pos_] = '\0';
1852   }
1853
1854   int instr_len = data - instr;
1855   if (instr_len == 0) {
1856     printf("%02x", *data);
1857   }
1858   DCHECK(instr_len > 0);  // Ensure progress.
1859
1860   int outp = 0;
1861   // Instruction bytes.
1862   for (byte* bp = instr; bp < data; bp++) {
1863     outp += v8::internal::SNPrintF(out_buffer + outp,
1864                                    "%02x",
1865                                    *bp);
1866   }
1867   for (int i = 6 - instr_len; i >= 0; i--) {
1868     outp += v8::internal::SNPrintF(out_buffer + outp, "  ");
1869   }
1870
1871   outp += v8::internal::SNPrintF(out_buffer + outp,
1872                                  " %s",
1873                                  tmp_buffer_.start());
1874   return instr_len;
1875 }  // NOLINT (function is too long)
1876
1877
1878 //------------------------------------------------------------------------------
1879
1880
1881 static const char* cpu_regs[8] = {
1882   "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1883 };
1884
1885
1886 static const char* byte_cpu_regs[8] = {
1887   "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1888 };
1889
1890
1891 static const char* xmm_regs[8] = {
1892   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1893 };
1894
1895
1896 const char* NameConverter::NameOfAddress(byte* addr) const {
1897   v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1898   return tmp_buffer_.start();
1899 }
1900
1901
1902 const char* NameConverter::NameOfConstant(byte* addr) const {
1903   return NameOfAddress(addr);
1904 }
1905
1906
1907 const char* NameConverter::NameOfCPURegister(int reg) const {
1908   if (0 <= reg && reg < 8) return cpu_regs[reg];
1909   return "noreg";
1910 }
1911
1912
1913 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1914   if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1915   return "noreg";
1916 }
1917
1918
1919 const char* NameConverter::NameOfXMMRegister(int reg) const {
1920   if (0 <= reg && reg < 8) return xmm_regs[reg];
1921   return "noxmmreg";
1922 }
1923
1924
1925 const char* NameConverter::NameInCode(byte* addr) const {
1926   // IA32 does not embed debug strings at the moment.
1927   UNREACHABLE();
1928   return "";
1929 }
1930
1931
1932 //------------------------------------------------------------------------------
1933
1934 Disassembler::Disassembler(const NameConverter& converter)
1935     : converter_(converter) {}
1936
1937
1938 Disassembler::~Disassembler() {}
1939
1940
1941 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1942                                     byte* instruction) {
1943   DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1944   return d.InstructionDecode(buffer, instruction);
1945 }
1946
1947
1948 // The IA-32 assembler does not currently use constant pools.
1949 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1950
1951
1952 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1953   NameConverter converter;
1954   Disassembler d(converter);
1955   for (byte* pc = begin; pc < end;) {
1956     v8::internal::EmbeddedVector<char, 128> buffer;
1957     buffer[0] = '\0';
1958     byte* prev_pc = pc;
1959     pc += d.InstructionDecode(buffer, pc);
1960     fprintf(f, "%p", prev_pc);
1961     fprintf(f, "    ");
1962
1963     for (byte* bp = prev_pc; bp < pc; bp++) {
1964       fprintf(f, "%02x",  *bp);
1965     }
1966     for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1967       fprintf(f, "  ");
1968     }
1969     fprintf(f, "  %s\n", buffer.start());
1970   }
1971 }
1972
1973
1974 }  // namespace disasm
1975
1976 #endif  // V8_TARGET_ARCH_IA32