disasm-mips.cc 39.4 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7 8 9 10 11 12

// A Disassembler object is used to disassemble a block of code instruction by
// instruction. The default implementation of the NameConverter object can be
// overriden to modify register names or to do symbol lookup on addresses.
//
// The example below will disassemble a block of code and print it to stdout.
//
//   NameConverter converter;
//   Disassembler d(converter);
13
//   for (byte* pc = begin; pc < end;) {
14 15 16
//     v8::internal::EmbeddedVector<char, 256> buffer;
//     byte* prev_pc = pc;
//     pc += d.InstructionDecode(buffer, pc);
17 18 19 20 21 22 23 24 25 26 27
//     printf("%p    %08x      %s\n",
//            prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
//   }
//
// The Disassembler class also has a convenience method to disassemble a block
// of code into a FILE*, meaning that the above functionality could also be
// achieved by just calling Disassembler::Disassemble(stdout, begin, end);


#include <assert.h>
#include <stdarg.h>
28
#include <stdio.h>
29 30
#include <string.h>

31
#include "src/v8.h"
32

33
#if V8_TARGET_ARCH_MIPS
34

35
#include "src/base/platform/platform.h"
36 37
#include "src/disasm.h"
#include "src/macro-assembler.h"
38
#include "src/mips/constants-mips.h"
39

40 41
namespace v8 {
namespace internal {
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

//------------------------------------------------------------------------------

// Decoder decodes and disassembles instructions into an output buffer.
// It uses the converter to convert register names and call destinations into
// more informative description.
class Decoder {
 public:
  Decoder(const disasm::NameConverter& converter,
          v8::internal::Vector<char> out_buffer)
    : converter_(converter),
      out_buffer_(out_buffer),
      out_buffer_pos_(0) {
    out_buffer_[out_buffer_pos_] = '\0';
  }

  ~Decoder() {}

  // Writes one disassembled instruction into 'buffer' (0-terminated).
  // Returns the length of the disassembled machine instruction in bytes.
62
  int InstructionDecode(byte* instruction);
63 64 65 66 67 68 69 70

 private:
  // Bottleneck functions to print into the out_buffer.
  void PrintChar(const char ch);
  void Print(const char* str);

  // Printing of common values.
  void PrintRegister(int reg);
71
  void PrintFPURegister(int freg);
72 73 74 75 76 77 78
  void PrintRs(Instruction* instr);
  void PrintRt(Instruction* instr);
  void PrintRd(Instruction* instr);
  void PrintFs(Instruction* instr);
  void PrintFt(Instruction* instr);
  void PrintFd(Instruction* instr);
  void PrintSa(Instruction* instr);
79
  void PrintSd(Instruction* instr);
80 81
  void PrintSs1(Instruction* instr);
  void PrintSs2(Instruction* instr);
82 83
  void PrintBc(Instruction* instr);
  void PrintCc(Instruction* instr);
84 85 86 87 88
  void PrintFunction(Instruction* instr);
  void PrintSecondaryField(Instruction* instr);
  void PrintUImm16(Instruction* instr);
  void PrintSImm16(Instruction* instr);
  void PrintXImm16(Instruction* instr);
89
  void PrintXImm21(Instruction* instr);
90
  void PrintXImm26(Instruction* instr);
91 92 93 94 95 96
  void PrintCode(Instruction* instr);   // For break and trap instructions.
  // Printing of instruction name.
  void PrintInstructionName(Instruction* instr);

  // Handle formatting of instructions and their options.
  int FormatRegister(Instruction* instr, const char* option);
97
  int FormatFPURegister(Instruction* instr, const char* option);
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
  int FormatOption(Instruction* instr, const char* option);
  void Format(Instruction* instr, const char* format);
  void Unknown(Instruction* instr);

  // Each of these functions decodes one particular instruction type.
  void DecodeTypeRegister(Instruction* instr);
  void DecodeTypeImmediate(Instruction* instr);
  void DecodeTypeJump(Instruction* instr);

  const disasm::NameConverter& converter_;
  v8::internal::Vector<char> out_buffer_;
  int out_buffer_pos_;

  DISALLOW_COPY_AND_ASSIGN(Decoder);
};


// Support for assertions in the Decoder formatting functions.
#define STRING_STARTS_WITH(string, compare_string) \
  (strncmp(string, compare_string, strlen(compare_string)) == 0)


// Append the ch to the output buffer.
void Decoder::PrintChar(const char ch) {
  out_buffer_[out_buffer_pos_++] = ch;
}


// Append the str to the output buffer.
void Decoder::Print(const char* str) {
  char cur = *str++;
  while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
    PrintChar(cur);
    cur = *str++;
  }
  out_buffer_[out_buffer_pos_] = 0;
}


// Print the register name according to the active name converter.
void Decoder::PrintRegister(int reg) {
  Print(converter_.NameOfCPURegister(reg));
}


void Decoder::PrintRs(Instruction* instr) {
144
  int reg = instr->RsValue();
145 146 147 148 149
  PrintRegister(reg);
}


void Decoder::PrintRt(Instruction* instr) {
150
  int reg = instr->RtValue();
151 152 153 154 155
  PrintRegister(reg);
}


void Decoder::PrintRd(Instruction* instr) {
156
  int reg = instr->RdValue();
157 158 159 160
  PrintRegister(reg);
}


161 162 163
// Print the FPUregister name according to the active name converter.
void Decoder::PrintFPURegister(int freg) {
  Print(converter_.NameOfXMMRegister(freg));
164 165 166 167
}


void Decoder::PrintFs(Instruction* instr) {
168 169
  int freg = instr->RsValue();
  PrintFPURegister(freg);
170 171 172 173
}


void Decoder::PrintFt(Instruction* instr) {
174 175
  int freg = instr->RtValue();
  PrintFPURegister(freg);
176 177 178 179
}


void Decoder::PrintFd(Instruction* instr) {
180 181
  int freg = instr->RdValue();
  PrintFPURegister(freg);
182 183 184 185 186
}


// Print the integer value of the sa field.
void Decoder::PrintSa(Instruction* instr) {
187
  int sa = instr->SaValue();
188
  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sa);
189 190 191
}


192
// Print the integer value of the rd field, when it is not used as reg.
193 194
void Decoder::PrintSd(Instruction* instr) {
  int sd = instr->RdValue();
195
  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", sd);
196 197 198
}


199 200 201
// Print the integer value of the rd field, when used as 'ext' size.
void Decoder::PrintSs1(Instruction* instr) {
  int ss = instr->RdValue();
202
  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss + 1);
203 204 205 206 207 208 209 210
}


// Print the integer value of the rd field, when used as 'ins' size.
void Decoder::PrintSs2(Instruction* instr) {
  int ss = instr->RdValue();
  int pos = instr->SaValue();
  out_buffer_pos_ +=
211
      SNPrintF(out_buffer_ + out_buffer_pos_, "%d", ss - pos + 1);
212 213 214
}


215 216 217
// Print the integer value of the cc field for the bc1t/f instructions.
void Decoder::PrintBc(Instruction* instr) {
  int cc = instr->FBccValue();
218
  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", cc);
219 220 221 222 223 224
}


// Print the integer value of the cc field for the FP compare instructions.
void Decoder::PrintCc(Instruction* instr) {
  int cc = instr->FCccValue();
225
  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "cc(%d)", cc);
226 227 228 229 230
}


// Print 16-bit unsigned immediate value.
void Decoder::PrintUImm16(Instruction* instr) {
231
  int32_t imm = instr->Imm16Value();
232
  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
233 234 235 236 237
}


// Print 16-bit signed immediate value.
void Decoder::PrintSImm16(Instruction* instr) {
238
  int32_t imm = ((instr->Imm16Value()) << 16) >> 16;
239
  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
240 241 242 243 244
}


// Print 16-bit hexa immediate value.
void Decoder::PrintXImm16(Instruction* instr) {
245
  int32_t imm = instr->Imm16Value();
246
  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
247 248 249
}


250 251 252 253 254 255 256
// Print 21-bit immediate value.
void Decoder::PrintXImm21(Instruction* instr) {
  uint32_t imm = instr->Imm21Value();
  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}


257
// Print 26-bit immediate value.
258 259
void Decoder::PrintXImm26(Instruction* instr) {
  uint32_t imm = instr->Imm26Value() << kImmFieldShift;
260
  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
261 262 263 264 265 266 267 268 269 270
}


// Print 26-bit immediate value.
void Decoder::PrintCode(Instruction* instr) {
  if (instr->OpcodeFieldRaw() != SPECIAL)
    return;  // Not a break or trap instruction.
  switch (instr->FunctionFieldRaw()) {
    case BREAK: {
      int32_t code = instr->Bits(25, 6);
271 272
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
                                  "0x%05x (%d)", code, code);
273 274 275 276 277 278 279 280 281 282
      break;
                }
    case TGE:
    case TGEU:
    case TLT:
    case TLTU:
    case TEQ:
    case TNE: {
      int32_t code = instr->Bits(15, 6);
      out_buffer_pos_ +=
283
          SNPrintF(out_buffer_ + out_buffer_pos_, "0x%03x", code);
284 285 286 287
      break;
    }
    default:  // Not a break or trap instruction.
    break;
288
  }
289 290 291 292 293 294 295 296 297 298 299
}


// Printing of instruction name.
void Decoder::PrintInstructionName(Instruction* instr) {
}


// Handle all register based formatting in this function to reduce the
// complexity of FormatOption.
int Decoder::FormatRegister(Instruction* instr, const char* format) {
300
  DCHECK(format[0] == 'r');
301
  if (format[1] == 's') {  // 'rs: Rs register.
302
    int reg = instr->RsValue();
303 304
    PrintRegister(reg);
    return 2;
305
  } else if (format[1] == 't') {  // 'rt: rt register.
306
    int reg = instr->RtValue();
307 308
    PrintRegister(reg);
    return 2;
309
  } else if (format[1] == 'd') {  // 'rd: rd register.
310
    int reg = instr->RdValue();
311 312 313 314 315 316 317 318
    PrintRegister(reg);
    return 2;
  }
  UNREACHABLE();
  return -1;
}


319
// Handle all FPUregister based formatting in this function to reduce the
320
// complexity of FormatOption.
321
int Decoder::FormatFPURegister(Instruction* instr, const char* format) {
322
  DCHECK(format[0] == 'f');
323
  if (format[1] == 's') {  // 'fs: fs register.
324 325
    int reg = instr->FsValue();
    PrintFPURegister(reg);
326
    return 2;
327
  } else if (format[1] == 't') {  // 'ft: ft register.
328 329
    int reg = instr->FtValue();
    PrintFPURegister(reg);
330
    return 2;
331
  } else if (format[1] == 'd') {  // 'fd: fd register.
332 333
    int reg = instr->FdValue();
    PrintFPURegister(reg);
334
    return 2;
335 336 337 338
  } else if (format[1] == 'r') {  // 'fr: fr register.
    int reg = instr->FrValue();
    PrintFPURegister(reg);
    return 2;
339 340 341 342 343 344 345 346 347 348 349 350 351
  }
  UNREACHABLE();
  return -1;
}


// FormatOption takes a formatting string and interprets it based on
// the current instructions. The format string points to the first
// character of the option string (the option escape has already been
// consumed by the caller.)  FormatOption returns the number of
// characters that were consumed from the formatting string.
int Decoder::FormatOption(Instruction* instr, const char* format) {
  switch (format[0]) {
352
    case 'c': {   // 'code for break or trap instructions.
353
      DCHECK(STRING_STARTS_WITH(format, "code"));
354 355 356
      PrintCode(instr);
      return 4;
    }
357
    case 'i': {   // 'imm16u or 'imm26.
358
      if (format[3] == '1') {
359
        DCHECK(STRING_STARTS_WITH(format, "imm16"));
360
        if (format[5] == 's') {
361
          DCHECK(STRING_STARTS_WITH(format, "imm16s"));
362 363
          PrintSImm16(instr);
        } else if (format[5] == 'u') {
364
          DCHECK(STRING_STARTS_WITH(format, "imm16u"));
365 366
          PrintSImm16(instr);
        } else {
367
          DCHECK(STRING_STARTS_WITH(format, "imm16x"));
368 369 370
          PrintXImm16(instr);
        }
        return 6;
371 372 373 374 375
      } else if (format[3] == '2' && format[4] == '1') {
        DCHECK(STRING_STARTS_WITH(format, "imm21x"));
        PrintXImm21(instr);
        return 6;
      } else if (format[3] == '2' && format[4] == '6') {
376
        DCHECK(STRING_STARTS_WITH(format, "imm26x"));
377 378
        PrintXImm26(instr);
        return 6;
379 380
      }
    }
381
    case 'r': {   // 'r: registers.
382 383
      return FormatRegister(instr, format);
    }
384
    case 'f': {   // 'f: FPUregisters.
385
      return FormatFPURegister(instr, format);
386
    }
387
    case 's': {   // 'sa.
388 389
      switch (format[1]) {
        case 'a': {
390
          DCHECK(STRING_STARTS_WITH(format, "sa"));
391 392 393 394
          PrintSa(instr);
          return 2;
        }
        case 'd': {
395
          DCHECK(STRING_STARTS_WITH(format, "sd"));
396 397 398
          PrintSd(instr);
          return 2;
        }
399 400
        case 's': {
          if (format[2] == '1') {
401
              DCHECK(STRING_STARTS_WITH(format, "ss1"));  /* ext size */
402 403 404
              PrintSs1(instr);
              return 3;
          } else {
405
              DCHECK(STRING_STARTS_WITH(format, "ss2"));  /* ins size */
406 407 408 409
              PrintSs2(instr);
              return 3;
          }
        }
410 411 412
      }
    }
    case 'b': {   // 'bc - Special for bc1 cc field.
413
      DCHECK(STRING_STARTS_WITH(format, "bc"));
414 415 416 417
      PrintBc(instr);
      return 2;
    }
    case 'C': {   // 'Cc - Special for c.xx.d cc field.
418
      DCHECK(STRING_STARTS_WITH(format, "Cc"));
419
      PrintCc(instr);
420 421
      return 2;
    }
422
  }
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
  UNREACHABLE();
  return -1;
}


// Format takes a formatting string for a whole instruction and prints it into
// the output buffer. All escaped options are handed to FormatOption to be
// parsed further.
void Decoder::Format(Instruction* instr, const char* format) {
  char cur = *format++;
  while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
    if (cur == '\'') {  // Single quote is used as the formatting escape.
      format += FormatOption(instr, format);
    } else {
      out_buffer_[out_buffer_pos_++] = cur;
    }
    cur = *format++;
  }
  out_buffer_[out_buffer_pos_]  = '\0';
}


// For currently unimplemented decodings the disassembler calls Unknown(instr)
// which will just print "unknown" of the instruction bits.
void Decoder::Unknown(Instruction* instr) {
  Format(instr, "unknown");
}


void Decoder::DecodeTypeRegister(Instruction* instr) {
  switch (instr->OpcodeFieldRaw()) {
454
    case COP1:    // Coprocessor instructions.
455
      switch (instr->RsFieldRaw()) {
456
        case BC1:   // bc1 handled in DecodeTypeImmediate.
457 458 459
          UNREACHABLE();
          break;
        case MFC1:
460
          Format(instr, "mfc1    'rt, 'fs");
461 462
          break;
        case MFHC1:
463
          Format(instr, "mfhc1   'rt, 'fs");
464 465
          break;
        case MTC1:
466
          Format(instr, "mtc1    'rt, 'fs");
467 468 469
          break;
        // These are called "fs" too, although they are not FPU registers.
        case CTC1:
470
          Format(instr, "ctc1    'rt, 'fs");
471 472
          break;
        case CFC1:
473
          Format(instr, "cfc1    'rt, 'fs");
474 475
          break;
        case MTHC1:
476
          Format(instr, "mthc1   'rt, 'fs");
477 478
          break;
        case D:
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
          switch (instr->FunctionFieldRaw()) {
            case ADD_D:
              Format(instr, "add.d   'fd, 'fs, 'ft");
              break;
            case SUB_D:
              Format(instr, "sub.d   'fd, 'fs, 'ft");
              break;
            case MUL_D:
              Format(instr, "mul.d   'fd, 'fs, 'ft");
              break;
            case DIV_D:
              Format(instr, "div.d   'fd, 'fs, 'ft");
              break;
            case ABS_D:
              Format(instr, "abs.d   'fd, 'fs");
              break;
            case MOV_D:
              Format(instr, "mov.d   'fd, 'fs");
              break;
            case NEG_D:
              Format(instr, "neg.d   'fd, 'fs");
              break;
            case SQRT_D:
502
              Format(instr, "sqrt.d  'fd, 'fs");
503 504 505 506
              break;
            case CVT_W_D:
              Format(instr, "cvt.w.d 'fd, 'fs");
              break;
507 508
            case CVT_L_D:
              Format(instr, "cvt.l.d 'fd, 'fs");
509 510 511 512
              break;
            case TRUNC_W_D:
              Format(instr, "trunc.w.d 'fd, 'fs");
              break;
513 514
            case TRUNC_L_D:
              Format(instr, "trunc.l.d 'fd, 'fs");
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
              break;
            case ROUND_W_D:
              Format(instr, "round.w.d 'fd, 'fs");
              break;
            case FLOOR_W_D:
              Format(instr, "floor.w.d 'fd, 'fs");
              break;
            case CEIL_W_D:
              Format(instr, "ceil.w.d 'fd, 'fs");
              break;
            case CVT_S_D:
              Format(instr, "cvt.s.d 'fd, 'fs");
              break;
            case C_F_D:
              Format(instr, "c.f.d   'fs, 'ft, 'Cc");
              break;
            case C_UN_D:
              Format(instr, "c.un.d  'fs, 'ft, 'Cc");
              break;
            case C_EQ_D:
              Format(instr, "c.eq.d  'fs, 'ft, 'Cc");
              break;
            case C_UEQ_D:
              Format(instr, "c.ueq.d 'fs, 'ft, 'Cc");
              break;
            case C_OLT_D:
              Format(instr, "c.olt.d 'fs, 'ft, 'Cc");
              break;
            case C_ULT_D:
              Format(instr, "c.ult.d 'fs, 'ft, 'Cc");
              break;
            case C_OLE_D:
              Format(instr, "c.ole.d 'fs, 'ft, 'Cc");
              break;
            case C_ULE_D:
              Format(instr, "c.ule.d 'fs, 'ft, 'Cc");
              break;
            default:
              Format(instr, "unknown.cop1.d");
              break;
          }
          break;
        case S:
558 559 560 561 562 563 564
          switch (instr->FunctionFieldRaw()) {
            case CVT_D_S:
              Format(instr, "cvt.d.s 'fd, 'fs");
              break;
            default:
              UNIMPLEMENTED_MIPS();
          }
565 566 567
          break;
        case W:
          switch (instr->FunctionFieldRaw()) {
568 569
            case CVT_S_W:   // Convert word to float (single).
              Format(instr, "cvt.s.w 'fd, 'fs");
570 571
              break;
            case CVT_D_W:   // Convert word to double.
572
              Format(instr, "cvt.d.w 'fd, 'fs");
573 574 575
              break;
            default:
              UNREACHABLE();
576
          }
577 578
          break;
        case L:
579
          switch (instr->FunctionFieldRaw()) {
580 581
            case CVT_D_L:
              Format(instr, "cvt.d.l 'fd, 'fs");
582
              break;
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
            case CVT_S_L:
              Format(instr, "cvt.s.l 'fd, 'fs");
              break;
            case CMP_UN:
              Format(instr, "cmp.un.d  'fd,  'fs, 'ft");
              break;
            case CMP_EQ:
              Format(instr, "cmp.eq.d  'fd,  'fs, 'ft");
              break;
            case CMP_UEQ:
              Format(instr, "cmp.ueq.d  'fd,  'fs, 'ft");
              break;
            case CMP_LT:
              Format(instr, "cmp.lt.d  'fd,  'fs, 'ft");
              break;
            case CMP_ULT:
              Format(instr, "cmp.ult.d  'fd,  'fs, 'ft");
              break;
            case CMP_LE:
              Format(instr, "cmp.le.d  'fd,  'fs, 'ft");
              break;
            case CMP_ULE:
              Format(instr, "cmp.ule.d  'fd,  'fs, 'ft");
              break;
            case CMP_OR:
              Format(instr, "cmp.or.d  'fd,  'fs, 'ft");
              break;
            case CMP_UNE:
              Format(instr, "cmp.une.d  'fd,  'fs, 'ft");
              break;
            case CMP_NE:
              Format(instr, "cmp.ne.d  'fd,  'fs, 'ft");
615 616 617 618 619
              break;
            default:
              UNREACHABLE();
          }
          break;
620 621 622 623 624
        case PS:
          UNIMPLEMENTED_MIPS();
          break;
        default:
          UNREACHABLE();
625
      }
626
      break;
627 628 629 630 631 632 633
    case COP1X:
      switch (instr->FunctionFieldRaw()) {
        case MADD_D:
          Format(instr, "madd.d  'fd, 'fr, 'fs, 'ft");
          break;
        default:
          UNREACHABLE();
634
      }
635
      break;
636 637 638
    case SPECIAL:
      switch (instr->FunctionFieldRaw()) {
        case JR:
639
          Format(instr, "jr      'rs");
640 641
          break;
        case JALR:
642
          Format(instr, "jalr    'rs");
643 644 645 646 647
          break;
        case SLL:
          if ( 0x0 == static_cast<int>(instr->InstructionBits()))
            Format(instr, "nop");
          else
648
            Format(instr, "sll     'rd, 'rt, 'sa");
649 650
          break;
        case SRL:
651
          if (instr->RsValue() == 0) {
652
            Format(instr, "srl     'rd, 'rt, 'sa");
653
          } else {
654
            if (IsMipsArchVariant(kMips32r2)) {
655
              Format(instr, "rotr    'rd, 'rt, 'sa");
656 657 658 659
            } else {
              Unknown(instr);
            }
          }
660 661
          break;
        case SRA:
662
          Format(instr, "sra     'rd, 'rt, 'sa");
663 664
          break;
        case SLLV:
665
          Format(instr, "sllv    'rd, 'rt, 'rs");
666 667
          break;
        case SRLV:
668
          if (instr->SaValue() == 0) {
669
            Format(instr, "srlv    'rd, 'rt, 'rs");
670
          } else {
671
            if (IsMipsArchVariant(kMips32r2)) {
672
              Format(instr, "rotrv   'rd, 'rt, 'rs");
673 674 675 676
            } else {
              Unknown(instr);
            }
          }
677 678
          break;
        case SRAV:
679
          Format(instr, "srav    'rd, 'rt, 'rs");
680 681
          break;
        case MFHI:
682 683 684 685 686 687 688 689 690 691 692
          if (instr->Bits(25, 16) == 0) {
            Format(instr, "mfhi    'rd");
          } else {
            if ((instr->FunctionFieldRaw() == CLZ_R6)
                && (instr->FdValue() == 1)) {
              Format(instr, "clz     'rd, 'rs");
            } else if ((instr->FunctionFieldRaw() == CLO_R6)
                && (instr->FdValue() == 1)) {
              Format(instr, "clo     'rd, 'rs");
            }
          }
693 694
          break;
        case MFLO:
695
          Format(instr, "mflo    'rd");
696
          break;
697 698 699 700 701 702 703 704 705 706
        case MULT:  // @Mips32r6 == MUL_MUH.
          if (!IsMipsArchVariant(kMips32r6)) {
            Format(instr, "mult    'rs, 'rt");
          } else {
            if (instr->SaValue() == MUL_OP) {
              Format(instr, "mul    'rd, 'rs, 'rt");
            } else {
              Format(instr, "muh    'rd, 'rs, 'rt");
            }
          }
707
          break;
708 709 710 711 712 713 714 715 716 717
        case MULTU:  // @Mips32r6 == MUL_MUH_U.
          if (!IsMipsArchVariant(kMips32r6)) {
            Format(instr, "multu   'rs, 'rt");
          } else {
            if (instr->SaValue() == MUL_OP) {
              Format(instr, "mulu   'rd, 'rs, 'rt");
            } else {
              Format(instr, "muhu   'rd, 'rs, 'rt");
            }
          }
718
          break;
719 720 721 722 723 724 725 726 727 728
        case DIV:  // @Mips32r6 == DIV_MOD.
          if (!IsMipsArchVariant(kMips32r6)) {
            Format(instr, "div     'rs, 'rt");
          } else {
            if (instr->SaValue() == DIV_OP) {
              Format(instr, "div    'rd, 'rs, 'rt");
            } else {
              Format(instr, "mod    'rd, 'rs, 'rt");
            }
          }
729
          break;
730 731 732 733 734 735 736 737 738 739
        case DIVU:  // @Mips32r6 == DIV_MOD_U.
          if (!IsMipsArchVariant(kMips32r6)) {
            Format(instr, "divu    'rs, 'rt");
          } else {
            if (instr->SaValue() == DIV_OP) {
              Format(instr, "divu   'rd, 'rs, 'rt");
            } else {
              Format(instr, "modu   'rd, 'rs, 'rt");
            }
          }
740 741
          break;
        case ADD:
742
          Format(instr, "add     'rd, 'rs, 'rt");
743 744
          break;
        case ADDU:
745
          Format(instr, "addu    'rd, 'rs, 'rt");
746 747
          break;
        case SUB:
748
          Format(instr, "sub     'rd, 'rs, 'rt");
749 750
          break;
        case SUBU:
751
          Format(instr, "subu    'rd, 'rs, 'rt");
752 753
          break;
        case AND:
754
          Format(instr, "and     'rd, 'rs, 'rt");
755 756
          break;
        case OR:
757
          if (0 == instr->RsValue()) {
758
            Format(instr, "mov     'rd, 'rt");
759
          } else if (0 == instr->RtValue()) {
760
            Format(instr, "mov     'rd, 'rs");
761
          } else {
762
            Format(instr, "or      'rd, 'rs, 'rt");
763 764 765
          }
          break;
        case XOR:
766
          Format(instr, "xor     'rd, 'rs, 'rt");
767 768
          break;
        case NOR:
769
          Format(instr, "nor     'rd, 'rs, 'rt");
770 771
          break;
        case SLT:
772
          Format(instr, "slt     'rd, 'rs, 'rt");
773 774
          break;
        case SLTU:
775
          Format(instr, "sltu    'rd, 'rs, 'rt");
776 777 778 779 780
          break;
        case BREAK:
          Format(instr, "break, code: 'code");
          break;
        case TGE:
781
          Format(instr, "tge     'rs, 'rt, code: 'code");
782 783
          break;
        case TGEU:
784
          Format(instr, "tgeu    'rs, 'rt, code: 'code");
785 786
          break;
        case TLT:
787
          Format(instr, "tlt     'rs, 'rt, code: 'code");
788 789
          break;
        case TLTU:
790
          Format(instr, "tltu    'rs, 'rt, code: 'code");
791 792
          break;
        case TEQ:
793
          Format(instr, "teq     'rs, 'rt, code: 'code");
794 795
          break;
        case TNE:
796
          Format(instr, "tne     'rs, 'rt, code: 'code");
797
          break;
798
        case MOVZ:
799
          Format(instr, "movz    'rd, 'rs, 'rt");
800 801
          break;
        case MOVN:
802
          Format(instr, "movn    'rd, 'rs, 'rt");
803 804 805
          break;
        case MOVCI:
          if (instr->Bit(16)) {
806
            Format(instr, "movt    'rd, 'rs, 'bc");
807
          } else {
808
            Format(instr, "movf    'rd, 'rs, 'bc");
809 810
          }
          break;
811 812 813 814 815 816
        case SELEQZ_S:
          Format(instr, "seleqz    'rd, 'rs, 'rt");
          break;
        case SELNEZ_S:
          Format(instr, "selnez    'rd, 'rs, 'rt");
          break;
817 818
        default:
          UNREACHABLE();
819
      }
820 821 822 823
      break;
    case SPECIAL2:
      switch (instr->FunctionFieldRaw()) {
        case MUL:
824
          Format(instr, "mul     'rd, 'rs, 'rt");
825 826
          break;
        case CLZ:
827 828 829
          if (!IsMipsArchVariant(kMips32r6)) {
            Format(instr, "clz     'rd, 'rs");
          }
830 831 832
          break;
        default:
          UNREACHABLE();
833 834 835 836 837
      }
      break;
    case SPECIAL3:
      switch (instr->FunctionFieldRaw()) {
        case INS: {
838
          if (IsMipsArchVariant(kMips32r2)) {
839
            Format(instr, "ins     'rt, 'rs, 'sa, 'ss2");
840 841 842 843 844 845
          } else {
            Unknown(instr);
          }
          break;
        }
        case EXT: {
846
          if (IsMipsArchVariant(kMips32r2)) {
847
            Format(instr, "ext     'rt, 'rs, 'sa, 'ss1");
848 849 850 851 852 853 854 855
          } else {
            Unknown(instr);
          }
          break;
        }
        default:
          UNREACHABLE();
      }
856 857 858
      break;
    default:
      UNREACHABLE();
859
  }
860 861 862 863 864
}


void Decoder::DecodeTypeImmediate(Instruction* instr) {
  switch (instr->OpcodeFieldRaw()) {
865 866 867 868 869 870 871 872 873
    case COP1:
      switch (instr->RsFieldRaw()) {
        case BC1:
          if (instr->FBtrueValue()) {
            Format(instr, "bc1t    'bc, 'imm16u");
          } else {
            Format(instr, "bc1f    'bc, 'imm16u");
          }
          break;
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
        case BC1EQZ:
          Format(instr, "bc1eqz    'ft, 'imm16u");
          break;
        case BC1NEZ:
          Format(instr, "bc1nez    'ft, 'imm16u");
          break;
        case W:  // CMP.S instruction.
          switch (instr->FunctionValue()) {
            case CMP_AF:
              Format(instr, "cmp.af.S    'ft, 'fs, 'fd");
              break;
            case CMP_UN:
              Format(instr, "cmp.un.S    'ft, 'fs, 'fd");
              break;
            case CMP_EQ:
              Format(instr, "cmp.eq.S    'ft, 'fs, 'fd");
              break;
            case CMP_UEQ:
              Format(instr, "cmp.ueq.S   'ft, 'fs, 'fd");
              break;
            case CMP_LT:
              Format(instr, "cmp.lt.S    'ft, 'fs, 'fd");
              break;
            case CMP_ULT:
              Format(instr, "cmp.ult.S   'ft, 'fs, 'fd");
              break;
            case CMP_LE:
              Format(instr, "cmp.le.S    'ft, 'fs, 'fd");
              break;
            case CMP_ULE:
              Format(instr, "cmp.ule.S   'ft, 'fs, 'fd");
              break;
            case CMP_OR:
              Format(instr, "cmp.or.S    'ft, 'fs, 'fd");
              break;
            case CMP_UNE:
              Format(instr, "cmp.une.S   'ft, 'fs, 'fd");
              break;
            case CMP_NE:
              Format(instr, "cmp.ne.S    'ft, 'fs, 'fd");
              break;
            default:
              UNREACHABLE();
          }
          break;
        case L:  // CMP.D instruction.
          switch (instr->FunctionValue()) {
            case CMP_AF:
              Format(instr, "cmp.af.D    'ft, 'fs, 'fd");
              break;
            case CMP_UN:
              Format(instr, "cmp.un.D    'ft, 'fs, 'fd");
              break;
            case CMP_EQ:
              Format(instr, "cmp.eq.D    'ft, 'fs, 'fd");
              break;
            case CMP_UEQ:
              Format(instr, "cmp.ueq.D   'ft, 'fs, 'fd");
              break;
            case CMP_LT:
              Format(instr, "cmp.lt.D    'ft, 'fs, 'fd");
              break;
            case CMP_ULT:
              Format(instr, "cmp.ult.D   'ft, 'fs, 'fd");
              break;
            case CMP_LE:
              Format(instr, "cmp.le.D    'ft, 'fs, 'fd");
              break;
            case CMP_ULE:
              Format(instr, "cmp.ule.D   'ft, 'fs, 'fd");
              break;
            case CMP_OR:
              Format(instr, "cmp.or.D    'ft, 'fs, 'fd");
              break;
            case CMP_UNE:
              Format(instr, "cmp.une.D   'ft, 'fs, 'fd");
              break;
            case CMP_NE:
              Format(instr, "cmp.ne.D    'ft, 'fs, 'fd");
              break;
            default:
              UNREACHABLE();
          }
          break;
        case S:
          switch (instr->FunctionValue()) {
            case SEL:
              Format(instr, "sel.S    'ft, 'fs, 'fd");
              break;
            case SELEQZ_C:
              Format(instr, "seleqz.S 'ft, 'fs, 'fd");
              break;
            case SELNEZ_C:
              Format(instr, "selnez.S 'ft, 'fs, 'fd");
              break;
            case MIN:
              Format(instr, "min.S    'ft, 'fs, 'fd");
              break;
            case MINA:
              Format(instr, "mina.S   'ft, 'fs, 'fd");
              break;
            case MAX:
              Format(instr, "max.S    'ft, 'fs, 'fd");
              break;
            case MAXA:
              Format(instr, "maxa.S   'ft, 'fs, 'fd");
              break;
            default:
              UNREACHABLE();
          }
          break;
        case D:
          switch (instr->FunctionValue()) {
            case SEL:
              Format(instr, "sel.D    'ft, 'fs, 'fd");
              break;
            case SELEQZ_C:
              Format(instr, "seleqz.D 'ft, 'fs, 'fd");
              break;
            case SELNEZ_C:
              Format(instr, "selnez.D 'ft, 'fs, 'fd");
              break;
            case MIN:
              Format(instr, "min.D    'ft, 'fs, 'fd");
              break;
            case MINA:
              Format(instr, "mina.D   'ft, 'fs, 'fd");
              break;
            case MAX:
              Format(instr, "max.D    'ft, 'fs, 'fd");
              break;
            case MAXA:
              Format(instr, "maxa.D   'ft, 'fs, 'fd");
              break;
            default:
              UNREACHABLE();
          }
          break;
1012 1013
        default:
          UNREACHABLE();
1014
      }
1015

1016
      break;  // Case COP1.
1017
    // ------------- REGIMM class.
1018 1019 1020
    case REGIMM:
      switch (instr->RtFieldRaw()) {
        case BLTZ:
1021
          Format(instr, "bltz    'rs, 'imm16u");
1022 1023
          break;
        case BLTZAL:
1024
          Format(instr, "bltzal  'rs, 'imm16u");
1025 1026
          break;
        case BGEZ:
1027
          Format(instr, "bgez    'rs, 'imm16u");
1028 1029
          break;
        case BGEZAL:
1030
          Format(instr, "bgezal  'rs, 'imm16u");
1031
          break;
1032 1033 1034
        case BGEZALL:
          Format(instr, "bgezall 'rs, 'imm16u");
          break;
1035 1036
        default:
          UNREACHABLE();
1037 1038
      }
    break;  // Case REGIMM.
1039 1040
    // ------------- Branch instructions.
    case BEQ:
1041
      Format(instr, "beq     'rs, 'rt, 'imm16u");
1042 1043
      break;
    case BNE:
1044
      Format(instr, "bne     'rs, 'rt, 'imm16u");
1045 1046
      break;
    case BLEZ:
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
      if ((instr->RtFieldRaw() == 0)
          && (instr->RsFieldRaw() != 0)) {
        Format(instr, "blez    'rs, 'imm16u");
      } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
          && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
        Format(instr, "bgeuc    'rs, 'rt, 'imm16u");
      } else if ((instr->RtFieldRaw() == instr->RsFieldRaw())
          && (instr->RtFieldRaw() != 0)) {
        Format(instr, "bgezalc  'rs, 'imm16u");
      } else if ((instr->RsFieldRaw() == 0)
          && (instr->RtFieldRaw() != 0)) {
        Format(instr, "blezalc  'rs, 'imm16u");
      } else {
        UNREACHABLE();
      }
1062 1063
      break;
    case BGTZ:
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
      if ((instr->RtFieldRaw() == 0)
          && (instr->RsFieldRaw() != 0)) {
        Format(instr, "bgtz    'rs, 'imm16u");
      } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
          && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
        Format(instr, "bltuc   'rs, 'rt, 'imm16u");
      } else if ((instr->RtFieldRaw() == instr->RsFieldRaw())
          && (instr->RtFieldRaw() != 0)) {
        Format(instr, "bltzalc 'rt, 'imm16u");
      } else if ((instr->RsFieldRaw() == 0)
          && (instr->RtFieldRaw() != 0)) {
        Format(instr, "bgtzalc 'rt, 'imm16u");
      } else {
        UNREACHABLE();
      }
      break;
    case BLEZL:
      if ((instr->RtFieldRaw() == instr->RsFieldRaw())
          && (instr->RtFieldRaw() != 0)) {
        Format(instr, "bgezc    'rt, 'imm16u");
      } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
          && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
        Format(instr, "bgec     'rs, 'rt, 'imm16u");
      } else if ((instr->RsFieldRaw() == 0)
          && (instr->RtFieldRaw() != 0)) {
        Format(instr, "blezc    'rt, 'imm16u");
      } else {
        UNREACHABLE();
      }
      break;
    case BGTZL:
      if ((instr->RtFieldRaw() == instr->RsFieldRaw())
          && (instr->RtFieldRaw() != 0)) {
        Format(instr, "bltzc    'rt, 'imm16u");
      } else if ((instr->RtFieldRaw() != instr->RsFieldRaw())
          && (instr->RsFieldRaw() != 0) && (instr->RtFieldRaw() != 0)) {
        Format(instr, "bltc     'rs, 'rt, 'imm16u");
      } else if ((instr->RsFieldRaw() == 0)
          && (instr->RtFieldRaw() != 0)) {
        Format(instr, "bgtzc    'rt, 'imm16u");
      } else {
        UNREACHABLE();
      }
      break;
    case BEQZC:
      if (instr->RsFieldRaw() != 0) {
        Format(instr, "beqzc   'rs, 'imm21x");
      }
      break;
    case BNEZC:
      if (instr->RsFieldRaw() != 0) {
        Format(instr, "bnezc   'rs, 'imm21x");
      }
1117 1118 1119
      break;
    // ------------- Arithmetic instructions.
    case ADDI:
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
      if (!IsMipsArchVariant(kMips32r6)) {
        Format(instr, "addi    'rt, 'rs, 'imm16s");
      } else {
        // Check if BOVC or BEQC instruction.
        if (instr->RsFieldRaw() >= instr->RtFieldRaw()) {
          Format(instr, "bovc  'rs, 'rt, 'imm16s");
        } else if (instr->RsFieldRaw() < instr->RtFieldRaw()) {
          Format(instr, "beqc  'rs, 'rt, 'imm16s");
        } else {
          UNREACHABLE();
        }
      }
      break;
    case DADDI:
      if (IsMipsArchVariant(kMips32r6)) {
        // Check if BNVC or BNEC instruction.
        if (instr->RsFieldRaw() >= instr->RtFieldRaw()) {
          Format(instr, "bnvc  'rs, 'rt, 'imm16s");
        } else if (instr->RsFieldRaw() < instr->RtFieldRaw()) {
          Format(instr, "bnec  'rs, 'rt, 'imm16s");
        } else {
          UNREACHABLE();
        }
      }
1144 1145
      break;
    case ADDIU:
1146
      Format(instr, "addiu   'rt, 'rs, 'imm16s");
1147 1148
      break;
    case SLTI:
1149
      Format(instr, "slti    'rt, 'rs, 'imm16s");
1150 1151
      break;
    case SLTIU:
1152
      Format(instr, "sltiu   'rt, 'rs, 'imm16u");
1153 1154
      break;
    case ANDI:
1155
      Format(instr, "andi    'rt, 'rs, 'imm16x");
1156 1157
      break;
    case ORI:
1158
      Format(instr, "ori     'rt, 'rs, 'imm16x");
1159 1160
      break;
    case XORI:
1161
      Format(instr, "xori    'rt, 'rs, 'imm16x");
1162 1163
      break;
    case LUI:
1164 1165 1166 1167 1168 1169 1170 1171 1172
      if (!IsMipsArchVariant(kMips32r6)) {
        Format(instr, "lui     'rt, 'imm16x");
      } else {
        if (instr->RsValue() != 0) {
          Format(instr, "aui     'rt, 'imm16x");
        } else {
          Format(instr, "lui     'rt, 'imm16x");
        }
      }
1173 1174 1175
      break;
    // ------------- Memory instructions.
    case LB:
1176
      Format(instr, "lb      'rt, 'imm16s('rs)");
1177
      break;
1178
    case LH:
1179
      Format(instr, "lh      'rt, 'imm16s('rs)");
1180 1181
      break;
    case LWL:
1182
      Format(instr, "lwl     'rt, 'imm16s('rs)");
1183
      break;
1184
    case LW:
1185
      Format(instr, "lw      'rt, 'imm16s('rs)");
1186 1187
      break;
    case LBU:
1188
      Format(instr, "lbu     'rt, 'imm16s('rs)");
1189
      break;
1190
    case LHU:
1191
      Format(instr, "lhu     'rt, 'imm16s('rs)");
1192 1193
      break;
    case LWR:
1194
      Format(instr, "lwr     'rt, 'imm16s('rs)");
1195
      break;
plind44@gmail.com's avatar
plind44@gmail.com committed
1196 1197 1198
    case PREF:
      Format(instr, "pref    'rt, 'imm16s('rs)");
      break;
1199
    case SB:
1200
      Format(instr, "sb      'rt, 'imm16s('rs)");
1201
      break;
1202
    case SH:
1203
      Format(instr, "sh      'rt, 'imm16s('rs)");
1204 1205
      break;
    case SWL:
1206
      Format(instr, "swl     'rt, 'imm16s('rs)");
1207
      break;
1208
    case SW:
1209
      Format(instr, "sw      'rt, 'imm16s('rs)");
1210
      break;
1211
    case SWR:
1212
      Format(instr, "swr     'rt, 'imm16s('rs)");
1213
      break;
1214
    case LWC1:
1215
      Format(instr, "lwc1    'ft, 'imm16s('rs)");
1216 1217
      break;
    case LDC1:
1218
      Format(instr, "ldc1    'ft, 'imm16s('rs)");
1219 1220
      break;
    case SWC1:
1221
      Format(instr, "swc1    'ft, 'imm16s('rs)");
1222 1223
      break;
    case SDC1:
1224
      Format(instr, "sdc1    'ft, 'imm16s('rs)");
1225 1226
      break;
    default:
1227
      printf("a 0x%x \n", instr->OpcodeFieldRaw());
1228 1229
      UNREACHABLE();
      break;
1230
  }
1231 1232 1233 1234 1235 1236
}


void Decoder::DecodeTypeJump(Instruction* instr) {
  switch (instr->OpcodeFieldRaw()) {
    case J:
1237
      Format(instr, "j       'imm26x");
1238 1239
      break;
    case JAL:
1240
      Format(instr, "jal     'imm26x");
1241 1242 1243 1244 1245 1246 1247 1248
      break;
    default:
      UNREACHABLE();
  }
}


// Disassemble the instruction at *instr_ptr into the output buffer.
1249
int Decoder::InstructionDecode(byte* instr_ptr) {
1250 1251
  Instruction* instr = Instruction::At(instr_ptr);
  // Print raw instruction bytes.
1252 1253 1254
  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_,
                                   "%08x       ",
                                   instr->InstructionBits());
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
  switch (instr->InstructionType()) {
    case Instruction::kRegisterType: {
      DecodeTypeRegister(instr);
      break;
    }
    case Instruction::kImmediateType: {
      DecodeTypeImmediate(instr);
      break;
    }
    case Instruction::kJumpType: {
      DecodeTypeJump(instr);
      break;
    }
    default: {
1269
      Format(instr, "UNSUPPORTED");
1270 1271 1272
      UNSUPPORTED_MIPS();
    }
  }
1273
  return Instruction::kInstrSize;
1274 1275 1276
}


1277
} }  // namespace v8::internal
1278 1279 1280 1281 1282 1283 1284



//------------------------------------------------------------------------------

namespace disasm {

1285
const char* NameConverter::NameOfAddress(byte* addr) const {
1286
  v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1287
  return tmp_buffer_.start();
1288 1289 1290
}


1291
const char* NameConverter::NameOfConstant(byte* addr) const {
1292 1293 1294 1295 1296
  return NameOfAddress(addr);
}


const char* NameConverter::NameOfCPURegister(int reg) const {
1297
  return v8::internal::Registers::Name(reg);
1298 1299 1300 1301
}


const char* NameConverter::NameOfXMMRegister(int reg) const {
1302
  return v8::internal::FPURegisters::Name(reg);
1303 1304 1305 1306
}


const char* NameConverter::NameOfByteCPURegister(int reg) const {
1307
  UNREACHABLE();  // MIPS does not have the concept of a byte register.
1308 1309 1310 1311
  return "nobytereg";
}


1312
const char* NameConverter::NameInCode(byte* addr) const {
1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
  // The default name converter is called for unknown code. So we will not try
  // to access any memory.
  return "";
}


//------------------------------------------------------------------------------

Disassembler::Disassembler(const NameConverter& converter)
    : converter_(converter) {}


Disassembler::~Disassembler() {}


int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1329
                                    byte* instruction) {
1330
  v8::internal::Decoder d(converter_, buffer);
1331 1332 1333 1334
  return d.InstructionDecode(instruction);
}


1335
// The MIPS assembler does not currently use constant pools.
1336
int Disassembler::ConstantPoolSizeAt(byte* instruction) {
1337 1338 1339 1340
  return -1;
}


1341
void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1342 1343
  NameConverter converter;
  Disassembler d(converter);
1344
  for (byte* pc = begin; pc < end;) {
1345 1346
    v8::internal::EmbeddedVector<char, 128> buffer;
    buffer[0] = '\0';
1347
    byte* prev_pc = pc;
1348
    pc += d.InstructionDecode(buffer, pc);
1349 1350
    v8::internal::PrintF(f, "%p    %08x      %s\n",
        prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
1351 1352 1353
  }
}

1354

1355 1356 1357 1358
#undef UNSUPPORTED

}  // namespace disasm

1359
#endif  // V8_TARGET_ARCH_MIPS