deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / 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         vex_byte0_(0),
250         vex_byte1_(0),
251         vex_byte2_(0),
252         instruction_table_(InstructionTable::get_instance()),
253         tmp_buffer_pos_(0),
254         abort_on_unimplemented_(abort_on_unimplemented) {
255     tmp_buffer_[0] = '\0';
256   }
257
258   virtual ~DisassemblerIA32() {}
259
260   // Writes one disassembled instruction into 'buffer' (0-terminated).
261   // Returns the length of the disassembled machine instruction in bytes.
262   int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
263
264  private:
265   const NameConverter& converter_;
266   byte vex_byte0_;  // 0xc4 or 0xc5
267   byte vex_byte1_;
268   byte vex_byte2_;  // only for 3 bytes vex prefix
269   InstructionTable* instruction_table_;
270   v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
271   unsigned int tmp_buffer_pos_;
272   bool abort_on_unimplemented_;
273
274   enum {
275     eax = 0,
276     ecx = 1,
277     edx = 2,
278     ebx = 3,
279     esp = 4,
280     ebp = 5,
281     esi = 6,
282     edi = 7
283   };
284
285
286   enum ShiftOpcodeExtension {
287     kROL = 0,
288     kROR = 1,
289     kRCL = 2,
290     kRCR = 3,
291     kSHL = 4,
292     KSHR = 5,
293     kSAR = 7
294   };
295
296   bool vex_128() {
297     DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
298     byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
299     return (checked & 4) != 1;
300   }
301
302   bool vex_66() {
303     DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
304     byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
305     return (checked & 3) == 1;
306   }
307
308   bool vex_f3() {
309     DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
310     byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
311     return (checked & 3) == 2;
312   }
313
314   bool vex_f2() {
315     DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
316     byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
317     return (checked & 3) == 3;
318   }
319
320   bool vex_w() {
321     if (vex_byte0_ == 0xc5) return false;
322     return (vex_byte2_ & 0x80) != 0;
323   }
324
325   bool vex_0f() {
326     if (vex_byte0_ == 0xc5) return true;
327     return (vex_byte1_ & 3) == 1;
328   }
329
330   bool vex_0f38() {
331     if (vex_byte0_ == 0xc5) return false;
332     return (vex_byte1_ & 3) == 2;
333   }
334
335   bool vex_0f3a() {
336     if (vex_byte0_ == 0xc5) return false;
337     return (vex_byte1_ & 3) == 3;
338   }
339
340   int vex_vreg() {
341     DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
342     byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
343     return ~(checked >> 3) & 0xf;
344   }
345
346   char float_size_code() { return "sd"[vex_w()]; }
347
348   const char* NameOfCPURegister(int reg) const {
349     return converter_.NameOfCPURegister(reg);
350   }
351
352
353   const char* NameOfByteCPURegister(int reg) const {
354     return converter_.NameOfByteCPURegister(reg);
355   }
356
357
358   const char* NameOfXMMRegister(int reg) const {
359     return converter_.NameOfXMMRegister(reg);
360   }
361
362
363   const char* NameOfAddress(byte* addr) const {
364     return converter_.NameOfAddress(addr);
365   }
366
367
368   // Disassembler helper functions.
369   static void get_modrm(byte data, int* mod, int* regop, int* rm) {
370     *mod = (data >> 6) & 3;
371     *regop = (data & 0x38) >> 3;
372     *rm = data & 7;
373   }
374
375
376   static void get_sib(byte data, int* scale, int* index, int* base) {
377     *scale = (data >> 6) & 3;
378     *index = (data >> 3) & 7;
379     *base = data & 7;
380   }
381
382   typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
383
384   int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
385   int PrintRightOperand(byte* modrmp);
386   int PrintRightByteOperand(byte* modrmp);
387   int PrintRightXMMOperand(byte* modrmp);
388   int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
389   int PrintImmediateOp(byte* data);
390   int F7Instruction(byte* data);
391   int D1D3C1Instruction(byte* data);
392   int JumpShort(byte* data);
393   int JumpConditional(byte* data, const char* comment);
394   int JumpConditionalShort(byte* data, const char* comment);
395   int SetCC(byte* data);
396   int CMov(byte* data);
397   int FPUInstruction(byte* data);
398   int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
399   int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
400   int AVXInstruction(byte* data);
401   void AppendToBuffer(const char* format, ...);
402
403
404   void UnimplementedInstruction() {
405     if (abort_on_unimplemented_) {
406       UNIMPLEMENTED();
407     } else {
408       AppendToBuffer("'Unimplemented Instruction'");
409     }
410   }
411 };
412
413
414 void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
415   v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
416   va_list args;
417   va_start(args, format);
418   int result = v8::internal::VSNPrintF(buf, format, args);
419   va_end(args);
420   tmp_buffer_pos_ += result;
421 }
422
423 int DisassemblerIA32::PrintRightOperandHelper(
424     byte* modrmp,
425     RegisterNameMapping direct_register_name) {
426   int mod, regop, rm;
427   get_modrm(*modrmp, &mod, &regop, &rm);
428   RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
429       &DisassemblerIA32::NameOfCPURegister;
430   switch (mod) {
431     case 0:
432       if (rm == ebp) {
433         int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
434         AppendToBuffer("[0x%x]", disp);
435         return 5;
436       } else if (rm == esp) {
437         byte sib = *(modrmp + 1);
438         int scale, index, base;
439         get_sib(sib, &scale, &index, &base);
440         if (index == esp && base == esp && scale == 0 /*times_1*/) {
441           AppendToBuffer("[%s]", (this->*register_name)(rm));
442           return 2;
443         } else if (base == ebp) {
444           int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
445           AppendToBuffer("[%s*%d%s0x%x]",
446                          (this->*register_name)(index),
447                          1 << scale,
448                          disp < 0 ? "-" : "+",
449                          disp < 0 ? -disp : disp);
450           return 6;
451         } else if (index != esp && base != ebp) {
452           // [base+index*scale]
453           AppendToBuffer("[%s+%s*%d]",
454                          (this->*register_name)(base),
455                          (this->*register_name)(index),
456                          1 << scale);
457           return 2;
458         } else {
459           UnimplementedInstruction();
460           return 1;
461         }
462       } else {
463         AppendToBuffer("[%s]", (this->*register_name)(rm));
464         return 1;
465       }
466       break;
467     case 1:  // fall through
468     case 2:
469       if (rm == esp) {
470         byte sib = *(modrmp + 1);
471         int scale, index, base;
472         get_sib(sib, &scale, &index, &base);
473         int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
474                             : *reinterpret_cast<int8_t*>(modrmp + 2);
475         if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
476           AppendToBuffer("[%s%s0x%x]",
477                          (this->*register_name)(rm),
478                          disp < 0 ? "-" : "+",
479                          disp < 0 ? -disp : disp);
480         } else {
481           AppendToBuffer("[%s+%s*%d%s0x%x]",
482                          (this->*register_name)(base),
483                          (this->*register_name)(index),
484                          1 << scale,
485                          disp < 0 ? "-" : "+",
486                          disp < 0 ? -disp : disp);
487         }
488         return mod == 2 ? 6 : 3;
489       } else {
490         // No sib.
491         int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
492                             : *reinterpret_cast<int8_t*>(modrmp + 1);
493         AppendToBuffer("[%s%s0x%x]",
494                        (this->*register_name)(rm),
495                        disp < 0 ? "-" : "+",
496                        disp < 0 ? -disp : disp);
497         return mod == 2 ? 5 : 2;
498       }
499       break;
500     case 3:
501       AppendToBuffer("%s", (this->*register_name)(rm));
502       return 1;
503     default:
504       UnimplementedInstruction();
505       return 1;
506   }
507   UNREACHABLE();
508 }
509
510
511 int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
512   return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
513 }
514
515
516 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
517   return PrintRightOperandHelper(modrmp,
518                                  &DisassemblerIA32::NameOfByteCPURegister);
519 }
520
521
522 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
523   return PrintRightOperandHelper(modrmp,
524                                  &DisassemblerIA32::NameOfXMMRegister);
525 }
526
527
528 // Returns number of bytes used including the current *data.
529 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
530 int DisassemblerIA32::PrintOperands(const char* mnem,
531                                     OperandOrder op_order,
532                                     byte* data) {
533   byte modrm = *data;
534   int mod, regop, rm;
535   get_modrm(modrm, &mod, &regop, &rm);
536   int advance = 0;
537   switch (op_order) {
538     case REG_OPER_OP_ORDER: {
539       AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
540       advance = PrintRightOperand(data);
541       break;
542     }
543     case OPER_REG_OP_ORDER: {
544       AppendToBuffer("%s ", mnem);
545       advance = PrintRightOperand(data);
546       AppendToBuffer(",%s", NameOfCPURegister(regop));
547       break;
548     }
549     default:
550       UNREACHABLE();
551       break;
552   }
553   return advance;
554 }
555
556
557 // Returns number of bytes used by machine instruction, including *data byte.
558 // Writes immediate instructions to 'tmp_buffer_'.
559 int DisassemblerIA32::PrintImmediateOp(byte* data) {
560   bool sign_extension_bit = (*data & 0x02) != 0;
561   byte modrm = *(data+1);
562   int mod, regop, rm;
563   get_modrm(modrm, &mod, &regop, &rm);
564   const char* mnem = "Imm???";
565   switch (regop) {
566     case 0: mnem = "add"; break;
567     case 1: mnem = "or"; break;
568     case 2: mnem = "adc"; break;
569     case 4: mnem = "and"; break;
570     case 5: mnem = "sub"; break;
571     case 6: mnem = "xor"; break;
572     case 7: mnem = "cmp"; break;
573     default: UnimplementedInstruction();
574   }
575   AppendToBuffer("%s ", mnem);
576   int count = PrintRightOperand(data+1);
577   if (sign_extension_bit) {
578     AppendToBuffer(",0x%x", *(data + 1 + count));
579     return 1 + count + 1 /*int8*/;
580   } else {
581     AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
582     return 1 + count + 4 /*int32_t*/;
583   }
584 }
585
586
587 // Returns number of bytes used, including *data.
588 int DisassemblerIA32::F7Instruction(byte* data) {
589   DCHECK_EQ(0xF7, *data);
590   byte modrm = *++data;
591   int mod, regop, rm;
592   get_modrm(modrm, &mod, &regop, &rm);
593   const char* mnem = NULL;
594   switch (regop) {
595     case 0:
596       mnem = "test";
597       break;
598     case 2:
599       mnem = "not";
600       break;
601     case 3:
602       mnem = "neg";
603       break;
604     case 4:
605       mnem = "mul";
606       break;
607     case 5:
608       mnem = "imul";
609       break;
610     case 6:
611       mnem = "div";
612       break;
613     case 7:
614       mnem = "idiv";
615       break;
616     default:
617       UnimplementedInstruction();
618   }
619   AppendToBuffer("%s ", mnem);
620   int count = PrintRightOperand(data);
621   if (regop == 0) {
622     AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
623     count += 4;
624   }
625   return 1 + count;
626 }
627
628
629 int DisassemblerIA32::D1D3C1Instruction(byte* data) {
630   byte op = *data;
631   DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
632   byte modrm = *++data;
633   int mod, regop, rm;
634   get_modrm(modrm, &mod, &regop, &rm);
635   int imm8 = -1;
636   const char* mnem = NULL;
637   switch (regop) {
638     case kROL:
639       mnem = "rol";
640       break;
641     case kROR:
642       mnem = "ror";
643       break;
644     case kRCL:
645       mnem = "rcl";
646       break;
647     case kRCR:
648       mnem = "rcr";
649       break;
650     case kSHL:
651       mnem = "shl";
652       break;
653     case KSHR:
654       mnem = "shr";
655       break;
656     case kSAR:
657       mnem = "sar";
658       break;
659     default:
660       UnimplementedInstruction();
661   }
662   AppendToBuffer("%s ", mnem);
663   int count = PrintRightOperand(data);
664   if (op == 0xD1) {
665     imm8 = 1;
666   } else if (op == 0xC1) {
667     imm8 = *(data + 1);
668     count++;
669   } else if (op == 0xD3) {
670     // Shift/rotate by cl.
671   }
672   if (imm8 >= 0) {
673     AppendToBuffer(",%d", imm8);
674   } else {
675     AppendToBuffer(",cl");
676   }
677   return 1 + count;
678 }
679
680
681 // Returns number of bytes used, including *data.
682 int DisassemblerIA32::JumpShort(byte* data) {
683   DCHECK_EQ(0xEB, *data);
684   byte b = *(data+1);
685   byte* dest = data + static_cast<int8_t>(b) + 2;
686   AppendToBuffer("jmp %s", NameOfAddress(dest));
687   return 2;
688 }
689
690
691 // Returns number of bytes used, including *data.
692 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
693   DCHECK_EQ(0x0F, *data);
694   byte cond = *(data+1) & 0x0F;
695   byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
696   const char* mnem = jump_conditional_mnem[cond];
697   AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
698   if (comment != NULL) {
699     AppendToBuffer(", %s", comment);
700   }
701   return 6;  // includes 0x0F
702 }
703
704
705 // Returns number of bytes used, including *data.
706 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
707   byte cond = *data & 0x0F;
708   byte b = *(data+1);
709   byte* dest = data + static_cast<int8_t>(b) + 2;
710   const char* mnem = jump_conditional_mnem[cond];
711   AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
712   if (comment != NULL) {
713     AppendToBuffer(", %s", comment);
714   }
715   return 2;
716 }
717
718
719 // Returns number of bytes used, including *data.
720 int DisassemblerIA32::SetCC(byte* data) {
721   DCHECK_EQ(0x0F, *data);
722   byte cond = *(data+1) & 0x0F;
723   const char* mnem = set_conditional_mnem[cond];
724   AppendToBuffer("%s ", mnem);
725   PrintRightByteOperand(data+2);
726   return 3;  // Includes 0x0F.
727 }
728
729
730 // Returns number of bytes used, including *data.
731 int DisassemblerIA32::CMov(byte* data) {
732   DCHECK_EQ(0x0F, *data);
733   byte cond = *(data + 1) & 0x0F;
734   const char* mnem = conditional_move_mnem[cond];
735   int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
736   return 2 + op_size;  // includes 0x0F
737 }
738
739
740 int DisassemblerIA32::AVXInstruction(byte* data) {
741   byte opcode = *data;
742   byte* current = data + 1;
743   if (vex_66() && vex_0f38()) {
744     int mod, regop, rm, vvvv = vex_vreg();
745     get_modrm(*current, &mod, &regop, &rm);
746     switch (opcode) {
747       case 0x99:
748         AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
749                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
750         current += PrintRightXMMOperand(current);
751         break;
752       case 0xa9:
753         AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
754                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
755         current += PrintRightXMMOperand(current);
756         break;
757       case 0xb9:
758         AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
759                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
760         current += PrintRightXMMOperand(current);
761         break;
762       case 0x9b:
763         AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
764                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
765         current += PrintRightXMMOperand(current);
766         break;
767       case 0xab:
768         AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
769                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
770         current += PrintRightXMMOperand(current);
771         break;
772       case 0xbb:
773         AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
774                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
775         current += PrintRightXMMOperand(current);
776         break;
777       case 0x9d:
778         AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
779                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
780         current += PrintRightXMMOperand(current);
781         break;
782       case 0xad:
783         AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
784                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
785         current += PrintRightXMMOperand(current);
786         break;
787       case 0xbd:
788         AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
789                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
790         current += PrintRightXMMOperand(current);
791         break;
792       case 0x9f:
793         AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
794                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
795         current += PrintRightXMMOperand(current);
796         break;
797       case 0xaf:
798         AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
799                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
800         current += PrintRightXMMOperand(current);
801         break;
802       case 0xbf:
803         AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
804                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
805         current += PrintRightXMMOperand(current);
806         break;
807       default:
808         UnimplementedInstruction();
809     }
810   } else if (vex_f2() && vex_0f()) {
811     int mod, regop, rm, vvvv = vex_vreg();
812     get_modrm(*current, &mod, &regop, &rm);
813     switch (opcode) {
814       case 0x58:
815         AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
816                        NameOfXMMRegister(vvvv));
817         current += PrintRightXMMOperand(current);
818         break;
819       case 0x59:
820         AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
821                        NameOfXMMRegister(vvvv));
822         current += PrintRightXMMOperand(current);
823         break;
824       case 0x5c:
825         AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
826                        NameOfXMMRegister(vvvv));
827         current += PrintRightXMMOperand(current);
828         break;
829       case 0x5d:
830         AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
831                        NameOfXMMRegister(vvvv));
832         current += PrintRightXMMOperand(current);
833         break;
834       case 0x5e:
835         AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
836                        NameOfXMMRegister(vvvv));
837         current += PrintRightXMMOperand(current);
838         break;
839       case 0x5f:
840         AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
841                        NameOfXMMRegister(vvvv));
842         current += PrintRightXMMOperand(current);
843         break;
844       default:
845         UnimplementedInstruction();
846     }
847   } else {
848     UnimplementedInstruction();
849   }
850
851   return static_cast<int>(current - data);
852 }
853
854
855 // Returns number of bytes used, including *data.
856 int DisassemblerIA32::FPUInstruction(byte* data) {
857   byte escape_opcode = *data;
858   DCHECK_EQ(0xD8, escape_opcode & 0xF8);
859   byte modrm_byte = *(data+1);
860
861   if (modrm_byte >= 0xC0) {
862     return RegisterFPUInstruction(escape_opcode, modrm_byte);
863   } else {
864     return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
865   }
866 }
867
868 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
869                                            int modrm_byte,
870                                            byte* modrm_start) {
871   const char* mnem = "?";
872   int regop = (modrm_byte >> 3) & 0x7;  // reg/op field of modrm byte.
873   switch (escape_opcode) {
874     case 0xD9: switch (regop) {
875         case 0: mnem = "fld_s"; break;
876         case 2: mnem = "fst_s"; break;
877         case 3: mnem = "fstp_s"; break;
878         case 7: mnem = "fstcw"; break;
879         default: UnimplementedInstruction();
880       }
881       break;
882
883     case 0xDB: switch (regop) {
884         case 0: mnem = "fild_s"; break;
885         case 1: mnem = "fisttp_s"; break;
886         case 2: mnem = "fist_s"; break;
887         case 3: mnem = "fistp_s"; break;
888         default: UnimplementedInstruction();
889       }
890       break;
891
892     case 0xDD: switch (regop) {
893         case 0: mnem = "fld_d"; break;
894         case 1: mnem = "fisttp_d"; break;
895         case 2: mnem = "fst_d"; break;
896         case 3: mnem = "fstp_d"; break;
897         default: UnimplementedInstruction();
898       }
899       break;
900
901     case 0xDF: switch (regop) {
902         case 5: mnem = "fild_d"; break;
903         case 7: mnem = "fistp_d"; break;
904         default: UnimplementedInstruction();
905       }
906       break;
907
908     default: UnimplementedInstruction();
909   }
910   AppendToBuffer("%s ", mnem);
911   int count = PrintRightOperand(modrm_start);
912   return count + 1;
913 }
914
915 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
916                                              byte modrm_byte) {
917   bool has_register = false;  // Is the FPU register encoded in modrm_byte?
918   const char* mnem = "?";
919
920   switch (escape_opcode) {
921     case 0xD8:
922       has_register = true;
923       switch (modrm_byte & 0xF8) {
924         case 0xC0: mnem = "fadd_i"; break;
925         case 0xE0: mnem = "fsub_i"; break;
926         case 0xC8: mnem = "fmul_i"; break;
927         case 0xF0: mnem = "fdiv_i"; break;
928         default: UnimplementedInstruction();
929       }
930       break;
931
932     case 0xD9:
933       switch (modrm_byte & 0xF8) {
934         case 0xC0:
935           mnem = "fld";
936           has_register = true;
937           break;
938         case 0xC8:
939           mnem = "fxch";
940           has_register = true;
941           break;
942         default:
943           switch (modrm_byte) {
944             case 0xE0: mnem = "fchs"; break;
945             case 0xE1: mnem = "fabs"; break;
946             case 0xE4: mnem = "ftst"; break;
947             case 0xE8: mnem = "fld1"; break;
948             case 0xEB: mnem = "fldpi"; break;
949             case 0xED: mnem = "fldln2"; break;
950             case 0xEE: mnem = "fldz"; break;
951             case 0xF0: mnem = "f2xm1"; break;
952             case 0xF1: mnem = "fyl2x"; break;
953             case 0xF4: mnem = "fxtract"; break;
954             case 0xF5: mnem = "fprem1"; break;
955             case 0xF7: mnem = "fincstp"; break;
956             case 0xF8: mnem = "fprem"; break;
957             case 0xFC: mnem = "frndint"; break;
958             case 0xFD: mnem = "fscale"; break;
959             case 0xFE: mnem = "fsin"; break;
960             case 0xFF: mnem = "fcos"; break;
961             default: UnimplementedInstruction();
962           }
963       }
964       break;
965
966     case 0xDA:
967       if (modrm_byte == 0xE9) {
968         mnem = "fucompp";
969       } else {
970         UnimplementedInstruction();
971       }
972       break;
973
974     case 0xDB:
975       if ((modrm_byte & 0xF8) == 0xE8) {
976         mnem = "fucomi";
977         has_register = true;
978       } else if (modrm_byte  == 0xE2) {
979         mnem = "fclex";
980       } else if (modrm_byte == 0xE3) {
981         mnem = "fninit";
982       } else {
983         UnimplementedInstruction();
984       }
985       break;
986
987     case 0xDC:
988       has_register = true;
989       switch (modrm_byte & 0xF8) {
990         case 0xC0: mnem = "fadd"; break;
991         case 0xE8: mnem = "fsub"; break;
992         case 0xC8: mnem = "fmul"; break;
993         case 0xF8: mnem = "fdiv"; break;
994         default: UnimplementedInstruction();
995       }
996       break;
997
998     case 0xDD:
999       has_register = true;
1000       switch (modrm_byte & 0xF8) {
1001         case 0xC0: mnem = "ffree"; break;
1002         case 0xD0: mnem = "fst"; break;
1003         case 0xD8: mnem = "fstp"; break;
1004         default: UnimplementedInstruction();
1005       }
1006       break;
1007
1008     case 0xDE:
1009       if (modrm_byte  == 0xD9) {
1010         mnem = "fcompp";
1011       } else {
1012         has_register = true;
1013         switch (modrm_byte & 0xF8) {
1014           case 0xC0: mnem = "faddp"; break;
1015           case 0xE8: mnem = "fsubp"; break;
1016           case 0xC8: mnem = "fmulp"; break;
1017           case 0xF8: mnem = "fdivp"; break;
1018           default: UnimplementedInstruction();
1019         }
1020       }
1021       break;
1022
1023     case 0xDF:
1024       if (modrm_byte == 0xE0) {
1025         mnem = "fnstsw_ax";
1026       } else if ((modrm_byte & 0xF8) == 0xE8) {
1027         mnem = "fucomip";
1028         has_register = true;
1029       }
1030       break;
1031
1032     default: UnimplementedInstruction();
1033   }
1034
1035   if (has_register) {
1036     AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1037   } else {
1038     AppendToBuffer("%s", mnem);
1039   }
1040   return 2;
1041 }
1042
1043
1044 // Mnemonics for instructions 0xF0 byte.
1045 // Returns NULL if the instruction is not handled here.
1046 static const char* F0Mnem(byte f0byte) {
1047   switch (f0byte) {
1048     case 0x0B:
1049       return "ud2";
1050     case 0x18: return "prefetch";
1051     case 0xA2: return "cpuid";
1052     case 0xBE: return "movsx_b";
1053     case 0xBF: return "movsx_w";
1054     case 0xB6: return "movzx_b";
1055     case 0xB7: return "movzx_w";
1056     case 0xAF: return "imul";
1057     case 0xA5: return "shld";
1058     case 0xAD: return "shrd";
1059     case 0xAC: return "shrd";  // 3-operand version.
1060     case 0xAB: return "bts";
1061     case 0xBD: return "bsr";
1062     default: return NULL;
1063   }
1064 }
1065
1066
1067 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
1068 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
1069                                         byte* instr) {
1070   tmp_buffer_pos_ = 0;  // starting to write as position 0
1071   byte* data = instr;
1072   // Check for hints.
1073   const char* branch_hint = NULL;
1074   // We use these two prefixes only with branch prediction
1075   if (*data == 0x3E /*ds*/) {
1076     branch_hint = "predicted taken";
1077     data++;
1078   } else if (*data == 0x2E /*cs*/) {
1079     branch_hint = "predicted not taken";
1080     data++;
1081   } else if (*data == 0xC4 && *(data + 1) >= 0xc0) {
1082     vex_byte0_ = *data;
1083     vex_byte1_ = *(data + 1);
1084     vex_byte2_ = *(data + 2);
1085     data += 3;
1086   } else if (*data == 0xC5 && *(data + 1) >= 0xc0) {
1087     vex_byte0_ = *data;
1088     vex_byte1_ = *(data + 1);
1089     data += 2;
1090   }
1091
1092   bool processed = true;  // Will be set to false if the current instruction
1093                           // is not in 'instructions' table.
1094   // Decode AVX instructions.
1095   if (vex_byte0_ != 0) {
1096     data += AVXInstruction(data);
1097   } else {
1098     const InstructionDesc& idesc = instruction_table_->Get(*data);
1099     switch (idesc.type) {
1100       case ZERO_OPERANDS_INSTR:
1101         AppendToBuffer(idesc.mnem);
1102         data++;
1103         break;
1104
1105       case TWO_OPERANDS_INSTR:
1106         data++;
1107         data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1108         break;
1109
1110       case JUMP_CONDITIONAL_SHORT_INSTR:
1111         data += JumpConditionalShort(data, branch_hint);
1112         break;
1113
1114       case REGISTER_INSTR:
1115         AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1116         data++;
1117         break;
1118
1119       case MOVE_REG_INSTR: {
1120         byte* addr =
1121             reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1122         AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1123                        NameOfAddress(addr));
1124         data += 5;
1125         break;
1126       }
1127
1128       case CALL_JUMP_INSTR: {
1129         byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1130         AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1131         data += 5;
1132         break;
1133       }
1134
1135       case SHORT_IMMEDIATE_INSTR: {
1136         byte* addr =
1137             reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1138         AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1139         data += 5;
1140         break;
1141       }
1142
1143       case BYTE_IMMEDIATE_INSTR: {
1144         AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1145         data += 2;
1146         break;
1147       }
1148
1149       case NO_INSTR:
1150         processed = false;
1151         break;
1152
1153       default:
1154         UNIMPLEMENTED();  // This type is not implemented.
1155     }
1156   }
1157   //----------------------------
1158   if (!processed) {
1159     switch (*data) {
1160       case 0xC2:
1161         AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
1162         data += 3;
1163         break;
1164
1165       case 0x6B: {
1166         data++;
1167         data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1168         AppendToBuffer(",%d", *data);
1169         data++;
1170       } break;
1171
1172       case 0x69: {
1173         data++;
1174         data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1175         AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
1176         data += 4;
1177         }
1178         break;
1179
1180       case 0xF6:
1181         { data++;
1182           int mod, regop, rm;
1183           get_modrm(*data, &mod, &regop, &rm);
1184           if (regop == eax) {
1185             AppendToBuffer("test_b ");
1186             data += PrintRightByteOperand(data);
1187             int32_t imm = *data;
1188             AppendToBuffer(",0x%x", imm);
1189             data++;
1190           } else {
1191             UnimplementedInstruction();
1192           }
1193         }
1194         break;
1195
1196       case 0x81:  // fall through
1197       case 0x83:  // 0x81 with sign extension bit set
1198         data += PrintImmediateOp(data);
1199         break;
1200
1201       case 0x0F:
1202         { byte f0byte = data[1];
1203           const char* f0mnem = F0Mnem(f0byte);
1204           if (f0byte == 0x18) {
1205             data += 2;
1206             int mod, regop, rm;
1207             get_modrm(*data, &mod, &regop, &rm);
1208             const char* suffix[] = {"nta", "1", "2", "3"};
1209             AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1210             data += PrintRightOperand(data);
1211           } else if (f0byte == 0x1F && data[2] == 0) {
1212             AppendToBuffer("nop");  // 3 byte nop.
1213             data += 3;
1214           } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1215             AppendToBuffer("nop");  // 4 byte nop.
1216             data += 4;
1217           } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1218                      data[4] == 0) {
1219             AppendToBuffer("nop");  // 5 byte nop.
1220             data += 5;
1221           } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1222                      data[4] == 0 && data[5] == 0 && data[6] == 0) {
1223             AppendToBuffer("nop");  // 7 byte nop.
1224             data += 7;
1225           } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1226                      data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1227                      data[7] == 0) {
1228             AppendToBuffer("nop");  // 8 byte nop.
1229             data += 8;
1230           } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
1231             AppendToBuffer("%s", f0mnem);
1232             data += 2;
1233           } else if (f0byte == 0x28) {
1234             data += 2;
1235             int mod, regop, rm;
1236             get_modrm(*data, &mod, &regop, &rm);
1237             AppendToBuffer("movaps %s,%s",
1238                            NameOfXMMRegister(regop),
1239                            NameOfXMMRegister(rm));
1240             data++;
1241           } else if (f0byte == 0x2e) {
1242             data += 2;
1243             int mod, regop, rm;
1244             get_modrm(*data, &mod, &regop, &rm);
1245             AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1246             data += PrintRightXMMOperand(data);
1247           } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1248             const char* const pseudo_op[] = {
1249               "rcpps",
1250               "andps",
1251               "andnps",
1252               "orps",
1253               "xorps",
1254               "addps",
1255               "mulps",
1256               "cvtps2pd",
1257               "cvtdq2ps",
1258               "subps",
1259               "minps",
1260               "divps",
1261               "maxps",
1262             };
1263
1264             data += 2;
1265             int mod, regop, rm;
1266             get_modrm(*data, &mod, &regop, &rm);
1267             AppendToBuffer("%s %s,",
1268                            pseudo_op[f0byte - 0x53],
1269                            NameOfXMMRegister(regop));
1270             data += PrintRightXMMOperand(data);
1271           } else if (f0byte == 0x50) {
1272             data += 2;
1273             int mod, regop, rm;
1274             get_modrm(*data, &mod, &regop, &rm);
1275             AppendToBuffer("movmskps %s,%s",
1276                            NameOfCPURegister(regop),
1277                            NameOfXMMRegister(rm));
1278             data++;
1279           } else if (f0byte== 0xC6) {
1280             // shufps xmm, xmm/m128, imm8
1281             data += 2;
1282             int mod, regop, rm;
1283             get_modrm(*data, &mod, &regop, &rm);
1284             int8_t imm8 = static_cast<int8_t>(data[1]);
1285             AppendToBuffer("shufps %s,%s,%d",
1286                             NameOfXMMRegister(rm),
1287                             NameOfXMMRegister(regop),
1288                             static_cast<int>(imm8));
1289             data += 2;
1290           } else if ((f0byte & 0xF0) == 0x80) {
1291             data += JumpConditional(data, branch_hint);
1292           } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1293                      f0byte == 0xB7 || f0byte == 0xAF) {
1294             data += 2;
1295             data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1296           } else if ((f0byte & 0xF0) == 0x90) {
1297             data += SetCC(data);
1298           } else if ((f0byte & 0xF0) == 0x40) {
1299             data += CMov(data);
1300           } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1301             // shrd, shld, bts
1302             data += 2;
1303             AppendToBuffer("%s ", f0mnem);
1304             int mod, regop, rm;
1305             get_modrm(*data, &mod, &regop, &rm);
1306             data += PrintRightOperand(data);
1307             if (f0byte == 0xAB) {
1308               AppendToBuffer(",%s", NameOfCPURegister(regop));
1309             } else {
1310               AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1311             }
1312           } else if (f0byte == 0xBD) {
1313             data += 2;
1314             int mod, regop, rm;
1315             get_modrm(*data, &mod, &regop, &rm);
1316             AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1317             data += PrintRightOperand(data);
1318           } else {
1319             UnimplementedInstruction();
1320           }
1321         }
1322         break;
1323
1324       case 0x8F:
1325         { data++;
1326           int mod, regop, rm;
1327           get_modrm(*data, &mod, &regop, &rm);
1328           if (regop == eax) {
1329             AppendToBuffer("pop ");
1330             data += PrintRightOperand(data);
1331           }
1332         }
1333         break;
1334
1335       case 0xFF:
1336         { data++;
1337           int mod, regop, rm;
1338           get_modrm(*data, &mod, &regop, &rm);
1339           const char* mnem = NULL;
1340           switch (regop) {
1341             case esi: mnem = "push"; break;
1342             case eax: mnem = "inc"; break;
1343             case ecx: mnem = "dec"; break;
1344             case edx: mnem = "call"; break;
1345             case esp: mnem = "jmp"; break;
1346             default: mnem = "???";
1347           }
1348           AppendToBuffer("%s ", mnem);
1349           data += PrintRightOperand(data);
1350         }
1351         break;
1352
1353       case 0xC7:  // imm32, fall through
1354       case 0xC6:  // imm8
1355         { bool is_byte = *data == 0xC6;
1356           data++;
1357           if (is_byte) {
1358             AppendToBuffer("%s ", "mov_b");
1359             data += PrintRightByteOperand(data);
1360             int32_t imm = *data;
1361             AppendToBuffer(",0x%x", imm);
1362             data++;
1363           } else {
1364             AppendToBuffer("%s ", "mov");
1365             data += PrintRightOperand(data);
1366             int32_t imm = *reinterpret_cast<int32_t*>(data);
1367             AppendToBuffer(",0x%x", imm);
1368             data += 4;
1369           }
1370         }
1371         break;
1372
1373       case 0x80:
1374         { data++;
1375           int mod, regop, rm;
1376           get_modrm(*data, &mod, &regop, &rm);
1377           const char* mnem = NULL;
1378           switch (regop) {
1379             case 5:  mnem = "subb"; break;
1380             case 7:  mnem = "cmpb"; break;
1381             default: UnimplementedInstruction();
1382           }
1383           AppendToBuffer("%s ", mnem);
1384           data += PrintRightByteOperand(data);
1385           int32_t imm = *data;
1386           AppendToBuffer(",0x%x", imm);
1387           data++;
1388         }
1389         break;
1390
1391       case 0x88:  // 8bit, fall through
1392       case 0x89:  // 32bit
1393         { bool is_byte = *data == 0x88;
1394           int mod, regop, rm;
1395           data++;
1396           get_modrm(*data, &mod, &regop, &rm);
1397           if (is_byte) {
1398             AppendToBuffer("%s ", "mov_b");
1399             data += PrintRightByteOperand(data);
1400             AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1401           } else {
1402             AppendToBuffer("%s ", "mov");
1403             data += PrintRightOperand(data);
1404             AppendToBuffer(",%s", NameOfCPURegister(regop));
1405           }
1406         }
1407         break;
1408
1409       case 0x66:  // prefix
1410         while (*data == 0x66) data++;
1411         if (*data == 0xf && data[1] == 0x1f) {
1412           AppendToBuffer("nop");  // 0x66 prefix
1413         } else if (*data == 0x90) {
1414           AppendToBuffer("nop");  // 0x66 prefix
1415         } else if (*data == 0x8B) {
1416           data++;
1417           data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1418         } else if (*data == 0x89) {
1419           data++;
1420           int mod, regop, rm;
1421           get_modrm(*data, &mod, &regop, &rm);
1422           AppendToBuffer("mov_w ");
1423           data += PrintRightOperand(data);
1424           AppendToBuffer(",%s", NameOfCPURegister(regop));
1425         } else if (*data == 0xC7) {
1426           data++;
1427           AppendToBuffer("%s ", "mov_w");
1428           data += PrintRightOperand(data);
1429           int imm = *reinterpret_cast<int16_t*>(data);
1430           AppendToBuffer(",0x%x", imm);
1431           data += 2;
1432         } else if (*data == 0x0F) {
1433           data++;
1434           if (*data == 0x38) {
1435             data++;
1436             if (*data == 0x17) {
1437               data++;
1438               int mod, regop, rm;
1439               get_modrm(*data, &mod, &regop, &rm);
1440               AppendToBuffer("ptest %s,%s",
1441                              NameOfXMMRegister(regop),
1442                              NameOfXMMRegister(rm));
1443               data++;
1444             } else if (*data == 0x2A) {
1445               // movntdqa
1446               data++;
1447               int mod, regop, rm;
1448               get_modrm(*data, &mod, &regop, &rm);
1449               AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1450               data += PrintRightOperand(data);
1451             } else {
1452               UnimplementedInstruction();
1453             }
1454           } else if (*data == 0x3A) {
1455             data++;
1456             if (*data == 0x0B) {
1457               data++;
1458               int mod, regop, rm;
1459               get_modrm(*data, &mod, &regop, &rm);
1460               int8_t imm8 = static_cast<int8_t>(data[1]);
1461               AppendToBuffer("roundsd %s,%s,%d",
1462                              NameOfXMMRegister(regop),
1463                              NameOfXMMRegister(rm),
1464                              static_cast<int>(imm8));
1465               data += 2;
1466             } else if (*data == 0x16) {
1467               data++;
1468               int mod, regop, rm;
1469               get_modrm(*data, &mod, &regop, &rm);
1470               int8_t imm8 = static_cast<int8_t>(data[1]);
1471               AppendToBuffer("pextrd %s,%s,%d",
1472                              NameOfCPURegister(regop),
1473                              NameOfXMMRegister(rm),
1474                              static_cast<int>(imm8));
1475               data += 2;
1476             } else if (*data == 0x17) {
1477               data++;
1478               int mod, regop, rm;
1479               get_modrm(*data, &mod, &regop, &rm);
1480               int8_t imm8 = static_cast<int8_t>(data[1]);
1481               AppendToBuffer("extractps %s,%s,%d",
1482                              NameOfCPURegister(rm),
1483                              NameOfXMMRegister(regop),
1484                              static_cast<int>(imm8));
1485               data += 2;
1486             } else if (*data == 0x22) {
1487               data++;
1488               int mod, regop, rm;
1489               get_modrm(*data, &mod, &regop, &rm);
1490               int8_t imm8 = static_cast<int8_t>(data[1]);
1491               AppendToBuffer("pinsrd %s,%s,%d",
1492                              NameOfXMMRegister(regop),
1493                              NameOfCPURegister(rm),
1494                              static_cast<int>(imm8));
1495               data += 2;
1496             } else {
1497               UnimplementedInstruction();
1498             }
1499           } else if (*data == 0x2E || *data == 0x2F) {
1500             const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
1501             data++;
1502             int mod, regop, rm;
1503             get_modrm(*data, &mod, &regop, &rm);
1504             if (mod == 0x3) {
1505               AppendToBuffer("%s %s,%s", mnem,
1506                              NameOfXMMRegister(regop),
1507                              NameOfXMMRegister(rm));
1508               data++;
1509             } else {
1510               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1511               data += PrintRightOperand(data);
1512             }
1513           } else if (*data == 0x50) {
1514             data++;
1515             int mod, regop, rm;
1516             get_modrm(*data, &mod, &regop, &rm);
1517             AppendToBuffer("movmskpd %s,%s",
1518                            NameOfCPURegister(regop),
1519                            NameOfXMMRegister(rm));
1520             data++;
1521           } else if (*data == 0x54) {
1522             data++;
1523             int mod, regop, rm;
1524             get_modrm(*data, &mod, &regop, &rm);
1525             AppendToBuffer("andpd %s,%s",
1526                            NameOfXMMRegister(regop),
1527                            NameOfXMMRegister(rm));
1528             data++;
1529           } else if (*data == 0x56) {
1530             data++;
1531             int mod, regop, rm;
1532             get_modrm(*data, &mod, &regop, &rm);
1533             AppendToBuffer("orpd %s,%s",
1534                            NameOfXMMRegister(regop),
1535                            NameOfXMMRegister(rm));
1536             data++;
1537           } else if (*data == 0x57) {
1538             data++;
1539             int mod, regop, rm;
1540             get_modrm(*data, &mod, &regop, &rm);
1541             AppendToBuffer("xorpd %s,%s",
1542                            NameOfXMMRegister(regop),
1543                            NameOfXMMRegister(rm));
1544             data++;
1545           } else if (*data == 0x6E) {
1546             data++;
1547             int mod, regop, rm;
1548             get_modrm(*data, &mod, &regop, &rm);
1549             AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1550             data += PrintRightOperand(data);
1551           } else if (*data == 0x6F) {
1552             data++;
1553             int mod, regop, rm;
1554             get_modrm(*data, &mod, &regop, &rm);
1555             AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1556             data += PrintRightXMMOperand(data);
1557           } else if (*data == 0x70) {
1558             data++;
1559             int mod, regop, rm;
1560             get_modrm(*data, &mod, &regop, &rm);
1561             int8_t imm8 = static_cast<int8_t>(data[1]);
1562             AppendToBuffer("pshufd %s,%s,%d",
1563                            NameOfXMMRegister(regop),
1564                            NameOfXMMRegister(rm),
1565                            static_cast<int>(imm8));
1566             data += 2;
1567           } else if (*data == 0x62) {
1568             data++;
1569             int mod, regop, rm;
1570             get_modrm(*data, &mod, &regop, &rm);
1571             AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop),
1572                            NameOfXMMRegister(rm));
1573             data++;
1574           } else if (*data == 0x6A) {
1575             data++;
1576             int mod, regop, rm;
1577             get_modrm(*data, &mod, &regop, &rm);
1578             AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop),
1579                            NameOfXMMRegister(rm));
1580             data++;
1581           } else if (*data == 0x76) {
1582             data++;
1583             int mod, regop, rm;
1584             get_modrm(*data, &mod, &regop, &rm);
1585             AppendToBuffer("pcmpeqd %s,%s",
1586                            NameOfXMMRegister(regop),
1587                            NameOfXMMRegister(rm));
1588             data++;
1589           } else if (*data == 0x90) {
1590             data++;
1591             AppendToBuffer("nop");  // 2 byte nop.
1592           } else if (*data == 0xF3) {
1593             data++;
1594             int mod, regop, rm;
1595             get_modrm(*data, &mod, &regop, &rm);
1596             AppendToBuffer("psllq %s,%s",
1597                            NameOfXMMRegister(regop),
1598                            NameOfXMMRegister(rm));
1599             data++;
1600           } else if (*data == 0x72) {
1601             data++;
1602             int mod, regop, rm;
1603             get_modrm(*data, &mod, &regop, &rm);
1604             int8_t imm8 = static_cast<int8_t>(data[1]);
1605             DCHECK(regop == esi || regop == edx);
1606             AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld",
1607                            NameOfXMMRegister(rm), static_cast<int>(imm8));
1608             data += 2;
1609           } else if (*data == 0x73) {
1610             data++;
1611             int mod, regop, rm;
1612             get_modrm(*data, &mod, &regop, &rm);
1613             int8_t imm8 = static_cast<int8_t>(data[1]);
1614             DCHECK(regop == esi || regop == edx);
1615             AppendToBuffer("%s %s,%d",
1616                            (regop == esi) ? "psllq" : "psrlq",
1617                            NameOfXMMRegister(rm),
1618                            static_cast<int>(imm8));
1619             data += 2;
1620           } else if (*data == 0xD3) {
1621             data++;
1622             int mod, regop, rm;
1623             get_modrm(*data, &mod, &regop, &rm);
1624             AppendToBuffer("psrlq %s,%s",
1625                            NameOfXMMRegister(regop),
1626                            NameOfXMMRegister(rm));
1627             data++;
1628           } else if (*data == 0x7F) {
1629             AppendToBuffer("movdqa ");
1630             data++;
1631             int mod, regop, rm;
1632             get_modrm(*data, &mod, &regop, &rm);
1633             data += PrintRightXMMOperand(data);
1634             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1635           } else if (*data == 0x7E) {
1636             data++;
1637             int mod, regop, rm;
1638             get_modrm(*data, &mod, &regop, &rm);
1639             AppendToBuffer("movd ");
1640             data += PrintRightOperand(data);
1641             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1642           } else if (*data == 0xDB) {
1643             data++;
1644             int mod, regop, rm;
1645             get_modrm(*data, &mod, &regop, &rm);
1646             AppendToBuffer("pand %s,%s",
1647                            NameOfXMMRegister(regop),
1648                            NameOfXMMRegister(rm));
1649             data++;
1650           } else if (*data == 0xE7) {
1651             data++;
1652             int mod, regop, rm;
1653             get_modrm(*data, &mod, &regop, &rm);
1654             if (mod == 3) {
1655               AppendToBuffer("movntdq ");
1656               data += PrintRightOperand(data);
1657               AppendToBuffer(",%s", NameOfXMMRegister(regop));
1658             } else {
1659               UnimplementedInstruction();
1660             }
1661           } else if (*data == 0xEF) {
1662             data++;
1663             int mod, regop, rm;
1664             get_modrm(*data, &mod, &regop, &rm);
1665             AppendToBuffer("pxor %s,%s",
1666                            NameOfXMMRegister(regop),
1667                            NameOfXMMRegister(rm));
1668             data++;
1669           } else if (*data == 0xEB) {
1670             data++;
1671             int mod, regop, rm;
1672             get_modrm(*data, &mod, &regop, &rm);
1673             AppendToBuffer("por %s,%s",
1674                            NameOfXMMRegister(regop),
1675                            NameOfXMMRegister(rm));
1676             data++;
1677           } else {
1678             UnimplementedInstruction();
1679           }
1680         } else {
1681           UnimplementedInstruction();
1682         }
1683         break;
1684
1685       case 0xFE:
1686         { data++;
1687           int mod, regop, rm;
1688           get_modrm(*data, &mod, &regop, &rm);
1689           if (regop == ecx) {
1690             AppendToBuffer("dec_b ");
1691             data += PrintRightOperand(data);
1692           } else {
1693             UnimplementedInstruction();
1694           }
1695         }
1696         break;
1697
1698       case 0x68:
1699         AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1700         data += 5;
1701         break;
1702
1703       case 0x6A:
1704         AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1705         data += 2;
1706         break;
1707
1708       case 0xA8:
1709         AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1710         data += 2;
1711         break;
1712
1713       case 0xA9:
1714         AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1715         data += 5;
1716         break;
1717
1718       case 0xD1:  // fall through
1719       case 0xD3:  // fall through
1720       case 0xC1:
1721         data += D1D3C1Instruction(data);
1722         break;
1723
1724       case 0xD8:  // fall through
1725       case 0xD9:  // fall through
1726       case 0xDA:  // fall through
1727       case 0xDB:  // fall through
1728       case 0xDC:  // fall through
1729       case 0xDD:  // fall through
1730       case 0xDE:  // fall through
1731       case 0xDF:
1732         data += FPUInstruction(data);
1733         break;
1734
1735       case 0xEB:
1736         data += JumpShort(data);
1737         break;
1738
1739       case 0xF2:
1740         if (*(data+1) == 0x0F) {
1741           byte b2 = *(data+2);
1742           if (b2 == 0x11) {
1743             AppendToBuffer("movsd ");
1744             data += 3;
1745             int mod, regop, rm;
1746             get_modrm(*data, &mod, &regop, &rm);
1747             data += PrintRightXMMOperand(data);
1748             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1749           } else if (b2 == 0x10) {
1750             data += 3;
1751             int mod, regop, rm;
1752             get_modrm(*data, &mod, &regop, &rm);
1753             AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1754             data += PrintRightXMMOperand(data);
1755           } else  if (b2 == 0x5A) {
1756             data += 3;
1757             int mod, regop, rm;
1758             get_modrm(*data, &mod, &regop, &rm);
1759             AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1760             data += PrintRightXMMOperand(data);
1761           } else {
1762             const char* mnem = "?";
1763             switch (b2) {
1764               case 0x2A: mnem = "cvtsi2sd"; break;
1765               case 0x2C: mnem = "cvttsd2si"; break;
1766               case 0x2D: mnem = "cvtsd2si"; break;
1767               case 0x51: mnem = "sqrtsd"; break;
1768               case 0x58: mnem = "addsd"; break;
1769               case 0x59: mnem = "mulsd"; break;
1770               case 0x5C: mnem = "subsd"; break;
1771               case 0x5D:
1772                 mnem = "minsd";
1773                 break;
1774               case 0x5E: mnem = "divsd"; break;
1775               case 0x5F:
1776                 mnem = "maxsd";
1777                 break;
1778             }
1779             data += 3;
1780             int mod, regop, rm;
1781             get_modrm(*data, &mod, &regop, &rm);
1782             if (b2 == 0x2A) {
1783               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1784               data += PrintRightOperand(data);
1785             } else if (b2 == 0x2C || b2 == 0x2D) {
1786               AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1787               data += PrintRightXMMOperand(data);
1788             } else if (b2 == 0xC2) {
1789               // Intel manual 2A, Table 3-18.
1790               const char* const pseudo_op[] = {
1791                 "cmpeqsd",
1792                 "cmpltsd",
1793                 "cmplesd",
1794                 "cmpunordsd",
1795                 "cmpneqsd",
1796                 "cmpnltsd",
1797                 "cmpnlesd",
1798                 "cmpordsd"
1799               };
1800               AppendToBuffer("%s %s,%s",
1801                              pseudo_op[data[1]],
1802                              NameOfXMMRegister(regop),
1803                              NameOfXMMRegister(rm));
1804               data += 2;
1805             } else {
1806               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1807               data += PrintRightXMMOperand(data);
1808             }
1809           }
1810         } else {
1811           UnimplementedInstruction();
1812         }
1813         break;
1814
1815       case 0xF3:
1816         if (*(data+1) == 0x0F) {
1817           byte b2 = *(data+2);
1818           if (b2 == 0x11) {
1819             AppendToBuffer("movss ");
1820             data += 3;
1821             int mod, regop, rm;
1822             get_modrm(*data, &mod, &regop, &rm);
1823             data += PrintRightXMMOperand(data);
1824             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1825           } else if (b2 == 0x10) {
1826             data += 3;
1827             int mod, regop, rm;
1828             get_modrm(*data, &mod, &regop, &rm);
1829             AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1830             data += PrintRightXMMOperand(data);
1831           } else if (b2 == 0x2C) {
1832             data += 3;
1833             int mod, regop, rm;
1834             get_modrm(*data, &mod, &regop, &rm);
1835             AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1836             data += PrintRightXMMOperand(data);
1837           } else if (b2 == 0x58) {
1838             data += 3;
1839             int mod, regop, rm;
1840             get_modrm(*data, &mod, &regop, &rm);
1841             AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
1842             data += PrintRightXMMOperand(data);
1843           } else if (b2 == 0x59) {
1844             data += 3;
1845             int mod, regop, rm;
1846             get_modrm(*data, &mod, &regop, &rm);
1847             AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
1848             data += PrintRightXMMOperand(data);
1849           } else if (b2 == 0x5A) {
1850             data += 3;
1851             int mod, regop, rm;
1852             get_modrm(*data, &mod, &regop, &rm);
1853             AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1854             data += PrintRightXMMOperand(data);
1855           } else if (b2 == 0x5c) {
1856             data += 3;
1857             int mod, regop, rm;
1858             get_modrm(*data, &mod, &regop, &rm);
1859             AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
1860             data += PrintRightXMMOperand(data);
1861           } else if (b2 == 0x5e) {
1862             data += 3;
1863             int mod, regop, rm;
1864             get_modrm(*data, &mod, &regop, &rm);
1865             AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
1866             data += PrintRightXMMOperand(data);
1867           } else if (b2 == 0x6F) {
1868             data += 3;
1869             int mod, regop, rm;
1870             get_modrm(*data, &mod, &regop, &rm);
1871             AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1872             data += PrintRightXMMOperand(data);
1873           } else if (b2 == 0x7F) {
1874             AppendToBuffer("movdqu ");
1875             data += 3;
1876             int mod, regop, rm;
1877             get_modrm(*data, &mod, &regop, &rm);
1878             data += PrintRightXMMOperand(data);
1879             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1880           } else {
1881             UnimplementedInstruction();
1882           }
1883         } else if (*(data+1) == 0xA5) {
1884           data += 2;
1885           AppendToBuffer("rep_movs");
1886         } else if (*(data+1) == 0xAB) {
1887           data += 2;
1888           AppendToBuffer("rep_stos");
1889         } else {
1890           UnimplementedInstruction();
1891         }
1892         break;
1893
1894       case 0xF7:
1895         data += F7Instruction(data);
1896         break;
1897
1898       default:
1899         UnimplementedInstruction();
1900     }
1901   }
1902
1903   if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1904     tmp_buffer_[tmp_buffer_pos_] = '\0';
1905   }
1906
1907   int instr_len = data - instr;
1908   if (instr_len == 0) {
1909     printf("%02x", *data);
1910   }
1911   DCHECK(instr_len > 0);  // Ensure progress.
1912
1913   int outp = 0;
1914   // Instruction bytes.
1915   for (byte* bp = instr; bp < data; bp++) {
1916     outp += v8::internal::SNPrintF(out_buffer + outp,
1917                                    "%02x",
1918                                    *bp);
1919   }
1920   for (int i = 6 - instr_len; i >= 0; i--) {
1921     outp += v8::internal::SNPrintF(out_buffer + outp, "  ");
1922   }
1923
1924   outp += v8::internal::SNPrintF(out_buffer + outp,
1925                                  " %s",
1926                                  tmp_buffer_.start());
1927   return instr_len;
1928 }  // NOLINT (function is too long)
1929
1930
1931 //------------------------------------------------------------------------------
1932
1933
1934 static const char* const cpu_regs[8] = {
1935   "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1936 };
1937
1938
1939 static const char* const byte_cpu_regs[8] = {
1940   "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1941 };
1942
1943
1944 static const char* const xmm_regs[8] = {
1945   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1946 };
1947
1948
1949 const char* NameConverter::NameOfAddress(byte* addr) const {
1950   v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1951   return tmp_buffer_.start();
1952 }
1953
1954
1955 const char* NameConverter::NameOfConstant(byte* addr) const {
1956   return NameOfAddress(addr);
1957 }
1958
1959
1960 const char* NameConverter::NameOfCPURegister(int reg) const {
1961   if (0 <= reg && reg < 8) return cpu_regs[reg];
1962   return "noreg";
1963 }
1964
1965
1966 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1967   if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1968   return "noreg";
1969 }
1970
1971
1972 const char* NameConverter::NameOfXMMRegister(int reg) const {
1973   if (0 <= reg && reg < 8) return xmm_regs[reg];
1974   return "noxmmreg";
1975 }
1976
1977
1978 const char* NameConverter::NameInCode(byte* addr) const {
1979   // IA32 does not embed debug strings at the moment.
1980   UNREACHABLE();
1981   return "";
1982 }
1983
1984
1985 //------------------------------------------------------------------------------
1986
1987 Disassembler::Disassembler(const NameConverter& converter)
1988     : converter_(converter) {}
1989
1990
1991 Disassembler::~Disassembler() {}
1992
1993
1994 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1995                                     byte* instruction) {
1996   DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1997   return d.InstructionDecode(buffer, instruction);
1998 }
1999
2000
2001 // The IA-32 assembler does not currently use constant pools.
2002 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
2003
2004
2005 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2006   NameConverter converter;
2007   Disassembler d(converter);
2008   for (byte* pc = begin; pc < end;) {
2009     v8::internal::EmbeddedVector<char, 128> buffer;
2010     buffer[0] = '\0';
2011     byte* prev_pc = pc;
2012     pc += d.InstructionDecode(buffer, pc);
2013     fprintf(f, "%p", prev_pc);
2014     fprintf(f, "    ");
2015
2016     for (byte* bp = prev_pc; bp < pc; bp++) {
2017       fprintf(f, "%02x",  *bp);
2018     }
2019     for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2020       fprintf(f, "  ");
2021     }
2022     fprintf(f, "  %s\n", buffer.start());
2023   }
2024 }
2025
2026
2027 }  // namespace disasm
2028
2029 #endif  // V8_TARGET_ARCH_IA32