Home | History | Annotate | Download | only in arm64
      1 // Copyright 2013 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 #include <string.h>
      9 
     10 #include "src/v8.h"
     11 
     12 #if V8_TARGET_ARCH_ARM64
     13 
     14 #include "src/arm64/decoder-arm64-inl.h"
     15 #include "src/arm64/disasm-arm64.h"
     16 #include "src/base/platform/platform.h"
     17 #include "src/disasm.h"
     18 #include "src/macro-assembler.h"
     19 
     20 namespace v8 {
     21 namespace internal {
     22 
     23 
     24 Disassembler::Disassembler() {
     25   buffer_size_ = 256;
     26   buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
     27   buffer_pos_ = 0;
     28   own_buffer_ = true;
     29 }
     30 
     31 
     32 Disassembler::Disassembler(char* text_buffer, int buffer_size) {
     33   buffer_size_ = buffer_size;
     34   buffer_ = text_buffer;
     35   buffer_pos_ = 0;
     36   own_buffer_ = false;
     37 }
     38 
     39 
     40 Disassembler::~Disassembler() {
     41   if (own_buffer_) {
     42     free(buffer_);
     43   }
     44 }
     45 
     46 
     47 char* Disassembler::GetOutput() {
     48   return buffer_;
     49 }
     50 
     51 
     52 void Disassembler::VisitAddSubImmediate(Instruction* instr) {
     53   bool rd_is_zr = RdIsZROrSP(instr);
     54   bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
     55                   (instr->ImmAddSub() == 0) ? true : false;
     56   const char *mnemonic = "";
     57   const char *form = "'Rds, 'Rns, 'IAddSub";
     58   const char *form_cmp = "'Rns, 'IAddSub";
     59   const char *form_mov = "'Rds, 'Rns";
     60 
     61   switch (instr->Mask(AddSubImmediateMask)) {
     62     case ADD_w_imm:
     63     case ADD_x_imm: {
     64       mnemonic = "add";
     65       if (stack_op) {
     66         mnemonic = "mov";
     67         form = form_mov;
     68       }
     69       break;
     70     }
     71     case ADDS_w_imm:
     72     case ADDS_x_imm: {
     73       mnemonic = "adds";
     74       if (rd_is_zr) {
     75         mnemonic = "cmn";
     76         form = form_cmp;
     77       }
     78       break;
     79     }
     80     case SUB_w_imm:
     81     case SUB_x_imm: mnemonic = "sub"; break;
     82     case SUBS_w_imm:
     83     case SUBS_x_imm: {
     84       mnemonic = "subs";
     85       if (rd_is_zr) {
     86         mnemonic = "cmp";
     87         form = form_cmp;
     88       }
     89       break;
     90     }
     91     default: UNREACHABLE();
     92   }
     93   Format(instr, mnemonic, form);
     94 }
     95 
     96 
     97 void Disassembler::VisitAddSubShifted(Instruction* instr) {
     98   bool rd_is_zr = RdIsZROrSP(instr);
     99   bool rn_is_zr = RnIsZROrSP(instr);
    100   const char *mnemonic = "";
    101   const char *form = "'Rd, 'Rn, 'Rm'HDP";
    102   const char *form_cmp = "'Rn, 'Rm'HDP";
    103   const char *form_neg = "'Rd, 'Rm'HDP";
    104 
    105   switch (instr->Mask(AddSubShiftedMask)) {
    106     case ADD_w_shift:
    107     case ADD_x_shift: mnemonic = "add"; break;
    108     case ADDS_w_shift:
    109     case ADDS_x_shift: {
    110       mnemonic = "adds";
    111       if (rd_is_zr) {
    112         mnemonic = "cmn";
    113         form = form_cmp;
    114       }
    115       break;
    116     }
    117     case SUB_w_shift:
    118     case SUB_x_shift: {
    119       mnemonic = "sub";
    120       if (rn_is_zr) {
    121         mnemonic = "neg";
    122         form = form_neg;
    123       }
    124       break;
    125     }
    126     case SUBS_w_shift:
    127     case SUBS_x_shift: {
    128       mnemonic = "subs";
    129       if (rd_is_zr) {
    130         mnemonic = "cmp";
    131         form = form_cmp;
    132       } else if (rn_is_zr) {
    133         mnemonic = "negs";
    134         form = form_neg;
    135       }
    136       break;
    137     }
    138     default: UNREACHABLE();
    139   }
    140   Format(instr, mnemonic, form);
    141 }
    142 
    143 
    144 void Disassembler::VisitAddSubExtended(Instruction* instr) {
    145   bool rd_is_zr = RdIsZROrSP(instr);
    146   const char *mnemonic = "";
    147   Extend mode = static_cast<Extend>(instr->ExtendMode());
    148   const char *form = ((mode == UXTX) || (mode == SXTX)) ?
    149                      "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext";
    150   const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ?
    151                          "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
    152 
    153   switch (instr->Mask(AddSubExtendedMask)) {
    154     case ADD_w_ext:
    155     case ADD_x_ext: mnemonic = "add"; break;
    156     case ADDS_w_ext:
    157     case ADDS_x_ext: {
    158       mnemonic = "adds";
    159       if (rd_is_zr) {
    160         mnemonic = "cmn";
    161         form = form_cmp;
    162       }
    163       break;
    164     }
    165     case SUB_w_ext:
    166     case SUB_x_ext: mnemonic = "sub"; break;
    167     case SUBS_w_ext:
    168     case SUBS_x_ext: {
    169       mnemonic = "subs";
    170       if (rd_is_zr) {
    171         mnemonic = "cmp";
    172         form = form_cmp;
    173       }
    174       break;
    175     }
    176     default: UNREACHABLE();
    177   }
    178   Format(instr, mnemonic, form);
    179 }
    180 
    181 
    182 void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
    183   bool rn_is_zr = RnIsZROrSP(instr);
    184   const char *mnemonic = "";
    185   const char *form = "'Rd, 'Rn, 'Rm";
    186   const char *form_neg = "'Rd, 'Rm";
    187 
    188   switch (instr->Mask(AddSubWithCarryMask)) {
    189     case ADC_w:
    190     case ADC_x: mnemonic = "adc"; break;
    191     case ADCS_w:
    192     case ADCS_x: mnemonic = "adcs"; break;
    193     case SBC_w:
    194     case SBC_x: {
    195       mnemonic = "sbc";
    196       if (rn_is_zr) {
    197         mnemonic = "ngc";
    198         form = form_neg;
    199       }
    200       break;
    201     }
    202     case SBCS_w:
    203     case SBCS_x: {
    204       mnemonic = "sbcs";
    205       if (rn_is_zr) {
    206         mnemonic = "ngcs";
    207         form = form_neg;
    208       }
    209       break;
    210     }
    211     default: UNREACHABLE();
    212   }
    213   Format(instr, mnemonic, form);
    214 }
    215 
    216 
    217 void Disassembler::VisitLogicalImmediate(Instruction* instr) {
    218   bool rd_is_zr = RdIsZROrSP(instr);
    219   bool rn_is_zr = RnIsZROrSP(instr);
    220   const char *mnemonic = "";
    221   const char *form = "'Rds, 'Rn, 'ITri";
    222 
    223   if (instr->ImmLogical() == 0) {
    224     // The immediate encoded in the instruction is not in the expected format.
    225     Format(instr, "unallocated", "(LogicalImmediate)");
    226     return;
    227   }
    228 
    229   switch (instr->Mask(LogicalImmediateMask)) {
    230     case AND_w_imm:
    231     case AND_x_imm: mnemonic = "and"; break;
    232     case ORR_w_imm:
    233     case ORR_x_imm: {
    234       mnemonic = "orr";
    235       unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
    236                                                         : kWRegSizeInBits;
    237       if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
    238         mnemonic = "mov";
    239         form = "'Rds, 'ITri";
    240       }
    241       break;
    242     }
    243     case EOR_w_imm:
    244     case EOR_x_imm: mnemonic = "eor"; break;
    245     case ANDS_w_imm:
    246     case ANDS_x_imm: {
    247       mnemonic = "ands";
    248       if (rd_is_zr) {
    249         mnemonic = "tst";
    250         form = "'Rn, 'ITri";
    251       }
    252       break;
    253     }
    254     default: UNREACHABLE();
    255   }
    256   Format(instr, mnemonic, form);
    257 }
    258 
    259 
    260 bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
    261   DCHECK((reg_size == kXRegSizeInBits) ||
    262          ((reg_size == kWRegSizeInBits) && (value <= 0xffffffff)));
    263 
    264   // Test for movz: 16-bits set at positions 0, 16, 32 or 48.
    265   if (((value & 0xffffffffffff0000UL) == 0UL) ||
    266       ((value & 0xffffffff0000ffffUL) == 0UL) ||
    267       ((value & 0xffff0000ffffffffUL) == 0UL) ||
    268       ((value & 0x0000ffffffffffffUL) == 0UL)) {
    269     return true;
    270   }
    271 
    272   // Test for movn: NOT(16-bits set at positions 0, 16, 32 or 48).
    273   if ((reg_size == kXRegSizeInBits) &&
    274       (((value & 0xffffffffffff0000UL) == 0xffffffffffff0000UL) ||
    275        ((value & 0xffffffff0000ffffUL) == 0xffffffff0000ffffUL) ||
    276        ((value & 0xffff0000ffffffffUL) == 0xffff0000ffffffffUL) ||
    277        ((value & 0x0000ffffffffffffUL) == 0x0000ffffffffffffUL))) {
    278     return true;
    279   }
    280   if ((reg_size == kWRegSizeInBits) &&
    281       (((value & 0xffff0000) == 0xffff0000) ||
    282        ((value & 0x0000ffff) == 0x0000ffff))) {
    283     return true;
    284   }
    285   return false;
    286 }
    287 
    288 
    289 void Disassembler::VisitLogicalShifted(Instruction* instr) {
    290   bool rd_is_zr = RdIsZROrSP(instr);
    291   bool rn_is_zr = RnIsZROrSP(instr);
    292   const char *mnemonic = "";
    293   const char *form = "'Rd, 'Rn, 'Rm'HLo";
    294 
    295   switch (instr->Mask(LogicalShiftedMask)) {
    296     case AND_w:
    297     case AND_x: mnemonic = "and"; break;
    298     case BIC_w:
    299     case BIC_x: mnemonic = "bic"; break;
    300     case EOR_w:
    301     case EOR_x: mnemonic = "eor"; break;
    302     case EON_w:
    303     case EON_x: mnemonic = "eon"; break;
    304     case BICS_w:
    305     case BICS_x: mnemonic = "bics"; break;
    306     case ANDS_w:
    307     case ANDS_x: {
    308       mnemonic = "ands";
    309       if (rd_is_zr) {
    310         mnemonic = "tst";
    311         form = "'Rn, 'Rm'HLo";
    312       }
    313       break;
    314     }
    315     case ORR_w:
    316     case ORR_x: {
    317       mnemonic = "orr";
    318       if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
    319         mnemonic = "mov";
    320         form = "'Rd, 'Rm";
    321       }
    322       break;
    323     }
    324     case ORN_w:
    325     case ORN_x: {
    326       mnemonic = "orn";
    327       if (rn_is_zr) {
    328         mnemonic = "mvn";
    329         form = "'Rd, 'Rm'HLo";
    330       }
    331       break;
    332     }
    333     default: UNREACHABLE();
    334   }
    335 
    336   Format(instr, mnemonic, form);
    337 }
    338 
    339 
    340 void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
    341   const char *mnemonic = "";
    342   const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
    343 
    344   switch (instr->Mask(ConditionalCompareRegisterMask)) {
    345     case CCMN_w:
    346     case CCMN_x: mnemonic = "ccmn"; break;
    347     case CCMP_w:
    348     case CCMP_x: mnemonic = "ccmp"; break;
    349     default: UNREACHABLE();
    350   }
    351   Format(instr, mnemonic, form);
    352 }
    353 
    354 
    355 void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
    356   const char *mnemonic = "";
    357   const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
    358 
    359   switch (instr->Mask(ConditionalCompareImmediateMask)) {
    360     case CCMN_w_imm:
    361     case CCMN_x_imm: mnemonic = "ccmn"; break;
    362     case CCMP_w_imm:
    363     case CCMP_x_imm: mnemonic = "ccmp"; break;
    364     default: UNREACHABLE();
    365   }
    366   Format(instr, mnemonic, form);
    367 }
    368 
    369 
    370 void Disassembler::VisitConditionalSelect(Instruction* instr) {
    371   bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
    372   bool rn_is_rm = (instr->Rn() == instr->Rm());
    373   const char *mnemonic = "";
    374   const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
    375   const char *form_test = "'Rd, 'CInv";
    376   const char *form_update = "'Rd, 'Rn, 'CInv";
    377 
    378   Condition cond = static_cast<Condition>(instr->Condition());
    379   bool invertible_cond = (cond != al) && (cond != nv);
    380 
    381   switch (instr->Mask(ConditionalSelectMask)) {
    382     case CSEL_w:
    383     case CSEL_x: mnemonic = "csel"; break;
    384     case CSINC_w:
    385     case CSINC_x: {
    386       mnemonic = "csinc";
    387       if (rnm_is_zr && invertible_cond) {
    388         mnemonic = "cset";
    389         form = form_test;
    390       } else if (rn_is_rm && invertible_cond) {
    391         mnemonic = "cinc";
    392         form = form_update;
    393       }
    394       break;
    395     }
    396     case CSINV_w:
    397     case CSINV_x: {
    398       mnemonic = "csinv";
    399       if (rnm_is_zr && invertible_cond) {
    400         mnemonic = "csetm";
    401         form = form_test;
    402       } else if (rn_is_rm && invertible_cond) {
    403         mnemonic = "cinv";
    404         form = form_update;
    405       }
    406       break;
    407     }
    408     case CSNEG_w:
    409     case CSNEG_x: {
    410       mnemonic = "csneg";
    411       if (rn_is_rm && invertible_cond) {
    412         mnemonic = "cneg";
    413         form = form_update;
    414       }
    415       break;
    416     }
    417     default: UNREACHABLE();
    418   }
    419   Format(instr, mnemonic, form);
    420 }
    421 
    422 
    423 void Disassembler::VisitBitfield(Instruction* instr) {
    424   unsigned s = instr->ImmS();
    425   unsigned r = instr->ImmR();
    426   unsigned rd_size_minus_1 =
    427     ((instr->SixtyFourBits() == 1) ? kXRegSizeInBits : kWRegSizeInBits) - 1;
    428   const char *mnemonic = "";
    429   const char *form = "";
    430   const char *form_shift_right = "'Rd, 'Rn, 'IBr";
    431   const char *form_extend = "'Rd, 'Wn";
    432   const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
    433   const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
    434   const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
    435 
    436   switch (instr->Mask(BitfieldMask)) {
    437     case SBFM_w:
    438     case SBFM_x: {
    439       mnemonic = "sbfx";
    440       form = form_bfx;
    441       if (r == 0) {
    442         form = form_extend;
    443         if (s == 7) {
    444           mnemonic = "sxtb";
    445         } else if (s == 15) {
    446           mnemonic = "sxth";
    447         } else if ((s == 31) && (instr->SixtyFourBits() == 1)) {
    448           mnemonic = "sxtw";
    449         } else {
    450           form = form_bfx;
    451         }
    452       } else if (s == rd_size_minus_1) {
    453         mnemonic = "asr";
    454         form = form_shift_right;
    455       } else if (s < r) {
    456         mnemonic = "sbfiz";
    457         form = form_bfiz;
    458       }
    459       break;
    460     }
    461     case UBFM_w:
    462     case UBFM_x: {
    463       mnemonic = "ubfx";
    464       form = form_bfx;
    465       if (r == 0) {
    466         form = form_extend;
    467         if (s == 7) {
    468           mnemonic = "uxtb";
    469         } else if (s == 15) {
    470           mnemonic = "uxth";
    471         } else {
    472           form = form_bfx;
    473         }
    474       }
    475       if (s == rd_size_minus_1) {
    476         mnemonic = "lsr";
    477         form = form_shift_right;
    478       } else if (r == s + 1) {
    479         mnemonic = "lsl";
    480         form = form_lsl;
    481       } else if (s < r) {
    482         mnemonic = "ubfiz";
    483         form = form_bfiz;
    484       }
    485       break;
    486     }
    487     case BFM_w:
    488     case BFM_x: {
    489       mnemonic = "bfxil";
    490       form = form_bfx;
    491       if (s < r) {
    492         mnemonic = "bfi";
    493         form = form_bfiz;
    494       }
    495     }
    496   }
    497   Format(instr, mnemonic, form);
    498 }
    499 
    500 
    501 void Disassembler::VisitExtract(Instruction* instr) {
    502   const char *mnemonic = "";
    503   const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
    504 
    505   switch (instr->Mask(ExtractMask)) {
    506     case EXTR_w:
    507     case EXTR_x: {
    508       if (instr->Rn() == instr->Rm()) {
    509         mnemonic = "ror";
    510         form = "'Rd, 'Rn, 'IExtract";
    511       } else {
    512         mnemonic = "extr";
    513       }
    514       break;
    515     }
    516     default: UNREACHABLE();
    517   }
    518   Format(instr, mnemonic, form);
    519 }
    520 
    521 
    522 void Disassembler::VisitPCRelAddressing(Instruction* instr) {
    523   switch (instr->Mask(PCRelAddressingMask)) {
    524     case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
    525     // ADRP is not implemented.
    526     default: Format(instr, "unimplemented", "(PCRelAddressing)");
    527   }
    528 }
    529 
    530 
    531 void Disassembler::VisitConditionalBranch(Instruction* instr) {
    532   switch (instr->Mask(ConditionalBranchMask)) {
    533     case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
    534     default: UNREACHABLE();
    535   }
    536 }
    537 
    538 
    539 void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
    540   const char *mnemonic = "unimplemented";
    541   const char *form = "'Xn";
    542 
    543   switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
    544     case BR: mnemonic = "br"; break;
    545     case BLR: mnemonic = "blr"; break;
    546     case RET: {
    547       mnemonic = "ret";
    548       if (instr->Rn() == kLinkRegCode) {
    549         form = NULL;
    550       }
    551       break;
    552     }
    553     default: form = "(UnconditionalBranchToRegister)";
    554   }
    555   Format(instr, mnemonic, form);
    556 }
    557 
    558 
    559 void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
    560   const char *mnemonic = "";
    561   const char *form = "'BImmUncn";
    562 
    563   switch (instr->Mask(UnconditionalBranchMask)) {
    564     case B: mnemonic = "b"; break;
    565     case BL: mnemonic = "bl"; break;
    566     default: UNREACHABLE();
    567   }
    568   Format(instr, mnemonic, form);
    569 }
    570 
    571 
    572 void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
    573   const char *mnemonic = "";
    574   const char *form = "'Rd, 'Rn";
    575 
    576   switch (instr->Mask(DataProcessing1SourceMask)) {
    577     #define FORMAT(A, B)  \
    578     case A##_w:           \
    579     case A##_x: mnemonic = B; break;
    580     FORMAT(RBIT, "rbit");
    581     FORMAT(REV16, "rev16");
    582     FORMAT(REV, "rev");
    583     FORMAT(CLZ, "clz");
    584     FORMAT(CLS, "cls");
    585     #undef FORMAT
    586     case REV32_x: mnemonic = "rev32"; break;
    587     default: UNREACHABLE();
    588   }
    589   Format(instr, mnemonic, form);
    590 }
    591 
    592 
    593 void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
    594   const char *mnemonic = "unimplemented";
    595   const char *form = "'Rd, 'Rn, 'Rm";
    596 
    597   switch (instr->Mask(DataProcessing2SourceMask)) {
    598     #define FORMAT(A, B)  \
    599     case A##_w:           \
    600     case A##_x: mnemonic = B; break;
    601     FORMAT(UDIV, "udiv");
    602     FORMAT(SDIV, "sdiv");
    603     FORMAT(LSLV, "lsl");
    604     FORMAT(LSRV, "lsr");
    605     FORMAT(ASRV, "asr");
    606     FORMAT(RORV, "ror");
    607     #undef FORMAT
    608     default: form = "(DataProcessing2Source)";
    609   }
    610   Format(instr, mnemonic, form);
    611 }
    612 
    613 
    614 void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
    615   bool ra_is_zr = RaIsZROrSP(instr);
    616   const char *mnemonic = "";
    617   const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
    618   const char *form_rrr = "'Rd, 'Rn, 'Rm";
    619   const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
    620   const char *form_xww = "'Xd, 'Wn, 'Wm";
    621   const char *form_xxx = "'Xd, 'Xn, 'Xm";
    622 
    623   switch (instr->Mask(DataProcessing3SourceMask)) {
    624     case MADD_w:
    625     case MADD_x: {
    626       mnemonic = "madd";
    627       form = form_rrrr;
    628       if (ra_is_zr) {
    629         mnemonic = "mul";
    630         form = form_rrr;
    631       }
    632       break;
    633     }
    634     case MSUB_w:
    635     case MSUB_x: {
    636       mnemonic = "msub";
    637       form = form_rrrr;
    638       if (ra_is_zr) {
    639         mnemonic = "mneg";
    640         form = form_rrr;
    641       }
    642       break;
    643     }
    644     case SMADDL_x: {
    645       mnemonic = "smaddl";
    646       if (ra_is_zr) {
    647         mnemonic = "smull";
    648         form = form_xww;
    649       }
    650       break;
    651     }
    652     case SMSUBL_x: {
    653       mnemonic = "smsubl";
    654       if (ra_is_zr) {
    655         mnemonic = "smnegl";
    656         form = form_xww;
    657       }
    658       break;
    659     }
    660     case UMADDL_x: {
    661       mnemonic = "umaddl";
    662       if (ra_is_zr) {
    663         mnemonic = "umull";
    664         form = form_xww;
    665       }
    666       break;
    667     }
    668     case UMSUBL_x: {
    669       mnemonic = "umsubl";
    670       if (ra_is_zr) {
    671         mnemonic = "umnegl";
    672         form = form_xww;
    673       }
    674       break;
    675     }
    676     case SMULH_x: {
    677       mnemonic = "smulh";
    678       form = form_xxx;
    679       break;
    680     }
    681     case UMULH_x: {
    682       mnemonic = "umulh";
    683       form = form_xxx;
    684       break;
    685     }
    686     default: UNREACHABLE();
    687   }
    688   Format(instr, mnemonic, form);
    689 }
    690 
    691 
    692 void Disassembler::VisitCompareBranch(Instruction* instr) {
    693   const char *mnemonic = "";
    694   const char *form = "'Rt, 'BImmCmpa";
    695 
    696   switch (instr->Mask(CompareBranchMask)) {
    697     case CBZ_w:
    698     case CBZ_x: mnemonic = "cbz"; break;
    699     case CBNZ_w:
    700     case CBNZ_x: mnemonic = "cbnz"; break;
    701     default: UNREACHABLE();
    702   }
    703   Format(instr, mnemonic, form);
    704 }
    705 
    706 
    707 void Disassembler::VisitTestBranch(Instruction* instr) {
    708   const char *mnemonic = "";
    709   // If the top bit of the immediate is clear, the tested register is
    710   // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
    711   // encoded in bit 31 of the instruction, we can reuse the Rt form, which
    712   // uses bit 31 (normally "sf") to choose the register size.
    713   const char *form = "'Rt, 'IS, 'BImmTest";
    714 
    715   switch (instr->Mask(TestBranchMask)) {
    716     case TBZ: mnemonic = "tbz"; break;
    717     case TBNZ: mnemonic = "tbnz"; break;
    718     default: UNREACHABLE();
    719   }
    720   Format(instr, mnemonic, form);
    721 }
    722 
    723 
    724 void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
    725   const char *mnemonic = "";
    726   const char *form = "'Rd, 'IMoveImm";
    727 
    728   // Print the shift separately for movk, to make it clear which half word will
    729   // be overwritten. Movn and movz print the computed immediate, which includes
    730   // shift calculation.
    731   switch (instr->Mask(MoveWideImmediateMask)) {
    732     case MOVN_w:
    733     case MOVN_x: mnemonic = "movn"; break;
    734     case MOVZ_w:
    735     case MOVZ_x: mnemonic = "movz"; break;
    736     case MOVK_w:
    737     case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
    738     default: UNREACHABLE();
    739   }
    740   Format(instr, mnemonic, form);
    741 }
    742 
    743 
    744 #define LOAD_STORE_LIST(V)    \
    745   V(STRB_w, "strb", "'Wt")    \
    746   V(STRH_w, "strh", "'Wt")    \
    747   V(STR_w, "str", "'Wt")      \
    748   V(STR_x, "str", "'Xt")      \
    749   V(LDRB_w, "ldrb", "'Wt")    \
    750   V(LDRH_w, "ldrh", "'Wt")    \
    751   V(LDR_w, "ldr", "'Wt")      \
    752   V(LDR_x, "ldr", "'Xt")      \
    753   V(LDRSB_x, "ldrsb", "'Xt")  \
    754   V(LDRSH_x, "ldrsh", "'Xt")  \
    755   V(LDRSW_x, "ldrsw", "'Xt")  \
    756   V(LDRSB_w, "ldrsb", "'Wt")  \
    757   V(LDRSH_w, "ldrsh", "'Wt")  \
    758   V(STR_s, "str", "'St")      \
    759   V(STR_d, "str", "'Dt")      \
    760   V(LDR_s, "ldr", "'St")      \
    761   V(LDR_d, "ldr", "'Dt")
    762 
    763 void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
    764   const char *mnemonic = "unimplemented";
    765   const char *form = "(LoadStorePreIndex)";
    766 
    767   switch (instr->Mask(LoadStorePreIndexMask)) {
    768     #define LS_PREINDEX(A, B, C) \
    769     case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
    770     LOAD_STORE_LIST(LS_PREINDEX)
    771     #undef LS_PREINDEX
    772   }
    773   Format(instr, mnemonic, form);
    774 }
    775 
    776 
    777 void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
    778   const char *mnemonic = "unimplemented";
    779   const char *form = "(LoadStorePostIndex)";
    780 
    781   switch (instr->Mask(LoadStorePostIndexMask)) {
    782     #define LS_POSTINDEX(A, B, C) \
    783     case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
    784     LOAD_STORE_LIST(LS_POSTINDEX)
    785     #undef LS_POSTINDEX
    786   }
    787   Format(instr, mnemonic, form);
    788 }
    789 
    790 
    791 void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
    792   const char *mnemonic = "unimplemented";
    793   const char *form = "(LoadStoreUnsignedOffset)";
    794 
    795   switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
    796     #define LS_UNSIGNEDOFFSET(A, B, C) \
    797     case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
    798     LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
    799     #undef LS_UNSIGNEDOFFSET
    800     case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xn'ILU]";
    801   }
    802   Format(instr, mnemonic, form);
    803 }
    804 
    805 
    806 void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
    807   const char *mnemonic = "unimplemented";
    808   const char *form = "(LoadStoreRegisterOffset)";
    809 
    810   switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
    811     #define LS_REGISTEROFFSET(A, B, C) \
    812     case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
    813     LOAD_STORE_LIST(LS_REGISTEROFFSET)
    814     #undef LS_REGISTEROFFSET
    815     case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]";
    816   }
    817   Format(instr, mnemonic, form);
    818 }
    819 
    820 
    821 void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
    822   const char *mnemonic = "unimplemented";
    823   const char *form = "'Wt, ['Xns'ILS]";
    824   const char *form_x = "'Xt, ['Xns'ILS]";
    825   const char *form_s = "'St, ['Xns'ILS]";
    826   const char *form_d = "'Dt, ['Xns'ILS]";
    827 
    828   switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
    829     case STURB_w:  mnemonic = "sturb"; break;
    830     case STURH_w:  mnemonic = "sturh"; break;
    831     case STUR_w:   mnemonic = "stur"; break;
    832     case STUR_x:   mnemonic = "stur"; form = form_x; break;
    833     case STUR_s:   mnemonic = "stur"; form = form_s; break;
    834     case STUR_d:   mnemonic = "stur"; form = form_d; break;
    835     case LDURB_w:  mnemonic = "ldurb"; break;
    836     case LDURH_w:  mnemonic = "ldurh"; break;
    837     case LDUR_w:   mnemonic = "ldur"; break;
    838     case LDUR_x:   mnemonic = "ldur"; form = form_x; break;
    839     case LDUR_s:   mnemonic = "ldur"; form = form_s; break;
    840     case LDUR_d:   mnemonic = "ldur"; form = form_d; break;
    841     case LDURSB_x: form = form_x;  // Fall through.
    842     case LDURSB_w: mnemonic = "ldursb"; break;
    843     case LDURSH_x: form = form_x;  // Fall through.
    844     case LDURSH_w: mnemonic = "ldursh"; break;
    845     case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
    846     default: form = "(LoadStoreUnscaledOffset)";
    847   }
    848   Format(instr, mnemonic, form);
    849 }
    850 
    851 
    852 void Disassembler::VisitLoadLiteral(Instruction* instr) {
    853   const char *mnemonic = "ldr";
    854   const char *form = "(LoadLiteral)";
    855 
    856   switch (instr->Mask(LoadLiteralMask)) {
    857     case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break;
    858     case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
    859     case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
    860     case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
    861     default: mnemonic = "unimplemented";
    862   }
    863   Format(instr, mnemonic, form);
    864 }
    865 
    866 
    867 #define LOAD_STORE_PAIR_LIST(V)         \
    868   V(STP_w, "stp", "'Wt, 'Wt2", "4")     \
    869   V(LDP_w, "ldp", "'Wt, 'Wt2", "4")     \
    870   V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \
    871   V(STP_x, "stp", "'Xt, 'Xt2", "8")     \
    872   V(LDP_x, "ldp", "'Xt, 'Xt2", "8")     \
    873   V(STP_s, "stp", "'St, 'St2", "4")     \
    874   V(LDP_s, "ldp", "'St, 'St2", "4")     \
    875   V(STP_d, "stp", "'Dt, 'Dt2", "8")     \
    876   V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
    877 
    878 void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
    879   const char *mnemonic = "unimplemented";
    880   const char *form = "(LoadStorePairPostIndex)";
    881 
    882   switch (instr->Mask(LoadStorePairPostIndexMask)) {
    883     #define LSP_POSTINDEX(A, B, C, D) \
    884     case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
    885     LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
    886     #undef LSP_POSTINDEX
    887   }
    888   Format(instr, mnemonic, form);
    889 }
    890 
    891 
    892 void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
    893   const char *mnemonic = "unimplemented";
    894   const char *form = "(LoadStorePairPreIndex)";
    895 
    896   switch (instr->Mask(LoadStorePairPreIndexMask)) {
    897     #define LSP_PREINDEX(A, B, C, D) \
    898     case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
    899     LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
    900     #undef LSP_PREINDEX
    901   }
    902   Format(instr, mnemonic, form);
    903 }
    904 
    905 
    906 void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
    907   const char *mnemonic = "unimplemented";
    908   const char *form = "(LoadStorePairOffset)";
    909 
    910   switch (instr->Mask(LoadStorePairOffsetMask)) {
    911     #define LSP_OFFSET(A, B, C, D) \
    912     case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
    913     LOAD_STORE_PAIR_LIST(LSP_OFFSET)
    914     #undef LSP_OFFSET
    915   }
    916   Format(instr, mnemonic, form);
    917 }
    918 
    919 
    920 void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
    921   const char *mnemonic = "unimplemented";
    922   const char *form;
    923 
    924   switch (instr->Mask(LoadStorePairNonTemporalMask)) {
    925     case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
    926     case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
    927     case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
    928     case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
    929     case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
    930     case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
    931     case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
    932     case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
    933     default: form = "(LoadStorePairNonTemporal)";
    934   }
    935   Format(instr, mnemonic, form);
    936 }
    937 
    938 
    939 void Disassembler::VisitFPCompare(Instruction* instr) {
    940   const char *mnemonic = "unimplemented";
    941   const char *form = "'Fn, 'Fm";
    942   const char *form_zero = "'Fn, #0.0";
    943 
    944   switch (instr->Mask(FPCompareMask)) {
    945     case FCMP_s_zero:
    946     case FCMP_d_zero: form = form_zero;  // Fall through.
    947     case FCMP_s:
    948     case FCMP_d: mnemonic = "fcmp"; break;
    949     default: form = "(FPCompare)";
    950   }
    951   Format(instr, mnemonic, form);
    952 }
    953 
    954 
    955 void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
    956   const char *mnemonic = "unimplemented";
    957   const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
    958 
    959   switch (instr->Mask(FPConditionalCompareMask)) {
    960     case FCCMP_s:
    961     case FCCMP_d: mnemonic = "fccmp"; break;
    962     case FCCMPE_s:
    963     case FCCMPE_d: mnemonic = "fccmpe"; break;
    964     default: form = "(FPConditionalCompare)";
    965   }
    966   Format(instr, mnemonic, form);
    967 }
    968 
    969 
    970 void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
    971   const char *mnemonic = "";
    972   const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
    973 
    974   switch (instr->Mask(FPConditionalSelectMask)) {
    975     case FCSEL_s:
    976     case FCSEL_d: mnemonic = "fcsel"; break;
    977     default: UNREACHABLE();
    978   }
    979   Format(instr, mnemonic, form);
    980 }
    981 
    982 
    983 void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
    984   const char *mnemonic = "unimplemented";
    985   const char *form = "'Fd, 'Fn";
    986 
    987   switch (instr->Mask(FPDataProcessing1SourceMask)) {
    988     #define FORMAT(A, B)  \
    989     case A##_s:           \
    990     case A##_d: mnemonic = B; break;
    991     FORMAT(FMOV, "fmov");
    992     FORMAT(FABS, "fabs");
    993     FORMAT(FNEG, "fneg");
    994     FORMAT(FSQRT, "fsqrt");
    995     FORMAT(FRINTN, "frintn");
    996     FORMAT(FRINTP, "frintp");
    997     FORMAT(FRINTM, "frintm");
    998     FORMAT(FRINTZ, "frintz");
    999     FORMAT(FRINTA, "frinta");
   1000     FORMAT(FRINTX, "frintx");
   1001     FORMAT(FRINTI, "frinti");
   1002     #undef FORMAT
   1003     case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
   1004     case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
   1005     default: form = "(FPDataProcessing1Source)";
   1006   }
   1007   Format(instr, mnemonic, form);
   1008 }
   1009 
   1010 
   1011 void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
   1012   const char *mnemonic = "";
   1013   const char *form = "'Fd, 'Fn, 'Fm";
   1014 
   1015   switch (instr->Mask(FPDataProcessing2SourceMask)) {
   1016     #define FORMAT(A, B)  \
   1017     case A##_s:           \
   1018     case A##_d: mnemonic = B; break;
   1019     FORMAT(FMUL, "fmul");
   1020     FORMAT(FDIV, "fdiv");
   1021     FORMAT(FADD, "fadd");
   1022     FORMAT(FSUB, "fsub");
   1023     FORMAT(FMAX, "fmax");
   1024     FORMAT(FMIN, "fmin");
   1025     FORMAT(FMAXNM, "fmaxnm");
   1026     FORMAT(FMINNM, "fminnm");
   1027     FORMAT(FNMUL, "fnmul");
   1028     #undef FORMAT
   1029     default: UNREACHABLE();
   1030   }
   1031   Format(instr, mnemonic, form);
   1032 }
   1033 
   1034 
   1035 void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
   1036   const char *mnemonic = "";
   1037   const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
   1038 
   1039   switch (instr->Mask(FPDataProcessing3SourceMask)) {
   1040     #define FORMAT(A, B)  \
   1041     case A##_s:           \
   1042     case A##_d: mnemonic = B; break;
   1043     FORMAT(FMADD, "fmadd");
   1044     FORMAT(FMSUB, "fmsub");
   1045     FORMAT(FNMADD, "fnmadd");
   1046     FORMAT(FNMSUB, "fnmsub");
   1047     #undef FORMAT
   1048     default: UNREACHABLE();
   1049   }
   1050   Format(instr, mnemonic, form);
   1051 }
   1052 
   1053 
   1054 void Disassembler::VisitFPImmediate(Instruction* instr) {
   1055   const char *mnemonic = "";
   1056   const char *form = "(FPImmediate)";
   1057 
   1058   switch (instr->Mask(FPImmediateMask)) {
   1059     case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
   1060     case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
   1061     default: UNREACHABLE();
   1062   }
   1063   Format(instr, mnemonic, form);
   1064 }
   1065 
   1066 
   1067 void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
   1068   const char *mnemonic = "unimplemented";
   1069   const char *form = "(FPIntegerConvert)";
   1070   const char *form_rf = "'Rd, 'Fn";
   1071   const char *form_fr = "'Fd, 'Rn";
   1072 
   1073   switch (instr->Mask(FPIntegerConvertMask)) {
   1074     case FMOV_ws:
   1075     case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
   1076     case FMOV_sw:
   1077     case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
   1078     case FCVTAS_ws:
   1079     case FCVTAS_xs:
   1080     case FCVTAS_wd:
   1081     case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
   1082     case FCVTAU_ws:
   1083     case FCVTAU_xs:
   1084     case FCVTAU_wd:
   1085     case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
   1086     case FCVTMS_ws:
   1087     case FCVTMS_xs:
   1088     case FCVTMS_wd:
   1089     case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
   1090     case FCVTMU_ws:
   1091     case FCVTMU_xs:
   1092     case FCVTMU_wd:
   1093     case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
   1094     case FCVTNS_ws:
   1095     case FCVTNS_xs:
   1096     case FCVTNS_wd:
   1097     case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
   1098     case FCVTNU_ws:
   1099     case FCVTNU_xs:
   1100     case FCVTNU_wd:
   1101     case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
   1102     case FCVTZU_xd:
   1103     case FCVTZU_ws:
   1104     case FCVTZU_wd:
   1105     case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
   1106     case FCVTZS_xd:
   1107     case FCVTZS_wd:
   1108     case FCVTZS_xs:
   1109     case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
   1110     case SCVTF_sw:
   1111     case SCVTF_sx:
   1112     case SCVTF_dw:
   1113     case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
   1114     case UCVTF_sw:
   1115     case UCVTF_sx:
   1116     case UCVTF_dw:
   1117     case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
   1118   }
   1119   Format(instr, mnemonic, form);
   1120 }
   1121 
   1122 
   1123 void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
   1124   const char *mnemonic = "";
   1125   const char *form = "'Rd, 'Fn, 'IFPFBits";
   1126   const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
   1127 
   1128   switch (instr->Mask(FPFixedPointConvertMask)) {
   1129     case FCVTZS_ws_fixed:
   1130     case FCVTZS_xs_fixed:
   1131     case FCVTZS_wd_fixed:
   1132     case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
   1133     case FCVTZU_ws_fixed:
   1134     case FCVTZU_xs_fixed:
   1135     case FCVTZU_wd_fixed:
   1136     case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
   1137     case SCVTF_sw_fixed:
   1138     case SCVTF_sx_fixed:
   1139     case SCVTF_dw_fixed:
   1140     case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
   1141     case UCVTF_sw_fixed:
   1142     case UCVTF_sx_fixed:
   1143     case UCVTF_dw_fixed:
   1144     case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
   1145   }
   1146   Format(instr, mnemonic, form);
   1147 }
   1148 
   1149 
   1150 void Disassembler::VisitSystem(Instruction* instr) {
   1151   // Some system instructions hijack their Op and Cp fields to represent a
   1152   // range of immediates instead of indicating a different instruction. This
   1153   // makes the decoding tricky.
   1154   const char *mnemonic = "unimplemented";
   1155   const char *form = "(System)";
   1156 
   1157   if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
   1158     switch (instr->Mask(SystemSysRegMask)) {
   1159       case MRS: {
   1160         mnemonic = "mrs";
   1161         switch (instr->ImmSystemRegister()) {
   1162           case NZCV: form = "'Xt, nzcv"; break;
   1163           case FPCR: form = "'Xt, fpcr"; break;
   1164           default: form = "'Xt, (unknown)"; break;
   1165         }
   1166         break;
   1167       }
   1168       case MSR: {
   1169         mnemonic = "msr";
   1170         switch (instr->ImmSystemRegister()) {
   1171           case NZCV: form = "nzcv, 'Xt"; break;
   1172           case FPCR: form = "fpcr, 'Xt"; break;
   1173           default: form = "(unknown), 'Xt"; break;
   1174         }
   1175         break;
   1176       }
   1177     }
   1178   } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
   1179     DCHECK(instr->Mask(SystemHintMask) == HINT);
   1180     switch (instr->ImmHint()) {
   1181       case NOP: {
   1182         mnemonic = "nop";
   1183         form = NULL;
   1184         break;
   1185       }
   1186     }
   1187   } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
   1188     switch (instr->Mask(MemBarrierMask)) {
   1189       case DMB: {
   1190         mnemonic = "dmb";
   1191         form = "'M";
   1192         break;
   1193       }
   1194       case DSB: {
   1195         mnemonic = "dsb";
   1196         form = "'M";
   1197         break;
   1198       }
   1199       case ISB: {
   1200         mnemonic = "isb";
   1201         form = NULL;
   1202         break;
   1203       }
   1204     }
   1205   }
   1206 
   1207   Format(instr, mnemonic, form);
   1208 }
   1209 
   1210 
   1211 void Disassembler::VisitException(Instruction* instr) {
   1212   const char *mnemonic = "unimplemented";
   1213   const char *form = "'IDebug";
   1214 
   1215   switch (instr->Mask(ExceptionMask)) {
   1216     case HLT: mnemonic = "hlt"; break;
   1217     case BRK: mnemonic = "brk"; break;
   1218     case SVC: mnemonic = "svc"; break;
   1219     case HVC: mnemonic = "hvc"; break;
   1220     case SMC: mnemonic = "smc"; break;
   1221     case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
   1222     case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
   1223     case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
   1224     default: form = "(Exception)";
   1225   }
   1226   Format(instr, mnemonic, form);
   1227 }
   1228 
   1229 
   1230 void Disassembler::VisitUnimplemented(Instruction* instr) {
   1231   Format(instr, "unimplemented", "(Unimplemented)");
   1232 }
   1233 
   1234 
   1235 void Disassembler::VisitUnallocated(Instruction* instr) {
   1236   Format(instr, "unallocated", "(Unallocated)");
   1237 }
   1238 
   1239 
   1240 void Disassembler::ProcessOutput(Instruction* /*instr*/) {
   1241   // The base disasm does nothing more than disassembling into a buffer.
   1242 }
   1243 
   1244 
   1245 void Disassembler::Format(Instruction* instr, const char* mnemonic,
   1246                           const char* format) {
   1247   // TODO(mcapewel) don't think I can use the instr address here - there needs
   1248   //                to be a base address too
   1249   DCHECK(mnemonic != NULL);
   1250   ResetOutput();
   1251   Substitute(instr, mnemonic);
   1252   if (format != NULL) {
   1253     buffer_[buffer_pos_++] = ' ';
   1254     Substitute(instr, format);
   1255   }
   1256   buffer_[buffer_pos_] = 0;
   1257   ProcessOutput(instr);
   1258 }
   1259 
   1260 
   1261 void Disassembler::Substitute(Instruction* instr, const char* string) {
   1262   char chr = *string++;
   1263   while (chr != '\0') {
   1264     if (chr == '\'') {
   1265       string += SubstituteField(instr, string);
   1266     } else {
   1267       buffer_[buffer_pos_++] = chr;
   1268     }
   1269     chr = *string++;
   1270   }
   1271 }
   1272 
   1273 
   1274 int Disassembler::SubstituteField(Instruction* instr, const char* format) {
   1275   switch (format[0]) {
   1276     case 'R':  // Register. X or W, selected by sf bit.
   1277     case 'F':  // FP Register. S or D, selected by type field.
   1278     case 'W':
   1279     case 'X':
   1280     case 'S':
   1281     case 'D': return SubstituteRegisterField(instr, format);
   1282     case 'I': return SubstituteImmediateField(instr, format);
   1283     case 'L': return SubstituteLiteralField(instr, format);
   1284     case 'H': return SubstituteShiftField(instr, format);
   1285     case 'P': return SubstitutePrefetchField(instr, format);
   1286     case 'C': return SubstituteConditionField(instr, format);
   1287     case 'E': return SubstituteExtendField(instr, format);
   1288     case 'A': return SubstitutePCRelAddressField(instr, format);
   1289     case 'B': return SubstituteBranchTargetField(instr, format);
   1290     case 'O': return SubstituteLSRegOffsetField(instr, format);
   1291     case 'M': return SubstituteBarrierField(instr, format);
   1292     default: {
   1293       UNREACHABLE();
   1294       return 1;
   1295     }
   1296   }
   1297 }
   1298 
   1299 
   1300 int Disassembler::SubstituteRegisterField(Instruction* instr,
   1301                                           const char* format) {
   1302   unsigned reg_num = 0;
   1303   unsigned field_len = 2;
   1304   switch (format[1]) {
   1305     case 'd': reg_num = instr->Rd(); break;
   1306     case 'n': reg_num = instr->Rn(); break;
   1307     case 'm': reg_num = instr->Rm(); break;
   1308     case 'a': reg_num = instr->Ra(); break;
   1309     case 't': {
   1310       if (format[2] == '2') {
   1311         reg_num = instr->Rt2();
   1312         field_len = 3;
   1313       } else {
   1314         reg_num = instr->Rt();
   1315       }
   1316       break;
   1317     }
   1318     default: UNREACHABLE();
   1319   }
   1320 
   1321   // Increase field length for registers tagged as stack.
   1322   if (format[2] == 's') {
   1323     field_len = 3;
   1324   }
   1325 
   1326   char reg_type;
   1327   if (format[0] == 'R') {
   1328     // Register type is R: use sf bit to choose X and W.
   1329     reg_type = instr->SixtyFourBits() ? 'x' : 'w';
   1330   } else if (format[0] == 'F') {
   1331     // Floating-point register: use type field to choose S or D.
   1332     reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
   1333   } else {
   1334     // Register type is specified. Make it lower case.
   1335     reg_type = format[0] + 0x20;
   1336   }
   1337 
   1338   if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
   1339     // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
   1340 
   1341     // Filter special registers
   1342     if ((reg_type == 'x') && (reg_num == 27)) {
   1343       AppendToOutput("cp");
   1344     } else if ((reg_type == 'x') && (reg_num == 28)) {
   1345       AppendToOutput("jssp");
   1346     } else if ((reg_type == 'x') && (reg_num == 29)) {
   1347       AppendToOutput("fp");
   1348     } else if ((reg_type == 'x') && (reg_num == 30)) {
   1349       AppendToOutput("lr");
   1350     } else {
   1351       AppendToOutput("%c%d", reg_type, reg_num);
   1352     }
   1353   } else if (format[2] == 's') {
   1354     // Disassemble w31/x31 as stack pointer wcsp/csp.
   1355     AppendToOutput("%s", (reg_type == 'w') ? "wcsp" : "csp");
   1356   } else {
   1357     // Disassemble w31/x31 as zero register wzr/xzr.
   1358     AppendToOutput("%czr", reg_type);
   1359   }
   1360 
   1361   return field_len;
   1362 }
   1363 
   1364 
   1365 int Disassembler::SubstituteImmediateField(Instruction* instr,
   1366                                            const char* format) {
   1367   DCHECK(format[0] == 'I');
   1368 
   1369   switch (format[1]) {
   1370     case 'M': {  // IMoveImm or IMoveLSL.
   1371       if (format[5] == 'I') {
   1372         uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
   1373         AppendToOutput("#0x%" PRIx64, imm);
   1374       } else {
   1375         DCHECK(format[5] == 'L');
   1376         AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
   1377         if (instr->ShiftMoveWide() > 0) {
   1378           AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
   1379         }
   1380       }
   1381       return 8;
   1382     }
   1383     case 'L': {
   1384       switch (format[2]) {
   1385         case 'L': {  // ILLiteral - Immediate Load Literal.
   1386           AppendToOutput("pc%+" PRId64,
   1387                          instr->ImmLLiteral() << kLoadLiteralScaleLog2);
   1388           return 9;
   1389         }
   1390         case 'S': {  // ILS - Immediate Load/Store.
   1391           if (instr->ImmLS() != 0) {
   1392             AppendToOutput(", #%" PRId64, instr->ImmLS());
   1393           }
   1394           return 3;
   1395         }
   1396         case 'P': {  // ILPx - Immediate Load/Store Pair, x = access size.
   1397           if (instr->ImmLSPair() != 0) {
   1398             // format[3] is the scale value. Convert to a number.
   1399             int scale = format[3] - 0x30;
   1400             AppendToOutput(", #%" PRId64, instr->ImmLSPair() * scale);
   1401           }
   1402           return 4;
   1403         }
   1404         case 'U': {  // ILU - Immediate Load/Store Unsigned.
   1405           if (instr->ImmLSUnsigned() != 0) {
   1406             AppendToOutput(", #%" PRIu64,
   1407                            instr->ImmLSUnsigned() << instr->SizeLS());
   1408           }
   1409           return 3;
   1410         }
   1411       }
   1412     }
   1413     case 'C': {  // ICondB - Immediate Conditional Branch.
   1414       int64_t offset = instr->ImmCondBranch() << 2;
   1415       char sign = (offset >= 0) ? '+' : '-';
   1416       AppendToOutput("#%c0x%" PRIx64, sign, offset);
   1417       return 6;
   1418     }
   1419     case 'A': {  // IAddSub.
   1420       DCHECK(instr->ShiftAddSub() <= 1);
   1421       int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
   1422       AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
   1423       return 7;
   1424     }
   1425     case 'F': {  // IFPSingle, IFPDouble or IFPFBits.
   1426       if (format[3] == 'F') {  // IFPFBits.
   1427         AppendToOutput("#%d", 64 - instr->FPScale());
   1428         return 8;
   1429       } else {
   1430         AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
   1431                        format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
   1432         return 9;
   1433       }
   1434     }
   1435     case 'T': {  // ITri - Immediate Triangular Encoded.
   1436       AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
   1437       return 4;
   1438     }
   1439     case 'N': {  // INzcv.
   1440       int nzcv = (instr->Nzcv() << Flags_offset);
   1441       AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
   1442                                   ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
   1443                                   ((nzcv & CFlag) == 0) ? 'c' : 'C',
   1444                                   ((nzcv & VFlag) == 0) ? 'v' : 'V');
   1445       return 5;
   1446     }
   1447     case 'P': {  // IP - Conditional compare.
   1448       AppendToOutput("#%d", instr->ImmCondCmp());
   1449       return 2;
   1450     }
   1451     case 'B': {  // Bitfields.
   1452       return SubstituteBitfieldImmediateField(instr, format);
   1453     }
   1454     case 'E': {  // IExtract.
   1455       AppendToOutput("#%d", instr->ImmS());
   1456       return 8;
   1457     }
   1458     case 'S': {  // IS - Test and branch bit.
   1459       AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
   1460                             instr->ImmTestBranchBit40());
   1461       return 2;
   1462     }
   1463     case 'D': {  // IDebug - HLT and BRK instructions.
   1464       AppendToOutput("#0x%x", instr->ImmException());
   1465       return 6;
   1466     }
   1467     default: {
   1468       UNREACHABLE();
   1469       return 0;
   1470     }
   1471   }
   1472 }
   1473 
   1474 
   1475 int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
   1476                                                    const char* format) {
   1477   DCHECK((format[0] == 'I') && (format[1] == 'B'));
   1478   unsigned r = instr->ImmR();
   1479   unsigned s = instr->ImmS();
   1480 
   1481   switch (format[2]) {
   1482     case 'r': {  // IBr.
   1483       AppendToOutput("#%d", r);
   1484       return 3;
   1485     }
   1486     case 's': {  // IBs+1 or IBs-r+1.
   1487       if (format[3] == '+') {
   1488         AppendToOutput("#%d", s + 1);
   1489         return 5;
   1490       } else {
   1491         DCHECK(format[3] == '-');
   1492         AppendToOutput("#%d", s - r + 1);
   1493         return 7;
   1494       }
   1495     }
   1496     case 'Z': {  // IBZ-r.
   1497       DCHECK((format[3] == '-') && (format[4] == 'r'));
   1498       unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
   1499                                                         : kWRegSizeInBits;
   1500       AppendToOutput("#%d", reg_size - r);
   1501       return 5;
   1502     }
   1503     default: {
   1504       UNREACHABLE();
   1505       return 0;
   1506     }
   1507   }
   1508 }
   1509 
   1510 
   1511 int Disassembler::SubstituteLiteralField(Instruction* instr,
   1512                                          const char* format) {
   1513   DCHECK(strncmp(format, "LValue", 6) == 0);
   1514   USE(format);
   1515 
   1516   switch (instr->Mask(LoadLiteralMask)) {
   1517     case LDR_w_lit:
   1518     case LDR_x_lit:
   1519     case LDR_s_lit:
   1520     case LDR_d_lit:
   1521       AppendToOutput("(addr 0x%016" PRIxPTR ")", instr->LiteralAddress());
   1522       break;
   1523     default: UNREACHABLE();
   1524   }
   1525 
   1526   return 6;
   1527 }
   1528 
   1529 
   1530 int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
   1531   DCHECK(format[0] == 'H');
   1532   DCHECK(instr->ShiftDP() <= 0x3);
   1533 
   1534   switch (format[1]) {
   1535     case 'D': {  // HDP.
   1536       DCHECK(instr->ShiftDP() != ROR);
   1537     }  // Fall through.
   1538     case 'L': {  // HLo.
   1539       if (instr->ImmDPShift() != 0) {
   1540         const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
   1541         AppendToOutput(", %s #%" PRId64, shift_type[instr->ShiftDP()],
   1542                        instr->ImmDPShift());
   1543       }
   1544       return 3;
   1545     }
   1546     default:
   1547       UNREACHABLE();
   1548       return 0;
   1549   }
   1550 }
   1551 
   1552 
   1553 int Disassembler::SubstituteConditionField(Instruction* instr,
   1554                                            const char* format) {
   1555   DCHECK(format[0] == 'C');
   1556   const char* condition_code[] = { "eq", "ne", "hs", "lo",
   1557                                    "mi", "pl", "vs", "vc",
   1558                                    "hi", "ls", "ge", "lt",
   1559                                    "gt", "le", "al", "nv" };
   1560   int cond;
   1561   switch (format[1]) {
   1562     case 'B': cond = instr->ConditionBranch(); break;
   1563     case 'I': {
   1564       cond = NegateCondition(static_cast<Condition>(instr->Condition()));
   1565       break;
   1566     }
   1567     default: cond = instr->Condition();
   1568   }
   1569   AppendToOutput("%s", condition_code[cond]);
   1570   return 4;
   1571 }
   1572 
   1573 
   1574 int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
   1575                                               const char* format) {
   1576   USE(format);
   1577   DCHECK(strncmp(format, "AddrPCRel", 9) == 0);
   1578 
   1579   int offset = instr->ImmPCRel();
   1580 
   1581   // Only ADR (AddrPCRelByte) is supported.
   1582   DCHECK(strcmp(format, "AddrPCRelByte") == 0);
   1583 
   1584   char sign = '+';
   1585   if (offset < 0) {
   1586     offset = -offset;
   1587     sign = '-';
   1588   }
   1589   AppendToOutput("#%c0x%x (addr %p)", sign, offset,
   1590                  instr->InstructionAtOffset(offset, Instruction::NO_CHECK));
   1591   return 13;
   1592 }
   1593 
   1594 
   1595 int Disassembler::SubstituteBranchTargetField(Instruction* instr,
   1596                                               const char* format) {
   1597   DCHECK(strncmp(format, "BImm", 4) == 0);
   1598 
   1599   int64_t offset = 0;
   1600   switch (format[5]) {
   1601     // BImmUncn - unconditional branch immediate.
   1602     case 'n': offset = instr->ImmUncondBranch(); break;
   1603     // BImmCond - conditional branch immediate.
   1604     case 'o': offset = instr->ImmCondBranch(); break;
   1605     // BImmCmpa - compare and branch immediate.
   1606     case 'm': offset = instr->ImmCmpBranch(); break;
   1607     // BImmTest - test and branch immediate.
   1608     case 'e': offset = instr->ImmTestBranch(); break;
   1609     default: UNREACHABLE();
   1610   }
   1611   offset <<= kInstructionSizeLog2;
   1612   char sign = '+';
   1613   if (offset < 0) {
   1614     sign = '-';
   1615   }
   1616   AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset),
   1617                  instr->InstructionAtOffset(offset), Instruction::NO_CHECK);
   1618   return 8;
   1619 }
   1620 
   1621 
   1622 int Disassembler::SubstituteExtendField(Instruction* instr,
   1623                                         const char* format) {
   1624   DCHECK(strncmp(format, "Ext", 3) == 0);
   1625   DCHECK(instr->ExtendMode() <= 7);
   1626   USE(format);
   1627 
   1628   const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
   1629                                 "sxtb", "sxth", "sxtw", "sxtx" };
   1630 
   1631   // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
   1632   // registers becomes lsl.
   1633   if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
   1634       (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
   1635        (instr->ExtendMode() == UXTX))) {
   1636     if (instr->ImmExtendShift() > 0) {
   1637       AppendToOutput(", lsl #%d", instr->ImmExtendShift());
   1638     }
   1639   } else {
   1640     AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
   1641     if (instr->ImmExtendShift() > 0) {
   1642       AppendToOutput(" #%d", instr->ImmExtendShift());
   1643     }
   1644   }
   1645   return 3;
   1646 }
   1647 
   1648 
   1649 int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
   1650                                              const char* format) {
   1651   DCHECK(strncmp(format, "Offsetreg", 9) == 0);
   1652   const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
   1653                                 "undefined", "undefined", "sxtw", "sxtx" };
   1654   USE(format);
   1655 
   1656   unsigned shift = instr->ImmShiftLS();
   1657   Extend ext = static_cast<Extend>(instr->ExtendMode());
   1658   char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
   1659 
   1660   unsigned rm = instr->Rm();
   1661   if (rm == kZeroRegCode) {
   1662     AppendToOutput("%czr", reg_type);
   1663   } else {
   1664     AppendToOutput("%c%d", reg_type, rm);
   1665   }
   1666 
   1667   // Extend mode UXTX is an alias for shift mode LSL here.
   1668   if (!((ext == UXTX) && (shift == 0))) {
   1669     AppendToOutput(", %s", extend_mode[ext]);
   1670     if (shift != 0) {
   1671       AppendToOutput(" #%d", instr->SizeLS());
   1672     }
   1673   }
   1674   return 9;
   1675 }
   1676 
   1677 
   1678 int Disassembler::SubstitutePrefetchField(Instruction* instr,
   1679                                           const char* format) {
   1680   DCHECK(format[0] == 'P');
   1681   USE(format);
   1682 
   1683   int prefetch_mode = instr->PrefetchMode();
   1684 
   1685   const char* ls = (prefetch_mode & 0x10) ? "st" : "ld";
   1686   int level = (prefetch_mode >> 1) + 1;
   1687   const char* ks = (prefetch_mode & 1) ? "strm" : "keep";
   1688 
   1689   AppendToOutput("p%sl%d%s", ls, level, ks);
   1690   return 6;
   1691 }
   1692 
   1693 int Disassembler::SubstituteBarrierField(Instruction* instr,
   1694                                          const char* format) {
   1695   DCHECK(format[0] == 'M');
   1696   USE(format);
   1697 
   1698   static const char* options[4][4] = {
   1699     { "sy (0b0000)", "oshld", "oshst", "osh" },
   1700     { "sy (0b0100)", "nshld", "nshst", "nsh" },
   1701     { "sy (0b1000)", "ishld", "ishst", "ish" },
   1702     { "sy (0b1100)", "ld", "st", "sy" }
   1703   };
   1704   int domain = instr->ImmBarrierDomain();
   1705   int type = instr->ImmBarrierType();
   1706 
   1707   AppendToOutput("%s", options[domain][type]);
   1708   return 1;
   1709 }
   1710 
   1711 
   1712 void Disassembler::ResetOutput() {
   1713   buffer_pos_ = 0;
   1714   buffer_[buffer_pos_] = 0;
   1715 }
   1716 
   1717 
   1718 void Disassembler::AppendToOutput(const char* format, ...) {
   1719   va_list args;
   1720   va_start(args, format);
   1721   buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
   1722   va_end(args);
   1723 }
   1724 
   1725 
   1726 void PrintDisassembler::ProcessOutput(Instruction* instr) {
   1727   fprintf(stream_, "0x%016" PRIx64 "  %08" PRIx32 "\t\t%s\n",
   1728           reinterpret_cast<uint64_t>(instr), instr->InstructionBits(),
   1729           GetOutput());
   1730 }
   1731 
   1732 } }  // namespace v8::internal
   1733 
   1734 
   1735 namespace disasm {
   1736 
   1737 
   1738 const char* NameConverter::NameOfAddress(byte* addr) const {
   1739   v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
   1740   return tmp_buffer_.start();
   1741 }
   1742 
   1743 
   1744 const char* NameConverter::NameOfConstant(byte* addr) const {
   1745   return NameOfAddress(addr);
   1746 }
   1747 
   1748 
   1749 const char* NameConverter::NameOfCPURegister(int reg) const {
   1750   unsigned ureg = reg;  // Avoid warnings about signed/unsigned comparisons.
   1751   if (ureg >= v8::internal::kNumberOfRegisters) {
   1752     return "noreg";
   1753   }
   1754   if (ureg == v8::internal::kZeroRegCode) {
   1755     return "xzr";
   1756   }
   1757   v8::internal::SNPrintF(tmp_buffer_, "x%u", ureg);
   1758   return tmp_buffer_.start();
   1759 }
   1760 
   1761 
   1762 const char* NameConverter::NameOfByteCPURegister(int reg) const {
   1763   UNREACHABLE();  // ARM64 does not have the concept of a byte register
   1764   return "nobytereg";
   1765 }
   1766 
   1767 
   1768 const char* NameConverter::NameOfXMMRegister(int reg) const {
   1769   UNREACHABLE();  // ARM64 does not have any XMM registers
   1770   return "noxmmreg";
   1771 }
   1772 
   1773 
   1774 const char* NameConverter::NameInCode(byte* addr) const {
   1775   // The default name converter is called for unknown code, so we will not try
   1776   // to access any memory.
   1777   return "";
   1778 }
   1779 
   1780 
   1781 //------------------------------------------------------------------------------
   1782 
   1783 class BufferDisassembler : public v8::internal::Disassembler {
   1784  public:
   1785   explicit BufferDisassembler(v8::internal::Vector<char> out_buffer)
   1786       : out_buffer_(out_buffer) { }
   1787 
   1788   ~BufferDisassembler() { }
   1789 
   1790   virtual void ProcessOutput(v8::internal::Instruction* instr) {
   1791     v8::internal::SNPrintF(out_buffer_, "%s", GetOutput());
   1792   }
   1793 
   1794  private:
   1795   v8::internal::Vector<char> out_buffer_;
   1796 };
   1797 
   1798 Disassembler::Disassembler(const NameConverter& converter)
   1799     : converter_(converter) {}
   1800 
   1801 
   1802 Disassembler::~Disassembler() { USE(converter_); }
   1803 
   1804 
   1805 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
   1806                                     byte* instr) {
   1807   v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder;
   1808   BufferDisassembler disasm(buffer);
   1809   decoder.AppendVisitor(&disasm);
   1810 
   1811   decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(instr));
   1812   return v8::internal::kInstructionSize;
   1813 }
   1814 
   1815 
   1816 int Disassembler::ConstantPoolSizeAt(byte* instr) {
   1817   return v8::internal::Assembler::ConstantPoolSizeAt(
   1818       reinterpret_cast<v8::internal::Instruction*>(instr));
   1819 }
   1820 
   1821 
   1822 void Disassembler::Disassemble(FILE* file, byte* start, byte* end) {
   1823   v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder;
   1824   v8::internal::PrintDisassembler disasm(file);
   1825   decoder.AppendVisitor(&disasm);
   1826 
   1827   for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) {
   1828     decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc));
   1829   }
   1830 }
   1831 
   1832 }  // namespace disasm
   1833 
   1834 #endif  // V8_TARGET_ARCH_ARM64
   1835