tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WasmSummarizeInsn.cpp (62261B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "wasm/WasmSummarizeInsn.h"
      8 
      9 // for Loongson extension detection
     10 #if defined(JS_CODEGEN_MIPS64)
     11 #  include "jit/mips-shared/Architecture-mips-shared.h"
     12 #endif
     13 
     14 #if defined(JS_CODEGEN_RISCV64)
     15 #  include "jit/riscv64/constant/Constant-riscv64.h"
     16 #endif
     17 
     18 using namespace js::jit;
     19 
     20 using mozilla::Maybe;
     21 using mozilla::Nothing;
     22 using mozilla::Some;
     23 
     24 namespace js {
     25 namespace wasm {
     26 
     27 // Sources of documentation of instruction-set encoding:
     28 //
     29 // Documentation for the ARM instruction sets can be found at
     30 // https://developer.arm.com/documentation/ddi0487/latest.  The documentation
     31 // is vast -- more than 10000 pages.  When looking up an instruction, be sure
     32 // to look in the correct section for the target word size -- AArch64 (arm64)
     33 // and AArch32 (arm32) instructions are listed in different sections.  And for
     34 // AArch32, be sure to look only at the "A<digit> variant/encoding" and not at
     35 // the "T<digit>" ones.  The latter are for Thumb encodings, which we don't
     36 // generate.
     37 //
     38 // The Intel documentation is similarly comprehensive: search for "Intel® 64
     39 // and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1,
     40 // 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4".  It's easy to find.
     41 
     42 #if defined(DEBUG)
     43 
     44 // ===================================================== x86_32 and x86_64 ====
     45 
     46 #  if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
     47 
     48 // Returns true iff a "Mod R/M" byte indicates a memory transaction.
     49 static bool ModRMisM(uint8_t modrm) {
     50  return (modrm & 0b11'000'000) != 0b11'000'000;
     51 }
     52 
     53 // Returns bits 6:4 of a Mod R/M byte, which (for our very limited purposes)
     54 // is sometimes interpreted as an opcode extension.
     55 static uint8_t ModRMmid3(uint8_t modrm) { return (modrm >> 3) & 0b00000111; }
     56 
     57 // Some simple helpers for dealing with (bitsets of) instruction prefixes.
     58 enum Prefix : uint32_t {
     59  PfxLock = 1 << 0,
     60  Pfx66 = 1 << 1,
     61  PfxF2 = 1 << 2,
     62  PfxF3 = 1 << 3,
     63  PfxRexW = 1 << 4,
     64  PfxVexL = 1 << 5
     65 };
     66 static bool isEmpty(uint32_t set) { return set == 0; }
     67 static bool hasAllOf(uint32_t set, uint32_t mustBePresent) {
     68  return (set & mustBePresent) == mustBePresent;
     69 }
     70 static bool hasNoneOf(uint32_t set, uint32_t mustNotBePresent) {
     71  return (set & mustNotBePresent) == 0;
     72 }
     73 static bool hasOnly(uint32_t set, uint32_t onlyTheseMayBePresent) {
     74  return (set & ~onlyTheseMayBePresent) == 0;
     75 }
     76 
     77 // Implied opcode-escape prefixes; these are used for decoding VEX-prefixed
     78 // (AVX) instructions only.  This is a real enumeration, not a bitset.
     79 enum Escape { EscNone, Esc0F, Esc0F38, Esc0F3A };
     80 
     81 Maybe<TrapMachineInsn> SummarizeTrapInstruction(const uint8_t* insn) {
     82  const bool is64bit = sizeof(void*) == 8;
     83 
     84  // First off, use up the prefix bytes, so we wind up pointing `insn` at the
     85  // primary opcode byte, and at the same time accumulate the prefixes in
     86  // `prefixes`.
     87  uint32_t prefixes = 0;
     88 
     89  bool hasREX = false;
     90  bool hasVEX = false;
     91 
     92  // Parse the "legacy" prefixes (only those we care about).  Skip REX on
     93  // 32-bit x86.
     94  while (true) {
     95    if (insn[0] >= 0x40 && insn[0] <= 0x4F && is64bit) {
     96      hasREX = true;
     97      // It has a REX prefix, but is REX.W set?
     98      if (insn[0] >= 0x48) {
     99        prefixes |= PfxRexW;
    100      }
    101      insn++;
    102      continue;
    103    }
    104    if (insn[0] == 0x66) {
    105      prefixes |= Pfx66;
    106      insn++;
    107      continue;
    108    }
    109    if (insn[0] == 0xF0) {
    110      prefixes |= PfxLock;
    111      insn++;
    112      continue;
    113    }
    114    if (insn[0] == 0xF2) {
    115      prefixes |= PfxF2;
    116      insn++;
    117      continue;
    118    }
    119    if (insn[0] == 0xF3) {
    120      prefixes |= PfxF3;
    121      insn++;
    122      continue;
    123    }
    124    if (insn[0] == 0xC4 || insn[0] == 0xC5) {
    125      hasVEX = true;
    126      // And fall through to the `break`, leaving `insn` pointing at the start
    127      // of the VEX prefix.
    128    }
    129    break;
    130  }
    131 
    132  // Throw out some invalid prefix combinations.
    133  if (hasAllOf(prefixes, PfxF2 | PfxF3) || (hasREX && hasVEX)) {
    134    return Nothing();
    135  }
    136 
    137  if (!hasVEX) {
    138    // The instruction has legacy prefixes only.  Deal with all these cases
    139    // first.
    140 
    141    // Determine the data size (in bytes) for "standard form" non-SIMD, non-FP
    142    // instructions whose opcode byte(s) don't directly imply an 8-bit
    143    // operation.  If both REX.W and 0x66 are present then REX.W "wins".
    144    int opSize = 4;
    145    if (prefixes & Pfx66) {
    146      opSize = 2;
    147    }
    148    if (prefixes & PfxRexW) {
    149      MOZ_ASSERT(is64bit);
    150      opSize = 8;
    151    }
    152 
    153    // `insn` should now point at the primary opcode, at least for the cases
    154    // we care about.  Start identifying instructions.  The OP_/OP2_/OP3_
    155    // comments are references to names as declared in Encoding-x86-shared.h.
    156 
    157    // This is the most common trap insn, so deal with it early.  Created by
    158    // MacroAssembler::wasmTrapInstruction.
    159    // OP_2BYTE_ESCAPE OP2_UD2
    160    // 0F 0B = ud2
    161    if (insn[0] == 0x0F && insn[1] == 0x0B && isEmpty(prefixes)) {
    162      return Some(TrapMachineInsn::OfficialUD);
    163    }
    164 
    165    // ==== Atomics
    166 
    167    // This is something of a kludge, but .. if the insn has a LOCK prefix,
    168    // declare it to be TrapMachineInsn::Atomic, regardless of what it
    169    // actually does.  It's good enough for checking purposes.
    170    if (prefixes & PfxLock) {
    171      return Some(TrapMachineInsn::Atomic);
    172    }
    173    // After this point, we can assume that no instruction has a lock prefix.
    174 
    175    // OP_XCHG_GbEb
    176    // OP_XCHG_GvEv
    177    // 86 = XCHG reg8, reg8/mem8.
    178    // 87 = XCHG reg64/32/16, reg64/32/16 / mem64/32/16.
    179    // The memory variants are atomic even though there is no LOCK prefix.
    180    if (insn[0] == 0x86 && ModRMisM(insn[1]) && isEmpty(prefixes)) {
    181      return Some(TrapMachineInsn::Atomic);
    182    }
    183    if (insn[0] == 0x87 && ModRMisM(insn[1]) &&
    184        hasOnly(prefixes, Pfx66 | PfxRexW)) {
    185      return Some(TrapMachineInsn::Atomic);
    186    }
    187 
    188    // ==== Scalar loads and stores
    189 
    190    // OP_MOV_EbGv
    191    // OP_MOV_GvEb
    192    // 88 = MOV src=reg, dst=mem/reg (8 bit int only)
    193    // 8A = MOV src=mem/reg, dst=reg (8 bit int only)
    194    if ((insn[0] == 0x88 || insn[0] == 0x8A) && ModRMisM(insn[1]) &&
    195        isEmpty(prefixes)) {
    196      return Some(insn[0] == 0x88 ? TrapMachineInsn::Store8
    197                                  : TrapMachineInsn::Load8);
    198    }
    199 
    200    // OP_MOV_EvGv
    201    // OP_MOV_GvEv
    202    // 89 = MOV src=reg, dst=mem/reg (64/32/16 bit int only)
    203    // 8B = MOV src=mem/reg, dst=reg (64/32/16 bit int only)
    204    if ((insn[0] == 0x89 || insn[0] == 0x8B) && ModRMisM(insn[1]) &&
    205        hasOnly(prefixes, Pfx66 | PfxRexW)) {
    206      return Some(insn[0] == 0x89 ? TrapMachineInsnForStore(opSize)
    207                                  : TrapMachineInsnForLoad(opSize));
    208    }
    209 
    210    // OP_GROUP11_EvIb GROUP11_MOV
    211    // C6 /0 = MOV src=immediate, dst=mem (8 bit int only)
    212    if (insn[0] == 0xC6 && ModRMisM(insn[1]) && ModRMmid3(insn[1]) == 0 &&
    213        isEmpty(prefixes)) {
    214      return Some(TrapMachineInsn::Store8);
    215    }
    216    // OP_GROUP11_EvIz GROUP11_MOV
    217    // C7 /0 = MOV src=immediate, dst=mem (64/32/16 bit int only)
    218    if (insn[0] == 0xC7 && ModRMisM(insn[1]) && ModRMmid3(insn[1]) == 0 &&
    219        hasOnly(prefixes, Pfx66 | PfxRexW)) {
    220      return Some(TrapMachineInsnForStore(opSize));
    221    }
    222 
    223    // OP_2BYTE_ESCAPE OP2_MOVZX_GvEb
    224    // OP_2BYTE_ESCAPE OP2_MOVSX_GvEb
    225    // 0F B6 = MOVZB{W,L,Q} src=reg/mem, dst=reg (8 -> 16, 32 or 64, int only)
    226    // 0F BE = MOVSB{W,L,Q} src=reg/mem, dst=reg (8 -> 16, 32 or 64, int only)
    227    if (insn[0] == 0x0F && (insn[1] == 0xB6 || insn[1] == 0xBE) &&
    228        ModRMisM(insn[2]) && (opSize == 2 || opSize == 4 || opSize == 8) &&
    229        hasOnly(prefixes, Pfx66 | PfxRexW)) {
    230      return Some(TrapMachineInsn::Load8);
    231    }
    232    // OP_2BYTE_ESCAPE OP2_MOVZX_GvEw
    233    // OP_2BYTE_ESCAPE OP2_MOVSX_GvEw
    234    // 0F B7 = MOVZW{L,Q} src=reg/mem, dst=reg (16 -> 32 or 64, int only)
    235    // 0F BF = MOVSW{L,Q} src=reg/mem, dst=reg (16 -> 32 or 64, int only)
    236    if (insn[0] == 0x0F && (insn[1] == 0xB7 || insn[1] == 0xBF) &&
    237        ModRMisM(insn[2]) && (opSize == 4 || opSize == 8) &&
    238        hasOnly(prefixes, PfxRexW)) {
    239      return Some(TrapMachineInsn::Load16);
    240    }
    241 
    242    // OP_MOVSXD_GvEv
    243    // REX.W 63 = MOVSLQ src=reg32/mem32, dst=reg64
    244    if (hasAllOf(prefixes, PfxRexW) && insn[0] == 0x63 && ModRMisM(insn[1]) &&
    245        hasOnly(prefixes, Pfx66 | PfxRexW)) {
    246      return Some(TrapMachineInsn::Load32);
    247    }
    248 
    249    // ==== SSE{2,3,E3,4} insns
    250 
    251    // OP_2BYTE_ESCAPE OP2_MOVPS_VpsWps
    252    // OP_2BYTE_ESCAPE OP2_MOVPS_WpsVps
    253    // 0F 10 = MOVUPS src=xmm/mem128, dst=xmm
    254    // 0F 11 = MOVUPS src=xmm, dst=xmm/mem128
    255    if (insn[0] == 0x0F && (insn[1] == 0x10 || insn[1] == 0x11) &&
    256        ModRMisM(insn[2]) && hasOnly(prefixes, PfxRexW)) {
    257      return Some(insn[1] == 0x10 ? TrapMachineInsn::Load128
    258                                  : TrapMachineInsn::Store128);
    259    }
    260 
    261    // OP_2BYTE_ESCAPE OP2_MOVLPS_VqEq
    262    // OP_2BYTE_ESCAPE OP2_MOVHPS_VqEq
    263    // 0F 12 = MOVLPS src=xmm64/mem64, dst=xmm
    264    // 0F 16 = MOVHPS src=xmm64/mem64, dst=xmm
    265    if (insn[0] == 0x0F && (insn[1] == 0x12 || insn[1] == 0x16) &&
    266        ModRMisM(insn[2]) && hasOnly(prefixes, PfxRexW)) {
    267      return Some(TrapMachineInsn::Load64);
    268    }
    269 
    270    // OP_2BYTE_ESCAPE OP2_MOVLPS_EqVq
    271    // OP_2BYTE_ESCAPE OP2_MOVHPS_EqVq
    272    // 0F 13 = MOVLPS src=xmm64, dst=xmm64/mem64
    273    // 0F 17 = MOVHPS src=xmm64, dst=xmm64/mem64
    274    if (insn[0] == 0x0F && (insn[1] == 0x13 || insn[1] == 0x17) &&
    275        ModRMisM(insn[2]) && hasOnly(prefixes, PfxRexW)) {
    276      return Some(TrapMachineInsn::Store64);
    277    }
    278 
    279    // PRE_SSE_F2 OP_2BYTE_ESCAPE OP2_MOVSD_VsdWsd
    280    // PRE_SSE_F2 OP_2BYTE_ESCAPE OP2_MOVSD_WsdVsd
    281    // F2 0F 10 = MOVSD src=mem64/xmm64, dst=xmm64
    282    // F2 0F 11 = MOVSD src=xmm64, dst=mem64/xmm64
    283    if (hasAllOf(prefixes, PfxF2) && insn[0] == 0x0F &&
    284        (insn[1] == 0x10 || insn[1] == 0x11) && ModRMisM(insn[2]) &&
    285        hasOnly(prefixes, PfxRexW | PfxF2)) {
    286      return Some(insn[1] == 0x10 ? TrapMachineInsn::Load64
    287                                  : TrapMachineInsn::Store64);
    288    }
    289 
    290    // PRE_SSE_F2 OP_2BYTE_ESCAPE OP2_MOVDDUP_VqWq
    291    // F2 0F 12 = MOVDDUP src=mem64/xmm64, dst=xmm
    292    if (hasAllOf(prefixes, PfxF2) && insn[0] == 0x0F && insn[1] == 0x12 &&
    293        ModRMisM(insn[2]) && hasOnly(prefixes, PfxF2)) {
    294      return Some(TrapMachineInsn::Load64);
    295    }
    296 
    297    // PRE_SSE_F3 OP_2BYTE_ESCAPE OP2_MOVSS_VssWss (name does not exist)
    298    // PRE_SSE_F3 OP_2BYTE_ESCAPE OP2_MOVSS_WssVss (name does not exist)
    299    // F3 0F 10 = MOVSS src=mem32/xmm32, dst=xmm32
    300    // F3 0F 11 = MOVSS src=xmm32, dst=mem32/xmm32
    301    if (hasAllOf(prefixes, PfxF3) && insn[0] == 0x0F &&
    302        (insn[1] == 0x10 || insn[1] == 0x11) && ModRMisM(insn[2]) &&
    303        hasOnly(prefixes, PfxRexW | PfxF3)) {
    304      return Some(insn[1] == 0x10 ? TrapMachineInsn::Load32
    305                                  : TrapMachineInsn::Store32);
    306    }
    307 
    308    // PRE_SSE_F3 OP_2BYTE_ESCAPE OP2_MOVDQ_VdqWdq
    309    // PRE_SSE_F3 OP_2BYTE_ESCAPE OP2_MOVDQ_WdqVdq
    310    // F3 0F 6F = MOVDQU src=mem128/xmm, dst=xmm
    311    // F3 0F 7F = MOVDQU src=xmm, dst=mem128/xmm
    312    if (hasAllOf(prefixes, PfxF3) && insn[0] == 0x0F &&
    313        (insn[1] == 0x6F || insn[1] == 0x7F) && ModRMisM(insn[2]) &&
    314        hasOnly(prefixes, PfxF3)) {
    315      return Some(insn[1] == 0x6F ? TrapMachineInsn::Load128
    316                                  : TrapMachineInsn::Store128);
    317    }
    318 
    319    // PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_3A OP3_PINSRB_VdqEvIb
    320    // 66 0F 3A 20 /r ib = PINSRB $imm8, src=mem8/ireg8, dst=xmm128.  I'd guess
    321    // that REX.W is meaningless here and therefore we should exclude it.
    322    if (hasAllOf(prefixes, Pfx66) && insn[0] == 0x0F && insn[1] == 0x3A &&
    323        insn[2] == 0x20 && ModRMisM(insn[3]) && hasOnly(prefixes, Pfx66)) {
    324      return Some(TrapMachineInsn::Load8);
    325    }
    326    // PRE_SSE_66 OP_2BYTE_ESCAPE OP2_PINSRW
    327    // 66 0F C4 /r ib = PINSRW $imm8, src=mem16/ireg16, dst=xmm128.  REX.W is
    328    // probably meaningless here.
    329    if (hasAllOf(prefixes, Pfx66) && insn[0] == 0x0F && insn[1] == 0xC4 &&
    330        ModRMisM(insn[2]) && hasOnly(prefixes, Pfx66)) {
    331      return Some(TrapMachineInsn::Load16);
    332    }
    333    // PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_3A OP3_INSERTPS_VpsUps
    334    // 66 0F 3A 21 /r ib = INSERTPS $imm8, src=mem32/xmm32, dst=xmm128.
    335    // REX.W is probably meaningless here.
    336    if (hasAllOf(prefixes, Pfx66) && insn[0] == 0x0F && insn[1] == 0x3A &&
    337        insn[2] == 0x21 && ModRMisM(insn[3]) && hasOnly(prefixes, Pfx66)) {
    338      return Some(TrapMachineInsn::Load32);
    339    }
    340 
    341    // PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_3A OP3_PEXTRB_EvVdqIb
    342    // PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_3A OP3_PEXTRW_EwVdqIb
    343    // PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_3A OP3_EXTRACTPS_EdVdqIb
    344    // 66 0F 3A 14 /r ib = PEXTRB src=xmm8, dst=reg8/mem8
    345    // 66 0F 3A 15 /r ib = PEXTRW src=xmm16, dst=reg16/mem16
    346    // 66 0F 3A 17 /r ib = EXTRACTPS src=xmm32, dst=reg32/mem32
    347    // REX.W is probably meaningless here.
    348    if (hasAllOf(prefixes, Pfx66) && insn[0] == 0x0F && insn[1] == 0x3A &&
    349        (insn[2] == 0x14 || insn[2] == 0x15 || insn[2] == 0x17) &&
    350        ModRMisM(insn[3]) && hasOnly(prefixes, Pfx66)) {
    351      return Some(insn[2] == 0x14   ? TrapMachineInsn::Store8
    352                  : insn[2] == 0x15 ? TrapMachineInsn::Store16
    353                                    : TrapMachineInsn::Store32);
    354    }
    355 
    356    // PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVSXBW_VdqWdq
    357    // PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVSXWD_VdqWdq
    358    // PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVSXDQ_VdqWdq
    359    // PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVZXBW_VdqWdq
    360    // PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVZXWD_VdqWdq
    361    // PRE_SSE_66 OP_2BYTE_ESCAPE ESCAPE_38 OP3_PMOVZXDQ_VdqWdq
    362    // 66 0F 38 20 /r = PMOVSXBW src=mem64/xmm64, dst=xmm
    363    // 66 0F 38 23 /r = PMOVSXWD src=mem64/xmm64, dst=xmm
    364    // 66 0F 38 25 /r = PMOVSXDQ src=mem64/xmm64, dst=xmm
    365    // 66 0F 38 30 /r = PMOVZXBW src=mem64/xmm64, dst=xmm
    366    // 66 0F 38 33 /r = PMOVZXWD src=mem64/xmm64, dst=xmm
    367    // 66 0F 38 35 /r = PMOVZXDQ src=mem64/xmm64, dst=xmm
    368    if (hasAllOf(prefixes, Pfx66) && insn[0] == 0x0F && insn[1] == 0x38 &&
    369        (insn[2] == 0x20 || insn[2] == 0x23 || insn[2] == 0x25 ||
    370         insn[2] == 0x30 || insn[2] == 0x33 || insn[2] == 0x35) &&
    371        ModRMisM(insn[3]) && hasOnly(prefixes, Pfx66)) {
    372      return Some(TrapMachineInsn::Load64);
    373    }
    374 
    375    // The insn only has legacy prefixes, and was not identified.
    376    return Nothing();
    377  }
    378 
    379  // We're dealing with a VEX-prefixed insn.  Fish out relevant bits of the
    380  // VEX prefix.  VEX prefixes come in two kinds: a 3-byte prefix, first byte
    381  // 0xC4, which gives us 16 bits of extra data, and a 2-byte prefix, first
    382  // byte 0xC5, which gives us 8 bits of extra data.  The 2-byte variant
    383  // contains a subset of the data that the 3-byte variant does and
    384  // (presumably) is to be used when the default values of the omitted fields
    385  // are correct for the instruction that is encoded.
    386  //
    387  // An instruction can't have both VEX and REX prefixes, because a 3-byte VEX
    388  // prefix specifies everything a REX prefix does, that is, the four bits
    389  // REX.{WRXB} and allowing both to be present would allow conflicting values
    390  // for them.  Of these four bits, we only care about REX.W (as obtained here
    391  // from the VEX prefix).
    392  //
    393  // A VEX prefix can also specify (imply?) the presence of the legacy
    394  // prefixes 66, F2 and F3.  Although the byte sequence we will have parsed
    395  // for this insn doesn't actually contain any of those, we must decode as if
    396  // we had seen them as legacy prefixes.
    397  //
    398  // A VEX prefix can also specify (imply?) the presence of the opcode escape
    399  // byte sequences 0F, 0F38 and 0F3A.  These are collected up into `esc`.
    400  // Again, we must decode as if we had actually seen these, although we
    401  // haven't really.
    402  //
    403  // The VEX prefix also holds various other bits which we ignore, because
    404  // these specify details of registers etc which we don't care about.
    405  MOZ_ASSERT(hasVEX && !hasREX);
    406  MOZ_ASSERT(hasNoneOf(prefixes, PfxRexW));
    407  MOZ_ASSERT(insn[0] == 0xC4 || insn[0] == 0xC5);
    408 
    409  Escape esc = EscNone;
    410 
    411  if (insn[0] == 0xC4) {
    412    // This is a 3-byte VEX prefix (3 bytes including the 0xC4).
    413    switch (insn[1] & 0x1F) {
    414      case 1:
    415        esc = Esc0F;
    416        break;
    417      case 2:
    418        esc = Esc0F38;
    419        break;
    420      case 3:
    421        esc = Esc0F3A;
    422        break;
    423      default:
    424        return Nothing();
    425    }
    426    switch (insn[2] & 3) {
    427      case 0:
    428        break;
    429      case 1:
    430        prefixes |= Pfx66;
    431        break;
    432      case 2:
    433        prefixes |= PfxF3;
    434        break;
    435      case 3:
    436        prefixes |= PfxF2;
    437        break;
    438    }
    439    if (insn[2] & 4) {
    440      // VEX.L distinguishes 128-bit (VEX.L==0) from 256-bit (VEX.L==1)
    441      // operations.
    442      prefixes |= PfxVexL;
    443    }
    444    if ((insn[2] & 0x80) && is64bit) {
    445      // Pull out REX.W, but only on 64-bit targets.  We'll need it for insn
    446      // decoding.  Recall that REX.W == 1 basically means "the
    447      // integer-register (GPR) aspect of this instruction requires a 64-bit
    448      // transaction", so we expect these to be relatively rare, since VEX is
    449      // primary used for SIMD instructions.
    450      prefixes |= PfxRexW;
    451    }
    452    // Step forwards to the primary opcode byte
    453    insn += 3;
    454  } else if (insn[0] == 0xC5) {
    455    // This is a 2-byte VEX prefix (2 bytes including the 0xC5).  Since it has
    456    // only 8 bits of useful payload, it adds less information than an 0xC4
    457    // prefix.
    458    esc = Esc0F;
    459    switch (insn[1] & 3) {
    460      case 0:
    461        break;
    462      case 1:
    463        prefixes |= Pfx66;
    464        break;
    465      case 2:
    466        prefixes |= PfxF3;
    467        break;
    468      case 3:
    469        prefixes |= PfxF2;
    470        break;
    471    }
    472    if (insn[1] & 4) {
    473      prefixes |= PfxVexL;
    474    }
    475    insn += 2;
    476  }
    477 
    478  // This isn't allowed.
    479  if (hasAllOf(prefixes, PfxF2 | PfxF3)) {
    480    return Nothing();
    481  }
    482 
    483  // This is useful for diagnosing decoding failures.
    484  // if (0) {
    485  //   fprintf(stderr, "FAIL  VEX  66=%d,F2=%d,F3=%d,REXW=%d,VEXL=%d esc=%s\n",
    486  //           (prefixes & Pfx66) ? 1 : 0, (prefixes & PfxF2) ? 1 : 0,
    487  //           (prefixes & PfxF3) ? 1 : 0, (prefixes & PfxRexW) ? 1 : 0,
    488  //           (prefixes & PfxVexL) ? 1 : 0,
    489  //           esc == Esc0F3A   ? "0F3A"
    490  //           : esc == Esc0F38 ? "0F38"
    491  //           : esc == Esc0F   ? "0F"
    492  //                            : "none");
    493  // }
    494 
    495  // (vex prefix) OP2_MOVPS_VpsWps
    496  // (vex prefix) OP2_MOVPS_WpsVps
    497  // 66=0,F2=0,F3=0,REXW=0,VEXL=0 esc=0F 10 = VMOVUPS src=xmm/mem128, dst=xmm
    498  // 66=0,F2=0,F3=0,REXW=0,VEXL=0 esc=0F 11 = VMOVUPS src=xmm, dst=xmm/mem128
    499  // REX.W is ignored.
    500  if (hasNoneOf(prefixes, Pfx66 | PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
    501      esc == Esc0F && (insn[0] == 0x10 || insn[0] == 0x11) &&
    502      ModRMisM(insn[1])) {
    503    return Some(insn[0] == 0x10 ? TrapMachineInsn::Load128
    504                                : TrapMachineInsn::Store128);
    505  }
    506 
    507  // (vex prefix) OP2_MOVSD_VsdWsd
    508  // (vex prefix) OP2_MOVSD_WsdVsd
    509  // 66=0,F2=1,F3=0,REXW=0,VEXL=0 esc=0F 10 = VMOVSD src=mem64, dst=xmm
    510  // 66=0,F2=1,F3=0,REXW=0,VEXL=0 esc=0F 11 = VMOVSD src=xmm, dst=mem64
    511  // REX.W and VEX.L are ignored.
    512  if (hasAllOf(prefixes, PfxF2) &&
    513      hasNoneOf(prefixes, Pfx66 | PfxF3 | PfxRexW | PfxVexL) && esc == Esc0F &&
    514      (insn[0] == 0x10 || insn[0] == 0x11) && ModRMisM(insn[1])) {
    515    return Some(insn[0] == 0x10 ? TrapMachineInsn::Load64
    516                                : TrapMachineInsn::Store64);
    517  }
    518 
    519  // (vex prefix) OP2_MOVSS_VssWss (name does not exist)
    520  // (vex prefix) OP2_MOVSS_WssVss (name does not exist)
    521  // 66=0,F2=0,F3=1,REXW=0,VEXL=0 esc=0F 10 = VMOVSS src=mem32, dst=xmm
    522  // 66=0,F2=0,F3=1,REXW=0,VEXL=0 esc=0F 11 = VMOVSS src=xmm, dst=mem32
    523  // REX.W and VEX.L are ignored.
    524  if (hasAllOf(prefixes, PfxF3) &&
    525      hasNoneOf(prefixes, Pfx66 | PfxF2 | PfxRexW | PfxVexL) && esc == Esc0F &&
    526      (insn[0] == 0x10 || insn[0] == 0x11) && ModRMisM(insn[1])) {
    527    return Some(insn[0] == 0x10 ? TrapMachineInsn::Load32
    528                                : TrapMachineInsn::Store32);
    529  }
    530 
    531  // (vex prefix) OP2_MOVDDUP_VqWq
    532  // 66=0,F2=1,F3=0,REXW=0,VEXL=0 esc=0F 12 = VMOVDDUP src=xmm/m64, dst=xmm
    533  // REX.W is ignored.
    534  if (hasAllOf(prefixes, PfxF2) &&
    535      hasNoneOf(prefixes, Pfx66 | PfxF3 | PfxRexW | PfxVexL) && esc == Esc0F &&
    536      insn[0] == 0x12 && ModRMisM(insn[1])) {
    537    return Some(TrapMachineInsn::Load64);
    538  }
    539 
    540  // (vex prefix) OP2_MOVLPS_EqVq
    541  // (vex prefix) OP2_MOVHPS_EqVq
    542  // 66=0,F2=0,F3=0,REXW=0,VEXL=0 esc=0F 13 = VMOVLPS src=xmm, dst=mem64
    543  // 66=0,F2=0,F3=0,REXW=0,VEXL=0 esc=0F 17 = VMOVHPS src=xmm, dst=mem64
    544  // REX.W is ignored.  These do a 64-bit mem transaction despite the 'S' in
    545  // the name, because a pair of float32s are transferred.
    546  if (hasNoneOf(prefixes, Pfx66 | PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
    547      esc == Esc0F && (insn[0] == 0x13 || insn[0] == 0x17) &&
    548      ModRMisM(insn[1])) {
    549    return Some(TrapMachineInsn::Store64);
    550  }
    551 
    552  // (vex prefix) OP2_MOVDQ_VdqWdq
    553  // (vex prefix) OP2_MOVDQ_WdqVdq
    554  // 66=0,F2=0,F3=1,REXW=0,VEXL=0 esc=0F 6F = VMOVDQU src=xmm/mem128, dst=xmm
    555  // 66=0,F2=0,F3=1,REXW=0,VEXL=0 esc=0F 7F = VMOVDQU src=xmm, dst=xmm/mem128
    556  // REX.W is ignored.
    557  if (hasAllOf(prefixes, PfxF3) &&
    558      hasNoneOf(prefixes, Pfx66 | PfxF2 | PfxRexW | PfxVexL) && esc == Esc0F &&
    559      (insn[0] == 0x6F || insn[0] == 0x7F) && ModRMisM(insn[1])) {
    560    return Some(insn[0] == 0x6F ? TrapMachineInsn::Load128
    561                                : TrapMachineInsn::Store128);
    562  }
    563 
    564  // (vex prefix) OP2_PINSRW
    565  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=OF C4
    566  //                                   = PINSRW src=ireg/mem16,src=xmm,dst=xmm
    567  // REX.W is ignored.
    568  if (hasAllOf(prefixes, Pfx66) &&
    569      hasNoneOf(prefixes, PfxF2 | PfxF3 | PfxRexW | PfxVexL) && esc == Esc0F &&
    570      insn[0] == 0xC4 && ModRMisM(insn[1])) {
    571    return Some(TrapMachineInsn::Load16);
    572  }
    573 
    574  // (vex prefix) OP3_PMOVSXBW_VdqWdq
    575  // (vex prefix) OP3_PMOVSXWD_VdqWdq
    576  // (vex prefix) OP3_PMOVSXDQ_VdqWdq
    577  // (vex prefix) OP3_PMOVZXBW_VdqWdq
    578  // (vex prefix) OP3_PMOVZXWD_VdqWdq
    579  // (vex prefix) OP3_PMOVZXDQ_VdqWdq
    580  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 20 = VPMOVSXBW src=xmm/m64, dst=xmm
    581  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 23 = VPMOVSXWD src=xmm/m64, dst=xmm
    582  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 25 = VPMOVSXDQ src=xmm/m64, dst=xmm
    583  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 30 = VPMOVZXBW src=xmm/m64, dst=xmm
    584  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 33 = VPMOVZXWD src=xmm/m64, dst=xmm
    585  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 35 = VPMOVZXDQ src=xmm/m64, dst=xmm
    586  // REX.W is ignored.
    587  if (hasAllOf(prefixes, Pfx66) &&
    588      hasNoneOf(prefixes, PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
    589      esc == Esc0F38 &&
    590      (insn[0] == 0x20 || insn[0] == 0x23 || insn[0] == 0x25 ||
    591       insn[0] == 0x30 || insn[0] == 0x33 || insn[0] == 0x35) &&
    592      ModRMisM(insn[1])) {
    593    return Some(TrapMachineInsn::Load64);
    594  }
    595 
    596  // (vex prefix) OP3_VBROADCASTB_VxWx
    597  // (vex prefix) OP3_VBROADCASTW_VxWx
    598  // (vex prefix) OP3_VBROADCASTSS_VxWd
    599  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 78
    600  //                                   = VPBROADCASTB src=xmm8/mem8, dst=xmm
    601  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 79
    602  //                                   = VPBROADCASTW src=xmm16/mem16, dst=xmm
    603  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F38 18
    604  //                                   = VBROADCASTSS src=m32, dst=xmm
    605  // VPBROADCASTB/W require REX.W == 0; VBROADCASTSS ignores REX.W.
    606  if (hasAllOf(prefixes, Pfx66) &&
    607      hasNoneOf(prefixes, PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
    608      esc == Esc0F38 &&
    609      (insn[0] == 0x78 || insn[0] == 0x79 || insn[0] == 0x18) &&
    610      ModRMisM(insn[1])) {
    611    return Some(insn[0] == 0x78   ? TrapMachineInsn::Load8
    612                : insn[0] == 0x79 ? TrapMachineInsn::Load16
    613                                  : TrapMachineInsn::Load32);
    614  }
    615 
    616  // (vex prefix) OP3_PEXTRB_EvVdqIb
    617  // (vex prefix) OP3_PEXTRW_EwVdqIb
    618  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F3A 14 = VPEXTRB src=xmm, dst=ireg/mem8
    619  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F3A 15 = VPEXTRW src=xmm, dst=ireg/mem16
    620  // These require REX.W == 0.
    621  if (hasAllOf(prefixes, Pfx66) &&
    622      hasNoneOf(prefixes, PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
    623      esc == Esc0F3A && (insn[0] == 0x14 || insn[0] == 0x15) &&
    624      ModRMisM(insn[1])) {
    625    return Some(insn[0] == 0x14 ? TrapMachineInsn::Store8
    626                                : TrapMachineInsn::Store16);
    627  }
    628 
    629  // (vex prefix) OP3_EXTRACTPS_EdVdqIb
    630  // 66=1,F2=0,F3=0,REXW=0,VEXL=0 esc=0F3A 17
    631  //                                   = VEXTRACTPS src=xmm, dst=ireg/mem32
    632  // REX.W is ignored.
    633  if (hasAllOf(prefixes, Pfx66) &&
    634      hasNoneOf(prefixes, PfxF2 | PfxF3 | PfxRexW | PfxVexL) &&
    635      esc == Esc0F3A && insn[0] == 0x17 && ModRMisM(insn[1])) {
    636    return Some(TrapMachineInsn::Store32);
    637  }
    638 
    639  // The instruction was not identified.
    640  return Nothing();
    641 }
    642 
    643 // ================================================================= arm64 ====
    644 
    645 #  elif defined(JS_CODEGEN_ARM64)
    646 
    647 Maybe<TrapMachineInsn> SummarizeTrapInstruction(const uint8_t* insnAddr) {
    648  // Check instruction alignment.
    649  MOZ_ASSERT(0 == (uintptr_t(insnAddr) & 3));
    650 
    651  const uint32_t insn = *(uint32_t*)insnAddr;
    652 
    653 #    define INSN(_maxIx, _minIx) \
    654      ((insn >> (_minIx)) & ((uint32_t(1) << ((_maxIx) - (_minIx) + 1)) - 1))
    655 
    656  // MacroAssembler::wasmTrapInstruction uses this to create SIGILL.
    657  if (insn == 0xD4A00000) {
    658    return Some(TrapMachineInsn::OfficialUD);
    659  }
    660 
    661  // A note about loads and stores.  Many (perhaps all) integer loads and
    662  // stores use bits 31:30 of the instruction as a size encoding, thusly:
    663  //
    664  //   11 -> 64 bit, 10 -> 32 bit, 01 -> 16 bit, 00 -> 8 bit
    665  //
    666  // It is also very common for corresponding load and store instructions to
    667  // differ by exactly one bit (logically enough).
    668  //
    669  // Meaning of register names:
    670  //
    671  //   Xn      The n-th GPR (all 64 bits), for 0 <= n <= 31
    672  //   Xn|SP   The n-th GPR (all 64 bits), for 0 <= n <= 30, or SP when n == 31
    673  //   Wn      The lower 32 bits of the n-th GPR
    674  //   Qn      All 128 bits of the n-th SIMD register
    675  //   Dn      Lower 64 bits of the n-th SIMD register
    676  //   Sn      Lower 32 bits of the n-th SIMD register
    677 
    678  // Plain and zero-extending loads/stores, reg + offset, scaled
    679  switch (INSN(31, 22)) {
    680    // 11 111 00100 imm12 n t = STR Xt, [Xn|SP, #imm12 * 8]
    681    case 0b11'111'00100:
    682      return Some(TrapMachineInsn::Store64);
    683    // 10 111 00100 imm12 n t = STR Wt, [Xn|SP, #imm12 * 4]
    684    case 0b10'111'00100:
    685      return Some(TrapMachineInsn::Store32);
    686    // 01 111 00100 imm12 n t = STRH Wt, [Xn|SP, #imm12 * 2]
    687    case 0b01'111'00100:
    688      return Some(TrapMachineInsn::Store16);
    689    // 00 111 00100 imm12 n t = STRB Wt, [Xn|SP, #imm12 * 1]
    690    case 0b00'111'00100:
    691      return Some(TrapMachineInsn::Store8);
    692    // 11 111 00101 imm12 n t = LDR Xt, [Xn|SP, #imm12 * 8]
    693    case 0b11'111'00101:
    694      return Some(TrapMachineInsn::Load64);
    695    // 10 111 00101 imm12 n t = LDR Wt, [Xn|SP, #imm12 * 4]
    696    case 0b10'111'00101:
    697      return Some(TrapMachineInsn::Load32);
    698    // 01 111 00101 imm12 n t = LDRH Wt, [Xn|SP, #imm12 * 2]
    699    case 0b01'111'00101:
    700      return Some(TrapMachineInsn::Load16);
    701    // 00 111 00101 imm12 n t = LDRB Wt, [Xn|SP, #imm12 * 1]
    702    case 0b00'111'00101:
    703      return Some(TrapMachineInsn::Load8);
    704  }
    705 
    706  // Plain, sign- and zero-extending loads/stores, reg + offset, unscaled
    707 
    708  if (INSN(11, 10) == 0b00) {
    709    switch (INSN(31, 21)) {
    710      // 11 111 00001 0 imm9 00 n t = LDUR Xt, [Xn|SP, #imm9]
    711      case 0b11'111'00001'0:
    712        return Some(TrapMachineInsn::Load64);
    713      // 10 111 00001 0 imm9 00 n t = LDUR Wt, [Xn|SP, #imm9]
    714      case 0b10'111'00001'0:
    715        return Some(TrapMachineInsn::Load32);
    716      // 01 111 00001 0 imm9 00 n t = LDURH Wt, [Xn|SP, #imm9]
    717      case 0b01'111'00001'0:
    718        return Some(TrapMachineInsn::Load16);
    719      // We do have code to generate LDURB insns, but it appears to not be used.
    720      // 11 111 00000 0 imm9 00 n t = STUR Xt, [Xn|SP, #imm9]
    721      case 0b11'111'00000'0:
    722        return Some(TrapMachineInsn::Store64);
    723      // 10 111 00000 0 imm9 00 n t = STUR Wt, [Xn|SP, #imm9]
    724      case 0b10'111'00000'0:
    725        return Some(TrapMachineInsn::Store32);
    726      // 01 111 00000 0 imm9 00 n t = STURH Wt, [Xn|SP, #imm9]
    727      case 0b01'111'00000'0:
    728        return Some(TrapMachineInsn::Store16);
    729      // STURB missing?
    730      // Sign extending loads:
    731      // 10 111 000 10 0 imm9 00 n t = LDURSW Xt, [Xn|SP, #imm9]
    732      case 0b10'111'000'10'0:
    733        return Some(TrapMachineInsn::Load32);
    734      // 01 111 000 11 0 imm9 00 n t = LDURSH Wt, [Xn|SP, #imm9]
    735      // 01 111 000 10 0 imm9 00 n t = LDURSH Xt, [Xn|SP, #imm9]
    736      case 0b01'111'000'11'0:
    737      case 0b01'111'000'10'0:
    738        return Some(TrapMachineInsn::Load16);
    739    }
    740  }
    741 
    742  // Sign extending loads, reg + offset, scaled
    743 
    744  switch (INSN(31, 22)) {
    745    // 10 111 001 10 imm12 n t = LDRSW Xt, [Xn|SP, #imm12 * 4]
    746    case 0b10'111'001'10:
    747      return Some(TrapMachineInsn::Load32);
    748    // 01 111 001 10 imm12 n t = LDRSH Xt, [Xn|SP, #imm12 * 2]
    749    // 01 111 001 11 imm12 n t = LDRSH Wt, [Xn|SP, #imm12 * 2]
    750    case 0b01'111'001'10:
    751    case 0b01'111'001'11:
    752      return Some(TrapMachineInsn::Load16);
    753    // 00 111 001 10 imm12 n t = LDRSB Xt, [Xn|SP, #imm12 * 1]
    754    // 00 111 001 11 imm12 n t = LDRSB Wt, [Xn|SP, #imm12 * 1]
    755    case 0b00'111'001'10:
    756    case 0b00'111'001'11:
    757      return Some(TrapMachineInsn::Load8);
    758  }
    759 
    760  // Sign extending loads, reg + reg(extended/shifted)
    761 
    762  if (INSN(11, 10) == 0b10) {
    763    switch (INSN(31, 21)) {
    764      // 10 1110001 01 m opt s 10 n t = LDRSW Xt, [Xn|SP, R<m>{ext/sh}]
    765      case 0b10'1110001'01:
    766        return Some(TrapMachineInsn::Load32);
    767      // 01 1110001 01 m opt s 10 n t = LDRSH Xt, [Xn|SP, R<m>{ext/sh}]
    768      case 0b01'1110001'01:
    769        return Some(TrapMachineInsn::Load16);
    770      // 01 1110001 11 m opt s 10 n t = LDRSH Wt, [Xn|SP, R<m>{ext/sh}]
    771      case 0b01'1110001'11:
    772        return Some(TrapMachineInsn::Load16);
    773      // 00 1110001 01 m opt s 10 n t = LDRSB Xt, [Xn|SP, R<m>{ext/sh}]
    774      case 0b00'1110001'01:
    775        return Some(TrapMachineInsn::Load8);
    776      // 00 1110001 11 m opt s 10 n t = LDRSB Wt, [Xn|SP, R<m>{ext/sh}]
    777      case 0b00'1110001'11:
    778        return Some(TrapMachineInsn::Load8);
    779    }
    780  }
    781 
    782  // Plain and zero-extending loads/stores, reg + reg(extended/shifted)
    783 
    784  if (INSN(11, 10) == 0b10) {
    785    switch (INSN(31, 21)) {
    786      // 11 111000001 m opt s 10 n t = STR Xt, [Xn|SP, Rm{ext/sh}]
    787      case 0b11'111000001:
    788        return Some(TrapMachineInsn::Store64);
    789      // 10 111000001 m opt s 10 n t = STR Wt, [Xn|SP, Rm{ext/sh}]
    790      case 0b10'111000001:
    791        return Some(TrapMachineInsn::Store32);
    792      // 01 111000001 m opt s 10 n t = STRH Wt, [Xn|SP, Rm{ext/sh}]
    793      case 0b01'111000001:
    794        return Some(TrapMachineInsn::Store16);
    795      // 00 111000001 m opt s 10 n t = STRB Wt, [Xn|SP, Rm{ext/sh}]
    796      case 0b00'111000001:
    797        return Some(TrapMachineInsn::Store8);
    798      // 11 111000011 m opt s 10 n t = LDR Xt, [Xn|SP, Rm{ext/sh}]
    799      case 0b11'111000011:
    800        return Some(TrapMachineInsn::Load64);
    801      // 10 111000011 m opt s 10 n t = LDR Wt, [Xn|SP, Rm{ext/sh}]
    802      case 0b10'111000011:
    803        return Some(TrapMachineInsn::Load32);
    804      // 01 111000011 m opt s 10 n t = LDRH Wt, [Xn|SP, Rm{ext/sh}]
    805      case 0b01'111000011:
    806        return Some(TrapMachineInsn::Load16);
    807      // 00 111000011 m opt s 10 n t = LDRB Wt, [Xn|SP, Rm{ext/sh}]
    808      case 0b00'111000011:
    809        return Some(TrapMachineInsn::Load8);
    810    }
    811  }
    812 
    813  // SIMD - scalar FP
    814 
    815  switch (INSN(31, 22)) {
    816    // 11 111 101 00 imm12 n t = STR Dt, [Xn|SP + imm12 * 8]
    817    case 0b11'111'101'00:
    818      return Some(TrapMachineInsn::Store64);
    819    // 10 111 101 00 imm12 n t = STR St, [Xn|SP + imm12 * 4]
    820    case 0b10'111'101'00:
    821      return Some(TrapMachineInsn::Store32);
    822    // 11 111 101 01 imm12 n t = LDR Dt, [Xn|SP + imm12 * 8]
    823    case 0b11'111'101'01:
    824      return Some(TrapMachineInsn::Load64);
    825    // 10 111 101 01 imm12 n t = LDR St, [Xn|SP + imm12 * 4]
    826    case 0b10'111'101'01:
    827      return Some(TrapMachineInsn::Load32);
    828  }
    829 
    830  if (INSN(11, 10) == 0b00) {
    831    switch (INSN(31, 21)) {
    832      // 11 111 100 00 0 imm9 00 n t = STUR Dt, [Xn|SP, #imm9]
    833      case 0b11'111'100'00'0:
    834        return Some(TrapMachineInsn::Store64);
    835      // 10 111 100 00 0 imm9 00 n t = STUR St, [Xn|SP, #imm9]
    836      case 0b10'111'100'00'0:
    837        return Some(TrapMachineInsn::Store32);
    838      // 11 111 100 01 0 imm9 00 n t = LDUR Dt, [Xn|SP, #imm9]
    839      case 0b11'111'100'01'0:
    840        return Some(TrapMachineInsn::Load64);
    841      // 10 111 100 01 0 imm9 00 n t = LDUR St, [Xn|SP, #imm9]
    842      case 0b10'111'100'01'0:
    843        return Some(TrapMachineInsn::Load32);
    844    }
    845  }
    846 
    847  if (INSN(11, 10) == 0b10) {
    848    switch (INSN(31, 21)) {
    849      // 11 111100 001 m opt s 10 n t = STR Dt, [Xn|SP, Rm{ext/sh}]
    850      case 0b11'111100'001:
    851        return Some(TrapMachineInsn::Store64);
    852      // 10 111100 001 m opt s 10 n t = STR St, [Xn|SP, Rm{ext/sh}]
    853      case 0b10'111100'001:
    854        return Some(TrapMachineInsn::Store32);
    855      // 11 111100 011 m opt s 10 n t = LDR Dt, [Xn|SP, Rm{ext/sh}]
    856      case 0b11'111100'011:
    857        return Some(TrapMachineInsn::Load64);
    858      // 10 111100 011 m opt s 10 n t = LDR St, [Xn|SP, Rm{ext/sh}]
    859      case 0b10'111100'011:
    860        return Some(TrapMachineInsn::Load32);
    861    }
    862  }
    863 
    864  // SIMD - whole register
    865 
    866  if (INSN(11, 10) == 0b00) {
    867    // 00 111 100 10 0 imm9 00 n t = STUR Qt, [Xn|SP, #imm9]
    868    if (INSN(31, 21) == 0b00'111'100'10'0) {
    869      return Some(TrapMachineInsn::Store128);
    870    }
    871    // 00 111 100 11 0 imm9 00 n t = LDUR Qt, [Xn|SP, #imm9]
    872    if (INSN(31, 21) == 0b00'111'100'11'0) {
    873      return Some(TrapMachineInsn::Load128);
    874    }
    875  }
    876 
    877  // 00 111 101 10 imm12 n t = STR Qt, [Xn|SP + imm12 * 16]
    878  if (INSN(31, 22) == 0b00'111'101'10) {
    879    return Some(TrapMachineInsn::Store128);
    880  }
    881  // 00 111 101 11 imm12 n t = LDR Qt, [Xn|SP + imm12 * 16]
    882  if (INSN(31, 22) == 0b00'111'101'11) {
    883    return Some(TrapMachineInsn::Load128);
    884  }
    885 
    886  if (INSN(11, 10) == 0b10) {
    887    // 00 111100 101 m opt s 10 n t = STR Qt, [Xn|SP, Rm{ext/sh}]
    888    if (INSN(31, 21) == 0b00'111100'101) {
    889      return Some(TrapMachineInsn::Store128);
    890    }
    891    // 00 111100 111 m opt s 10 n t = LDR Qt, [Xn|SP, Rm{ext/sh}]
    892    if (INSN(31, 21) == 0b00'111100'111) {
    893      return Some(TrapMachineInsn::Load128);
    894    }
    895  }
    896 
    897  // Atomics - loads/stores "exclusive" (with reservation) (LL/SC)
    898 
    899  switch (INSN(31, 10)) {
    900    // 11 001000 010 11111 0 11111 n t = LDXR  Xt, [Xn|SP]
    901    case 0b11'001000'010'11111'0'11111:
    902      return Some(TrapMachineInsn::Load64);
    903    // 10 001000 010 11111 0 11111 n t = LDXR  Wt, [Xn|SP]
    904    case 0b10'001000'010'11111'0'11111:
    905      return Some(TrapMachineInsn::Load32);
    906    // 01 001000 010 11111 0 11111 n t = LDXRH Wt, [Xn|SP]
    907    case 0b01'001000'010'11111'0'11111:
    908      return Some(TrapMachineInsn::Load16);
    909    // 00 001000 010 11111 0 11111 n t = LDXRB Wt, [Xn|SP]
    910    case 0b00'001000'010'11111'0'11111:
    911      return Some(TrapMachineInsn::Load8);
    912      // We are never asked to examine store-exclusive instructions, because any
    913      // store-exclusive should be preceded by a load-exclusive instruction of
    914      // the same size and for the same address.  So the TrapSite is omitted for
    915      // the store-exclusive since the load-exclusive will trap first.
    916  }
    917 
    918  // Atomics - atomic memory operations which do (LD- variants) or do not
    919  // (ST-variants) return the original value at the location.
    920 
    921  // 11 111 0000 11 s 0 000 00 n 11111 = STADDL  Xs, [Xn|SP]
    922  // 10 111 0000 11 s 0 000 00 n 11111 = STADDL  Ws, [Xn|SP]
    923  // 01 111 0000 11 s 0 000 00 n 11111 = STADDLH Ws, [Xn|SP]
    924  // 00 111 0000 11 s 0 000 00 n 11111 = STADDLB Ws, [Xn|SP]
    925  // and the same for
    926  // ---------------- 0 001 00 ------- = STCLRL
    927  // ---------------- 0 010 00 ------- = STEORL
    928  // ---------------- 0 011 00 ------- = STSETL
    929  if (INSN(29, 21) == 0b111'0000'11 && INSN(4, 0) == 0b11111) {
    930    switch (INSN(15, 10)) {
    931      case 0b0'000'00:  // STADDL
    932      case 0b0'001'00:  // STCLRL
    933      case 0b0'010'00:  // STEORL
    934      case 0b0'011'00:  // STSETL
    935        return Some(TrapMachineInsn::Atomic);
    936    }
    937  }
    938 
    939  // 11 111 0001 11 s 0 000 00 n t = LDADDAL  Xs, Xt, [Xn|SP]
    940  // 10 111 0001 11 s 0 000 00 n t = LDADDAL  Ws, Wt, [Xn|SP]
    941  // 01 111 0001 11 s 0 000 00 n t = LDADDALH Ws, Wt, [Xn|SP]
    942  // 00 111 0001 11 s 0 000 00 n t = LDADDALB Ws, Wt, [Xn|SP]
    943  // and the same for
    944  // ---------------- 0 001 00 --- = LDCLRAL
    945  // ---------------- 0 010 00 --- = LDEORAL
    946  // ---------------- 0 011 00 --- = LDSETAL
    947  if (INSN(29, 21) == 0b111'0001'11) {
    948    switch (INSN(15, 10)) {
    949      case 0b0'000'00:  // LDADDAL
    950      case 0b0'001'00:  // LDCLRAL
    951      case 0b0'010'00:  // LDEORAL
    952      case 0b0'011'00:  // LDSETAL
    953        return Some(TrapMachineInsn::Atomic);
    954    }
    955  }
    956 
    957  // Atomics -- compare-and-swap and plain swap
    958 
    959  // 11 001000111 s 111111 n t = CASAL  Xs, Xt, [Xn|SP]
    960  // 10 001000111 s 111111 n t = CASAL  Ws, Wt, [Xn|SP]
    961  // 01 001000111 s 111111 n t = CASALH Ws, Wt, [Xn|SP]
    962  // 00 001000111 s 111111 n t = CASALB Ws, Wt, [Xn|SP]
    963  if (INSN(29, 21) == 0b001000111 && INSN(15, 10) == 0b111111) {
    964    return Some(TrapMachineInsn::Atomic);
    965  }
    966 
    967  // 11 11100011 1 s 100000 n t = SWPAL  Xs, Xt, [Xn|SP]
    968  // 10 11100011 1 s 100000 n t = SWPAL  Ws, Wt, [Xn|SP]
    969  // 01 11100011 1 s 100000 n t = SWPALH Ws, Wt, [Xn|SP]
    970  // 00 11100011 1 s 100000 n t = SWPALB Ws, Wt, [Xn|SP]
    971  if (INSN(29, 21) == 0b11100011'1 && INSN(15, 10) == 0b100000) {
    972    return Some(TrapMachineInsn::Atomic);
    973  }
    974 
    975 #    undef INSN
    976 
    977  // The instruction was not identified.
    978 
    979  // This is useful for diagnosing decoding failures.
    980  // if (0) {
    981  //   fprintf(stderr, "insn = ");
    982  //   for (int i = 31; i >= 0; i--) {
    983  //     fprintf(stderr, "%c", ((insn >> i) & 1) ? '1' : '0');
    984  //     if (i < 31 && (i % 4) == 0) fprintf(stderr, " ");
    985  //   }
    986  //   fprintf(stderr, "\n");
    987  // }
    988 
    989  return Nothing();
    990 }
    991 
    992 // =================================================================== arm ====
    993 
    994 #  elif defined(JS_CODEGEN_ARM)
    995 
    996 Maybe<TrapMachineInsn> SummarizeTrapInstruction(const uint8_t* insnAddr) {
    997  // Almost all AArch32 instructions that use the ARM encoding (not Thumb) use
    998  // bits 31:28 as the guarding condition.  Since we do not expect to
    999  // encounter conditional loads or stores, most of the following is hardcoded
   1000  // to check that those bits are 1110 (0xE), which is the "always execute"
   1001  // condition.  An exception is Neon instructions, which are never
   1002  // conditional and so have those bits set to 1111 (0xF).
   1003 
   1004  // Check instruction alignment.
   1005  MOZ_ASSERT(0 == (uintptr_t(insnAddr) & 3));
   1006 
   1007  const uint32_t insn = *(uint32_t*)insnAddr;
   1008 
   1009 #    define INSN(_maxIx, _minIx) \
   1010      ((insn >> (_minIx)) & ((uint32_t(1) << ((_maxIx) - (_minIx) + 1)) - 1))
   1011 
   1012  // MacroAssembler::wasmTrapInstruction uses this to create SIGILL.
   1013  if (insn == 0xE7F000F0) {
   1014    return Some(TrapMachineInsn::OfficialUD);
   1015  }
   1016 
   1017  // 31   27   23   19 15 11
   1018  // cond 0101 U000 Rn Rt imm12 = STR<cond>  Rt, [Rn, +/- #imm12]
   1019  // cond 0101 U001 Rn Rt imm12 = LDR<cond>  Rt, [Rn, +/- #imm12]
   1020  // cond 0101 U100 Rn Rt imm12 = STRB<cond> Rt, [Rn, +/- #imm12]
   1021  // cond 0101 U101 Rn Rt imm12 = LDRB<cond> Rt, [Rn, +/- #imm12]
   1022  // if cond != 1111 and Rn != 1111
   1023  // U = 1 for +, U = 0 for -
   1024  if (INSN(31, 28) == 0b1110  // unconditional
   1025      && INSN(27, 24) == 0b0101 && INSN(19, 16) != 0b1111) {
   1026    switch (INSN(22, 20)) {
   1027      case 0b000:
   1028        return Some(TrapMachineInsn::Store32);
   1029      case 0b001:
   1030        return Some(TrapMachineInsn::Load32);
   1031      case 0b100:
   1032        return Some(TrapMachineInsn::Store8);
   1033      case 0b101:
   1034        return Some(TrapMachineInsn::Load8);
   1035      default:
   1036        break;
   1037    }
   1038  }
   1039 
   1040  // 31   27   23   19 15 11   7    3
   1041  // cond 0001 U100 Rn Rt imm4 1011 imm4 = STRH<cond>  Rt, [Rn +/- #imm8]
   1042  // cond 0001 U101 Rn Rt imm4 1101 imm4 = LDRSB<cond> Rt, [Rn +/- #imm8]
   1043  // cond 0001 U101 Rn Rt imm4 1111 imm4 = LDRSH<cond> Rt, [Rn +/- #imm8]
   1044  // cond 0001 U101 Rn Rt imm4 1011 imm4 = LDRH<cond>  Rt, [Rn +/- #imm8]
   1045  // U = 1 for +, U = 0 for -
   1046  if (INSN(31, 28) == 0b1110  // unconditional
   1047      && INSN(27, 24) == 0b0001 && INSN(22, 21) == 0b10) {
   1048    switch ((INSN(20, 20) << 4) | INSN(7, 4)) {
   1049      case 0b0'1011:
   1050        return Some(TrapMachineInsn::Store16);
   1051      case 0b1'1101:
   1052        return Some(TrapMachineInsn::Load8);
   1053      case 0b1'1111:
   1054        return Some(TrapMachineInsn::Load16);
   1055      case 0b1'1011:
   1056        return Some(TrapMachineInsn::Load16);
   1057      default:
   1058        break;
   1059    }
   1060  }
   1061 
   1062  // clang-format off
   1063  //
   1064  // 31   27   23   19 15 11    6  4 3
   1065  // cond 0111 U000 Rn Rt shimm 00 0 Rm = STR<cond>  Rt, [Rn, +/- Rm, [lsl #shimm]]
   1066  // cond 0111 U100 Rn Rt shimm 00 0 Rm = STRB<cond> Rt, [Rn, +/- Rm, [lsl #shimm]]
   1067  // cond 0111 U001 Rn Rt shimm 00 0 Rm = LDR<cond>  Rt, [Rn, +/- Rm, [lsl #shimm]]
   1068  // cond 0111 U101 Rn Rt shimm 00 0 Rm = LDRB<cond> Rt, [Rn, +/- Rm, [lsl #shimm]]
   1069  // U = 1 for +, U = 0 for -
   1070  //
   1071  // clang-format on
   1072  if (INSN(31, 28) == 0b1110                             // unconditional
   1073      && INSN(27, 24) == 0b0111 && INSN(6, 4) == 0b00'0  // lsl
   1074  ) {
   1075    switch (INSN(22, 20)) {
   1076      case 0b000:
   1077        return Some(TrapMachineInsn::Store32);
   1078      case 0b100:
   1079        return Some(TrapMachineInsn::Store8);
   1080      case 0b001:
   1081        return Some(TrapMachineInsn::Load32);
   1082      case 0b101:
   1083        return Some(TrapMachineInsn::Load8);
   1084      default:
   1085        break;
   1086    }
   1087  }
   1088 
   1089  // 31   27   23   19 15 11   7    3
   1090  // cond 0001 U000 Rn Rt 0000 1011 Rm = STRH<cond>  Rt, [Rn, +/- Rm]
   1091  // cond 0001 U001 Rn Rt 0000 1011 Rm = LDRH<cond>  Rt, [Rn, +/- Rm]
   1092  // cond 0001 U001 Rn Rt 0000 1101 Rm = LDRSB<cond> Rt, [Rn, +/- Rm]
   1093  // cond 0001 U001 Rn Rt 0000 1111 Rm = LDRSH<cond> Rt, [Rn, +/- Rm]
   1094  if (INSN(31, 28) == 0b1110  // unconditional
   1095      && INSN(27, 24) == 0b0001 && INSN(22, 21) == 0b00 &&
   1096      INSN(11, 8) == 0b0000) {
   1097    switch ((INSN(20, 20) << 4) | INSN(7, 4)) {
   1098      case 0b0'1011:
   1099        return Some(TrapMachineInsn::Store16);
   1100      case 0b1'1011:
   1101        return Some(TrapMachineInsn::Load16);
   1102      case 0b1'1101:
   1103        return Some(TrapMachineInsn::Load8);
   1104      case 0b1'1111:
   1105        return Some(TrapMachineInsn::Load16);
   1106      default:
   1107        break;
   1108    }
   1109  }
   1110 
   1111  // 31   27   23   19 15 11   7
   1112  // cond 1101 UD00 Rn Vd 1010 imm8 = VSTR<cond> Sd, [Rn +/- #imm8]
   1113  // cond 1101 UD00 Rn Vd 1011 imm8 = VSTR<cond> Dd, [Rn +/- #imm8]
   1114  // cond 1101 UD01 Rn Vd 1010 imm8 = VLDR<cond> Sd, [Rn +/- #imm8]
   1115  // cond 1101 UD01 Rn Vd 1011 imm8 = VLDR<cond> Dd, [Rn +/- #imm8]
   1116  // U = 1 for +, U = 0 for -
   1117  // D is an extension of Vd (so can be anything)
   1118  if (INSN(31, 28) == 0b1110  // unconditional
   1119      && INSN(27, 24) == 0b1101 && INSN(21, 21) == 0b0) {
   1120    switch ((INSN(20, 20) << 4) | (INSN(11, 8))) {
   1121      case 0b0'1010:
   1122        return Some(TrapMachineInsn::Store32);
   1123      case 0b0'1011:
   1124        return Some(TrapMachineInsn::Store64);
   1125      case 0b1'1010:
   1126        return Some(TrapMachineInsn::Load32);
   1127      case 0b1'1011:
   1128        return Some(TrapMachineInsn::Load64);
   1129      default:
   1130        break;
   1131    }
   1132  }
   1133 
   1134  // 31   27   23   19 15 11   7    3
   1135  // 1111 0100 1D00 Rn Vd 1000 0000 1111 = VST1.32 {Dd[0], [Rn]
   1136  // 1111 0100 1D10 Rn Vd 1000 0000 1111 = VLD1.32 {Dd[0], [Rn]
   1137  if (INSN(31, 23) == 0b1111'0100'1 && INSN(20, 20) == 0 &&
   1138      INSN(11, 0) == 0b1000'0000'1111) {
   1139    return INSN(21, 21) == 1 ? Some(TrapMachineInsn::Load32)
   1140                             : Some(TrapMachineInsn::Store32);
   1141  }
   1142 
   1143  // 31   27   23   19 15 11   7    3
   1144  // 1111 0100 0D00 Rn Vd 0111 1100 1111 = VST1.64 {Dd], [Rn]
   1145  // 1111 0100 0D10 Rn Vd 0111 1100 1111 = VLD1.64 {Dd], [Rn]
   1146  if (INSN(31, 23) == 0b1111'0100'0 && INSN(20, 20) == 0 &&
   1147      INSN(11, 0) == 0b0111'1100'1111) {
   1148    return INSN(21, 21) == 1 ? Some(TrapMachineInsn::Load64)
   1149                             : Some(TrapMachineInsn::Store64);
   1150  }
   1151 
   1152  // 31   27   23   19 15 11   7    3
   1153  // cond 0001 1101 n  t  1111 1001 1111 = LDREXB<cond> Rt, [Rn]
   1154  // cond 0001 1111 n  t  1111 1001 1111 = LDREXH<cond> Rt, [Rn]
   1155  // cond 0001 1001 n  t  1111 1001 1111 = LDREX<cond>  Rt, [Rn]
   1156  // cond 0001 1011 n  t  1111 1001 1111 = LDREXD<cond> Rt, [Rn]
   1157  if (INSN(31, 23) == 0b1110'0001'1 && INSN(11, 0) == 0b1111'1001'1111) {
   1158    switch (INSN(22, 20)) {
   1159      case 0b101:
   1160        return Some(TrapMachineInsn::Load8);
   1161      case 0b111:
   1162        return Some(TrapMachineInsn::Load16);
   1163      case 0b001:
   1164        return Some(TrapMachineInsn::Load32);
   1165      case 0b011:
   1166        return Some(TrapMachineInsn::Load64);
   1167      default:
   1168        break;
   1169    }
   1170  }
   1171 
   1172 #    undef INSN
   1173 
   1174  // The instruction was not identified.
   1175 
   1176  // This is useful for diagnosing decoding failures.
   1177  // if (0) {
   1178  //   fprintf(stderr, "insn = ");
   1179  //   for (int i = 31; i >= 0; i--) {
   1180  //     fprintf(stderr, "%c", ((insn >> i) & 1) ? '1' : '0');
   1181  //     if (i < 31 && (i % 4) == 0) fprintf(stderr, " ");
   1182  //   }
   1183  //   fprintf(stderr, "\n");
   1184  // }
   1185 
   1186  return Nothing();
   1187 }
   1188 
   1189 // =============================================================== riscv64 ====
   1190 
   1191 #  elif defined(JS_CODEGEN_RISCV64)
   1192 
   1193 Maybe<TrapMachineInsn> SummarizeTrapInstruction(const uint8_t* insnAddr) {
   1194  // Check instruction alignment.
   1195  MOZ_ASSERT(0 == (uintptr_t(insnAddr) & 3));
   1196 
   1197  const uint32_t insn = *(uint32_t*)insnAddr;
   1198 
   1199 #    define INSN(_maxIx, _minIx) \
   1200      ((insn >> (_minIx)) & ((uint32_t(1) << ((_maxIx) - (_minIx) + 1)) - 1))
   1201  // MacroAssembler::wasmTrapInstruction uses this to create SIGILL.
   1202  if (insn ==
   1203      (RO_CSRRWI | csr_cycle << kCsrShift | kWasmTrapCode << kRs1Shift)) {
   1204    return Some(TrapMachineInsn::OfficialUD);
   1205  }
   1206 
   1207  if (INSN(6, 0) == STORE) {
   1208    switch (INSN(14, 12)) {
   1209      case 0b011:
   1210        return Some(TrapMachineInsn::Load64);
   1211      case 0b010:
   1212        return Some(TrapMachineInsn::Load32);
   1213      case 0b001:
   1214        return Some(TrapMachineInsn::Load16);
   1215      case 0b000:
   1216        return Some(TrapMachineInsn::Load8);
   1217      default:
   1218        break;
   1219    }
   1220  }
   1221 
   1222  if (INSN(6, 0) == LOAD) {
   1223    switch (INSN(14, 12)) {
   1224      case 0b011:
   1225        return Some(TrapMachineInsn::Store64);
   1226      case 0b010:
   1227        return Some(TrapMachineInsn::Store32);
   1228      case 0b001:
   1229        return Some(TrapMachineInsn::Store16);
   1230      case 0b000:
   1231        return Some(TrapMachineInsn::Store8);
   1232      default:
   1233        break;
   1234    }
   1235  }
   1236 
   1237  if (INSN(6, 0) == LOAD_FP) {
   1238    switch (INSN(14, 12)) {
   1239      case 0b011:
   1240        return Some(TrapMachineInsn::Load64);
   1241      case 0b010:
   1242        return Some(TrapMachineInsn::Load32);
   1243      default:
   1244        break;
   1245    }
   1246  }
   1247 
   1248  if (INSN(6, 0) == STORE_FP) {
   1249    switch (INSN(14, 12)) {
   1250      case 0b011:
   1251        return Some(TrapMachineInsn::Store64);
   1252      case 0b010:
   1253        return Some(TrapMachineInsn::Store32);
   1254      default:
   1255        break;
   1256    }
   1257  }
   1258 
   1259  if (INSN(6, 0) == AMO && INSN(31, 27) == 00010) {
   1260    switch (INSN(14, 12)) {
   1261      case 0b011:
   1262        return Some(TrapMachineInsn::Load64);
   1263      case 0b010:
   1264        return Some(TrapMachineInsn::Load32);
   1265      default:
   1266        break;
   1267    }
   1268  }
   1269 
   1270  if (INSN(6, 0) == AMO && INSN(31, 27) == 00011) {
   1271    switch (INSN(14, 12)) {
   1272      case 0b011:
   1273        return Some(TrapMachineInsn::Store64);
   1274      case 0b010:
   1275        return Some(TrapMachineInsn::Store32);
   1276      default:
   1277        break;
   1278    }
   1279  }
   1280 
   1281 #    undef INSN
   1282 
   1283  return Nothing();
   1284 }
   1285 
   1286 // =========================================================== loongarch64 ====
   1287 
   1288 #  elif defined(JS_CODEGEN_LOONG64)
   1289 
   1290 Maybe<TrapMachineInsn> SummarizeTrapInstruction(const uint8_t* insnAddr) {
   1291  // Check instruction alignment.
   1292  MOZ_ASSERT(0 == (uintptr_t(insnAddr) & 3));
   1293 
   1294  const uint32_t insn = *(uint32_t*)insnAddr;
   1295 
   1296 #    define INSN(_maxIx, _minIx) \
   1297      ((insn >> (_minIx)) & ((uint32_t(1) << ((_maxIx) - (_minIx) + 1)) - 1))
   1298 
   1299  // LoongArch instructions encoding document:
   1300  // https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN#table-of-instruction-encoding
   1301 
   1302  // MacroAssembler::wasmTrapInstruction uses this to create SIGILL.
   1303  // break 0x6
   1304  if (insn == 0x002A0006) {
   1305    return Some(TrapMachineInsn::OfficialUD);
   1306  }
   1307 
   1308  // Loads/stores with reg + offset (si12).
   1309  if (INSN(31, 26) == 0b001010) {
   1310    switch (INSN(25, 22)) {
   1311      // ld.b  rd, rj, si12
   1312      case 0b0000:
   1313        return Some(TrapMachineInsn::Load8);
   1314      // ld.h  rd, rj, si12
   1315      case 0b0001:
   1316        return Some(TrapMachineInsn::Load16);
   1317      // ld.w  rd, rj, si12
   1318      case 0b0010:
   1319        return Some(TrapMachineInsn::Load32);
   1320      // ld.d  rd, rj, si12
   1321      case 0b0011:
   1322        return Some(TrapMachineInsn::Load64);
   1323      // st.b  rd, rj, si12
   1324      case 0b0100:
   1325        return Some(TrapMachineInsn::Store8);
   1326      // st.h  rd, rj, si12
   1327      case 0b0101:
   1328        return Some(TrapMachineInsn::Store16);
   1329      // st.w  rd, rj, si12
   1330      case 0b0110:
   1331        return Some(TrapMachineInsn::Store32);
   1332      // st.d  rd, rj, si12
   1333      case 0b0111:
   1334        return Some(TrapMachineInsn::Store64);
   1335      // ld.bu  rd, rj, si12
   1336      case 0b1000:
   1337        return Some(TrapMachineInsn::Load8);
   1338      // ld.hu  rd, rj, si12
   1339      case 0b1001:
   1340        return Some(TrapMachineInsn::Load16);
   1341      // ld.wu  rd, rj, si12
   1342      case 0b1010:
   1343        return Some(TrapMachineInsn::Load32);
   1344      // preld  hint, rj, si12
   1345      case 0b1011:
   1346        break;
   1347      // fld.s  fd, rj, si12
   1348      case 0b1100:
   1349        return Some(TrapMachineInsn::Load32);
   1350      // fst.s  fd, rj, si12
   1351      case 0b1101:
   1352        return Some(TrapMachineInsn::Store32);
   1353      // fld.d  fd, rj, si12
   1354      case 0b1110:
   1355        return Some(TrapMachineInsn::Load64);
   1356      // fst.s  fd, rj, si12
   1357      case 0b1111:
   1358        return Some(TrapMachineInsn::Store64);
   1359      default:
   1360        break;
   1361    }
   1362  }
   1363 
   1364  // Loads/stores with reg + reg.
   1365  if (INSN(31, 22) == 0b0011100000 && INSN(17, 15) == 0b000) {
   1366    switch (INSN(21, 18)) {
   1367      // ldx.b  rd, rj, rk
   1368      case 0b0000:
   1369        return Some(TrapMachineInsn::Load8);
   1370      // ldx.h  rd, rj, rk
   1371      case 0b0001:
   1372        return Some(TrapMachineInsn::Load16);
   1373      // ldx.w  rd, rj, rk
   1374      case 0b0010:
   1375        return Some(TrapMachineInsn::Load32);
   1376      // ldx.d  rd, rj, rk
   1377      case 0b0011:
   1378        return Some(TrapMachineInsn::Load64);
   1379      // stx.b  rd, rj, rk
   1380      case 0b0100:
   1381        return Some(TrapMachineInsn::Store8);
   1382      // stx.h  rd, rj, rk
   1383      case 0b0101:
   1384        return Some(TrapMachineInsn::Store16);
   1385      // stx.w  rd, rj, rk
   1386      case 0b0110:
   1387        return Some(TrapMachineInsn::Store32);
   1388      // stx.d  rd, rj, rk
   1389      case 0b0111:
   1390        return Some(TrapMachineInsn::Store64);
   1391      // ldx.bu  rd, rj, rk
   1392      case 0b1000:
   1393        return Some(TrapMachineInsn::Load8);
   1394      // ldx.hu  rd, rj, rk
   1395      case 0b1001:
   1396        return Some(TrapMachineInsn::Load16);
   1397      // ldx.wu  rd, rj, rk
   1398      case 0b1010:
   1399        return Some(TrapMachineInsn::Load32);
   1400      // preldx  hint, rj, rk
   1401      case 0b1011:
   1402        break;
   1403      // fldx.s  fd, rj, rk
   1404      case 0b1100:
   1405        return Some(TrapMachineInsn::Load32);
   1406      // fldx.d  fd, rj, rk
   1407      case 0b1101:
   1408        return Some(TrapMachineInsn::Load64);
   1409      // fstx.s  fd, rj, rk
   1410      case 0b1110:
   1411        return Some(TrapMachineInsn::Store32);
   1412      // fstx.d  fd, rj, rk
   1413      case 0b1111:
   1414        return Some(TrapMachineInsn::Store64);
   1415      default:
   1416        break;
   1417    }
   1418  }
   1419 
   1420  // Loads/stores with reg + offset (si14).
   1421  //   1. Atomics - loads/stores "exclusive" (with reservation) (LL/SC)
   1422  //   2. {ld/st}ptr.{w/d}
   1423  if (INSN(31, 27) == 0b00100) {
   1424    switch (INSN(26, 24)) {
   1425      // ll.w  rd, rj, si14
   1426      case 0b000:
   1427        return Some(TrapMachineInsn::Load32);
   1428      // ll.d  rd, rj, si14
   1429      case 0b010:
   1430        return Some(TrapMachineInsn::Load64);
   1431      // ldptr.w  rd, rj, si14
   1432      case 0b100:
   1433        return Some(TrapMachineInsn::Load32);
   1434      // stptr.w  rd, rj, si14
   1435      case 0b101:
   1436        return Some(TrapMachineInsn::Store32);
   1437      // ldptr.d  rd, rj, si14
   1438      case 0b110:
   1439        return Some(TrapMachineInsn::Load64);
   1440      // stptr.d  rd, rj, si14
   1441      case 0b111:
   1442        return Some(TrapMachineInsn::Store64);
   1443      default:
   1444        break;
   1445        // We are never asked to examine store-exclusive instructions, because
   1446        // any store-exclusive should be preceded by a load-exclusive
   1447        // instruction of the same size and for the same address.  So the
   1448        // TrapSite is omitted for the store-exclusive since the load-exclusive
   1449        // will trap first.
   1450    }
   1451  }
   1452 
   1453 #    undef INSN
   1454 
   1455  return Nothing();
   1456 }
   1457 
   1458 // ================================================================ mips64 ====
   1459 
   1460 #  elif defined(JS_CODEGEN_MIPS64)
   1461 
   1462 Maybe<TrapMachineInsn> SummarizeTrapInstruction(const uint8_t* insnAddr) {
   1463  // Check instruction alignment.
   1464  MOZ_ASSERT(0 == (uintptr_t(insnAddr) & 3));
   1465 
   1466  const uint32_t insn = *(uint32_t*)insnAddr;
   1467 
   1468 #    define INSN(_maxIx, _minIx) \
   1469      ((insn >> (_minIx)) & ((uint32_t(1) << ((_maxIx) - (_minIx) + 1)) - 1))
   1470 
   1471  // MIPS64R2 instruction encoding document:
   1472  // https://scc.ustc.edu.cn/_upload/article/files/c6/06/45556c084631b2855f0022175eaf/W020100308600769158777.pdf#G254.1001018
   1473 
   1474  // Loongson GS464 extension:
   1475  // No official encoding document. Refer to binutils-gdb/opcodes/mips-opc.c and
   1476  // https://github.com/FlyGoat/loongson-insn/blob/master/loongson-ext.md
   1477  // instead.
   1478 
   1479  // MacroAssembler::wasmTrapInstruction uses this to create SIGILL.
   1480  // teq zero, zero, 0x6
   1481  if (insn == 0x000001b4) {
   1482    return Some(TrapMachineInsn::OfficialUD);
   1483  }
   1484 
   1485  // MIPS64 Encoding of the Opcode Field of memory access instructions.
   1486  // +--------+--------------------------------------------------------+
   1487  // |  bits  |                          28..26                        |
   1488  // +--------+------+------+------+-------+------+------+------+------+
   1489  // | 31..29 |  000 | 001  | 010  |  011  |  100 |  101 |  110 |  111 |
   1490  // +--------+------+------+------+-------+------+------+------+------+
   1491  // |   010  |      |      |      | COP1X |      |      |      |      |
   1492  // |   011  |      |      |  LDL |  LDR  |      |      |      |      |
   1493  // |   100  |  LB  |  LH  |  LWL |   LW  |  LBU |  LHU |  LWR |  LWU |
   1494  // |   101  |  SB  |  SH  |  SWL |   SW  |  SDL |  SDR |  SWR |      |
   1495  // |   110  |  LL  | LWC1 | LWC2 |       |  LLD | LDC1 | LDC2 |  LD  |
   1496  // |   111  |  SC  | SWC1 | SWC2 |       |  SCD | SDC1 | SDC2 |  SD  |
   1497  // +--------+------+------+------+-------+------+------+------+------+
   1498  // Loongson GS464 Encoding of the Opcode and Function Field of memory access
   1499  // extension instructions.
   1500  // +--------+-------------------------------------------------------+
   1501  // |  bits  |                          2..0                         |
   1502  // +--------+-----+-----+-----+-----+-------+-------+-------+-------+
   1503  // | 31..26 | 000 | 001 | 010 | 011 |  100  |  101  |  110  |  111  |
   1504  // +--------+-----+-----+-----+-----+-------+-------+-------+-------+
   1505  // | 110010 |     |     |     |     |GSLWLC1|GSLWRC1|GSLDLC1|GSLDRC1|
   1506  // | 111010 |     |     |     |     |GSSWLC1|GSSWRC1|GSSDLC1|GSSDRC1|
   1507  // | 110110 |GSLBX|GSLHX|GSLWX|GSLDX|       |       |GSLWXC1|GSLDXC1|
   1508  // | 111110 |GSLBX|GSLHX|GSLWX|GSLDX|       |       |GSSWXC1|GSSDXC1|
   1509  // +--------+-----+-----+-----+-----+-------+-------+-------+-------+
   1510  if (INSN(31, 29) == 0b010) {
   1511    // MIPS64 COP1X Encoding of Function Field of memory access instructions.
   1512    // +--------+-----------------------------------------------------+
   1513    // |  bits  |                          2..0                       |
   1514    // +--------+-------+-------+-----+-----+-----+-------+-----+-----+
   1515    // |  5..3  |  000  |  001  | 010 | 011 | 100 |  101  | 110 | 111 |
   1516    // +--------+-------+-------+-----+-----+-----+-------+-----+-----+
   1517    // |   000  | LWXC1 | LDXC1 |     |     |     | LUXC1 |     |     |
   1518    // |   001  | SWXC1 | SDXC1 |     |     |     | SUXC1 |     |     |
   1519    // +--------+-------+-------+-----+-----+-----+-------+-----+-----+
   1520    switch (INSN(5, 0)) {
   1521      // lwxc1
   1522      case 0b000000:
   1523        return Some(TrapMachineInsn::Load32);
   1524      // ldxc1
   1525      case 0b000001:
   1526      // luxc1
   1527      case 0b000101:
   1528        return Some(TrapMachineInsn::Load64);
   1529      // swxc1
   1530      case 0b001000:
   1531        return Some(TrapMachineInsn::Store32);
   1532      // sdxc1
   1533      case 0b001001:
   1534      // suxc1
   1535      case 0b001101:
   1536        return Some(TrapMachineInsn::Store64);
   1537      default:
   1538        break;
   1539    }
   1540  } else if (INSN(31, 29) == 0b011) {
   1541    switch (INSN(28, 26)) {
   1542      // ldl
   1543      case 0b010:
   1544      // ldr
   1545      case 0b011:
   1546        return Some(TrapMachineInsn::Load64);
   1547      default:
   1548        break;
   1549    }
   1550  } else if (INSN(31, 29) == 0b100) {
   1551    switch (INSN(28, 26)) {
   1552      // lb
   1553      case 0b000:
   1554        return Some(TrapMachineInsn::Load8);
   1555      // lh
   1556      case 0b001:
   1557        return Some(TrapMachineInsn::Load16);
   1558      // lwl
   1559      case 0b010:
   1560      // lw
   1561      case 0b011:
   1562        return Some(TrapMachineInsn::Load32);
   1563      // lbu
   1564      case 0b100:
   1565        return Some(TrapMachineInsn::Load8);
   1566      // lhu
   1567      case 0b101:
   1568        return Some(TrapMachineInsn::Load16);
   1569      // lwr
   1570      case 0b110:
   1571      // lwu
   1572      case 0b111:
   1573        return Some(TrapMachineInsn::Load32);
   1574    }
   1575  } else if (INSN(31, 29) == 0b101) {
   1576    switch (INSN(28, 26)) {
   1577      // sb
   1578      case 0b000:
   1579        return Some(TrapMachineInsn::Store8);
   1580      // sh
   1581      case 0b001:
   1582        return Some(TrapMachineInsn::Store16);
   1583      // swl
   1584      case 0b010:
   1585      // sw
   1586      case 0b011:
   1587        return Some(TrapMachineInsn::Store32);
   1588      // sdl
   1589      case 0b100:
   1590      // sdr
   1591      case 0b101:
   1592        return Some(TrapMachineInsn::Store64);
   1593      // swr
   1594      case 0b110:
   1595        return Some(TrapMachineInsn::Store32);
   1596      // cache
   1597      case 0b111:
   1598        break;
   1599    }
   1600  } else if (INSN(31, 29) == 0b110) {
   1601    switch (INSN(28, 26)) {
   1602      // ll
   1603      case 0b000:
   1604      // lwc1
   1605      case 0b001:
   1606        return Some(TrapMachineInsn::Load32);
   1607      // lwc2
   1608      case 0b010:
   1609        if (jit::isLoongson()) {
   1610          switch (INSN(2, 0)) {
   1611            // gslsl
   1612            case 0b100:
   1613            // gslsr
   1614            case 0b101:
   1615              return Some(TrapMachineInsn::Load32);
   1616            // gsldl
   1617            case 0b110:
   1618            // gsldr
   1619            case 0b111:
   1620              return Some(TrapMachineInsn::Load64);
   1621            // invalid
   1622            default:
   1623              return Nothing();
   1624          }
   1625        }
   1626        return Some(TrapMachineInsn::Load32);
   1627      // pref
   1628      case 0b011:
   1629        break;
   1630      // lld
   1631      case 0b100:
   1632      // ldc1
   1633      case 0b101:
   1634        return Some(TrapMachineInsn::Load64);
   1635      // ldc2
   1636      case 0b110:
   1637        if (jit::isLoongson()) {
   1638          switch (INSN(2, 0)) {
   1639            // gslbx
   1640            case 0b000:
   1641              return Some(TrapMachineInsn::Load8);
   1642            // gslhx
   1643            case 0b001:
   1644              return Some(TrapMachineInsn::Load16);
   1645            // gslwx
   1646            case 0b010:
   1647            // gslwx (float)
   1648            case 0b110:
   1649              return Some(TrapMachineInsn::Load32);
   1650            // gsldx
   1651            case 0b011:
   1652            // gsldx (double)
   1653            case 0b111:
   1654              return Some(TrapMachineInsn::Load64);
   1655            // invalid
   1656            default:
   1657              return Nothing();
   1658          }
   1659        }
   1660        return Some(TrapMachineInsn::Load64);
   1661      // ld
   1662      case 0b111:
   1663        return Some(TrapMachineInsn::Load64);
   1664    }
   1665  } else if (INSN(31, 29) == 0b111) {
   1666    switch (INSN(28, 26)) {
   1667      // sc
   1668      case 0b000:
   1669      // swc1
   1670      case 0b001:
   1671        return Some(TrapMachineInsn::Store32);
   1672      // swc2
   1673      case 0b010:
   1674        if (jit::isLoongson()) {
   1675          switch (INSN(2, 0)) {
   1676            // gsssl
   1677            case 0b100:
   1678            // gsssr
   1679            case 0b101:
   1680              return Some(TrapMachineInsn::Store32);
   1681            // gssdl
   1682            case 0b110:
   1683            // gssdr
   1684            case 0b111:
   1685              return Some(TrapMachineInsn::Store64);
   1686            // invalid
   1687            default:
   1688              return Nothing();
   1689          }
   1690        }
   1691        return Some(TrapMachineInsn::Store32);
   1692      // reserved encoding
   1693      case 0b011:
   1694        break;
   1695      // scd
   1696      case 0b100:
   1697      // sdc1
   1698      case 0b101:
   1699        return Some(TrapMachineInsn::Store64);
   1700      // sdc2
   1701      case 0b110:
   1702        if (jit::isLoongson()) {
   1703          switch (INSN(2, 0)) {
   1704            // gssbx
   1705            case 0b000:
   1706              return Some(TrapMachineInsn::Store8);
   1707            // gsshx
   1708            case 0b001:
   1709              return Some(TrapMachineInsn::Store16);
   1710            // gsswx
   1711            case 0b010:
   1712            // gsswx (float)
   1713            case 0b110:
   1714              return Some(TrapMachineInsn::Store32);
   1715            // gssdx
   1716            case 0b011:
   1717            // gssdx (double)
   1718            case 0b111:
   1719              return Some(TrapMachineInsn::Store64);
   1720            // invalid
   1721            default:
   1722              return Nothing();
   1723          }
   1724        }
   1725        return Some(TrapMachineInsn::Store64);
   1726      // sd
   1727      case 0b111:
   1728        return Some(TrapMachineInsn::Store64);
   1729    }
   1730  }
   1731 
   1732 #    undef INSN
   1733  return Nothing();
   1734 }
   1735 
   1736 // ================================================================== none ====
   1737 
   1738 #  elif defined(JS_CODEGEN_NONE)
   1739 
   1740 Maybe<TrapMachineInsn> SummarizeTrapInstruction(const uint8_t* insnAddr) {
   1741  MOZ_CRASH();
   1742 }
   1743 
   1744 // ================================================================= other ====
   1745 
   1746 #  else
   1747 
   1748 #    error "SummarizeTrapInstruction: not implemented on this architecture"
   1749 
   1750 #  endif  // defined(JS_CODEGEN_*)
   1751 
   1752 #endif  // defined(DEBUG)
   1753 
   1754 }  // namespace wasm
   1755 }  // namespace js