tor-browser

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

Simulator-arm.cpp (155608B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 // Copyright 2012 the V8 project authors. All rights reserved.
      3 // Redistribution and use in source and binary forms, with or without
      4 // modification, are permitted provided that the following conditions are
      5 // met:
      6 //
      7 //     * Redistributions of source code must retain the above copyright
      8 //       notice, this list of conditions and the following disclaimer.
      9 //     * Redistributions in binary form must reproduce the above
     10 //       copyright notice, this list of conditions and the following
     11 //       disclaimer in the documentation and/or other materials provided
     12 //       with the distribution.
     13 //     * Neither the name of Google Inc. nor the names of its
     14 //       contributors may be used to endorse or promote products derived
     15 //       from this software without specific prior written permission.
     16 //
     17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 #include "jit/arm/Simulator-arm.h"
     30 
     31 #include "mozilla/Casting.h"
     32 #include "mozilla/DebugOnly.h"
     33 #include "mozilla/EndianUtils.h"
     34 #include "mozilla/Likely.h"
     35 #include "mozilla/MathAlgorithms.h"
     36 
     37 #include "jit/arm/Assembler-arm.h"
     38 #include "jit/arm/disasm/Constants-arm.h"
     39 #include "jit/AtomicOperations.h"
     40 #include "js/UniquePtr.h"
     41 #include "js/Utility.h"
     42 #include "threading/LockGuard.h"
     43 #include "vm/Float16.h"
     44 #include "vm/JSContext.h"
     45 #include "vm/Runtime.h"
     46 #include "vm/SharedMem.h"
     47 #include "wasm/WasmInstance.h"
     48 #include "wasm/WasmSignalHandlers.h"
     49 
     50 extern "C" {
     51 
     52 MOZ_EXPORT int64_t __aeabi_idivmod(int x, int y) {
     53  // Run-time ABI for the ARM architecture specifies that for |INT_MIN / -1|
     54  // "an implementation is (sic) may return any convenient value, possibly the
     55  // original numerator."
     56  //
     57  // |INT_MIN / -1| traps on x86, which isn't listed as an allowed behavior in
     58  // the ARM docs, so instead follow LLVM and return the numerator. (And zero
     59  // for the remainder.)
     60 
     61  if (x == INT32_MIN && y == -1) {
     62    return uint32_t(x);
     63  }
     64 
     65  uint32_t lo = uint32_t(x / y);
     66  uint32_t hi = uint32_t(x % y);
     67  return (int64_t(hi) << 32) | lo;
     68 }
     69 
     70 MOZ_EXPORT int64_t __aeabi_uidivmod(int x, int y) {
     71  uint32_t lo = uint32_t(x) / uint32_t(y);
     72  uint32_t hi = uint32_t(x) % uint32_t(y);
     73  return (int64_t(hi) << 32) | lo;
     74 }
     75 }
     76 
     77 namespace js {
     78 namespace jit {
     79 
     80 // For decoding load-exclusive and store-exclusive instructions.
     81 namespace excl {
     82 
     83 // Bit positions.
     84 enum {
     85  ExclusiveOpHi = 24,    // Hi bit of opcode field
     86  ExclusiveOpLo = 23,    // Lo bit of opcode field
     87  ExclusiveSizeHi = 22,  // Hi bit of operand size field
     88  ExclusiveSizeLo = 21,  // Lo bit of operand size field
     89  ExclusiveLoad = 20     // Bit indicating load
     90 };
     91 
     92 // Opcode bits for exclusive instructions.
     93 enum { ExclusiveOpcode = 3 };
     94 
     95 // Operand size, Bits(ExclusiveSizeHi,ExclusiveSizeLo).
     96 enum {
     97  ExclusiveWord = 0,
     98  ExclusiveDouble = 1,
     99  ExclusiveByte = 2,
    100  ExclusiveHalf = 3
    101 };
    102 
    103 }  // namespace excl
    104 
    105 // Load/store multiple addressing mode.
    106 enum BlockAddrMode {
    107  // Alias modes for comparison when writeback does not matter.
    108  da_x = (0 | 0 | 0) << 21,  // Decrement after.
    109  ia_x = (0 | 4 | 0) << 21,  // Increment after.
    110  db_x = (8 | 0 | 0) << 21,  // Decrement before.
    111  ib_x = (8 | 4 | 0) << 21,  // Increment before.
    112 };
    113 
    114 // Type of VFP register. Determines register encoding.
    115 enum VFPRegPrecision { kSinglePrecision = 0, kDoublePrecision = 1 };
    116 
    117 enum NeonListType { nlt_1 = 0x7, nlt_2 = 0xA, nlt_3 = 0x6, nlt_4 = 0x2 };
    118 
    119 // Supervisor Call (svc) specific support.
    120 
    121 // Special Software Interrupt codes when used in the presence of the ARM
    122 // simulator.
    123 // svc (formerly swi) provides a 24bit immediate value. Use bits 22:0 for
    124 // standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature.
    125 enum SoftwareInterruptCodes {
    126  kCallRtRedirected = 0x10,  // Transition to C code.
    127  kBreakpoint = 0x20,        // Breakpoint.
    128  kStopCode = 1 << 23        // Stop.
    129 };
    130 
    131 const uint32_t kStopCodeMask = kStopCode - 1;
    132 const uint32_t kMaxStopCode = kStopCode - 1;
    133 
    134 // -----------------------------------------------------------------------------
    135 // Instruction abstraction.
    136 
    137 // The class Instruction enables access to individual fields defined in the ARM
    138 // architecture instruction set encoding as described in figure A3-1.
    139 // Note that the Assembler uses using Instr = int32_t.
    140 //
    141 // Example: Test whether the instruction at ptr does set the condition code
    142 // bits.
    143 //
    144 // bool InstructionSetsConditionCodes(byte* ptr) {
    145 //   Instruction* instr = Instruction::At(ptr);
    146 //   int type = instr->TypeValue();
    147 //   return ((type == 0) || (type == 1)) && instr->hasS();
    148 // }
    149 //
    150 class SimInstruction {
    151 public:
    152  enum { kInstrSize = 4, kPCReadOffset = 8 };
    153 
    154  // Get the raw instruction bits.
    155  inline Instr instructionBits() const {
    156    return *reinterpret_cast<const Instr*>(this);
    157  }
    158 
    159  // Set the raw instruction bits to value.
    160  inline void setInstructionBits(Instr value) {
    161    *reinterpret_cast<Instr*>(this) = value;
    162  }
    163 
    164  // Read one particular bit out of the instruction bits.
    165  inline int bit(int nr) const { return (instructionBits() >> nr) & 1; }
    166 
    167  // Read a bit field's value out of the instruction bits.
    168  inline int bits(int hi, int lo) const {
    169    return (instructionBits() >> lo) & ((2 << (hi - lo)) - 1);
    170  }
    171 
    172  // Read a bit field out of the instruction bits.
    173  inline int bitField(int hi, int lo) const {
    174    return instructionBits() & (((2 << (hi - lo)) - 1) << lo);
    175  }
    176 
    177  // Accessors for the different named fields used in the ARM encoding.
    178  // The naming of these accessor corresponds to figure A3-1.
    179  //
    180  // Two kind of accessors are declared:
    181  // - <Name>Field() will return the raw field, i.e. the field's bits at their
    182  //   original place in the instruction encoding.
    183  //   e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as
    184  //   0xC0810002 conditionField(instr) will return 0xC0000000.
    185  // - <Name>Value() will return the field value, shifted back to bit 0.
    186  //   e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as
    187  //   0xC0810002 conditionField(instr) will return 0xC.
    188 
    189  // Generally applicable fields
    190  inline Assembler::ARMCondition conditionField() const {
    191    return static_cast<Assembler::ARMCondition>(bitField(31, 28));
    192  }
    193  inline int typeValue() const { return bits(27, 25); }
    194  inline int specialValue() const { return bits(27, 23); }
    195 
    196  inline int rnValue() const { return bits(19, 16); }
    197  inline int rdValue() const { return bits(15, 12); }
    198 
    199  inline int coprocessorValue() const { return bits(11, 8); }
    200 
    201  // Support for VFP.
    202  // Vn(19-16) | Vd(15-12) |  Vm(3-0)
    203  inline int vnValue() const { return bits(19, 16); }
    204  inline int vmValue() const { return bits(3, 0); }
    205  inline int vdValue() const { return bits(15, 12); }
    206  inline int nValue() const { return bit(7); }
    207  inline int mValue() const { return bit(5); }
    208  inline int dValue() const { return bit(22); }
    209  inline int rtValue() const { return bits(15, 12); }
    210  inline int pValue() const { return bit(24); }
    211  inline int uValue() const { return bit(23); }
    212  inline int opc1Value() const { return (bit(23) << 2) | bits(21, 20); }
    213  inline int opc2Value() const { return bits(19, 16); }
    214  inline int opc3Value() const { return bits(7, 6); }
    215  inline int szValue() const { return bit(8); }
    216  inline int VLValue() const { return bit(20); }
    217  inline int VCValue() const { return bit(8); }
    218  inline int VAValue() const { return bits(23, 21); }
    219  inline int VBValue() const { return bits(6, 5); }
    220  inline int VFPNRegValue(VFPRegPrecision pre) {
    221    return VFPGlueRegValue(pre, 16, 7);
    222  }
    223  inline int VFPMRegValue(VFPRegPrecision pre) {
    224    return VFPGlueRegValue(pre, 0, 5);
    225  }
    226  inline int VFPDRegValue(VFPRegPrecision pre) {
    227    return VFPGlueRegValue(pre, 12, 22);
    228  }
    229 
    230  // Fields used in Data processing instructions.
    231  inline int opcodeValue() const { return static_cast<ALUOp>(bits(24, 21)); }
    232  inline ALUOp opcodeField() const {
    233    return static_cast<ALUOp>(bitField(24, 21));
    234  }
    235  inline int sValue() const { return bit(20); }
    236 
    237  // With register.
    238  inline int rmValue() const { return bits(3, 0); }
    239  inline ShiftType shifttypeValue() const {
    240    return static_cast<ShiftType>(bits(6, 5));
    241  }
    242  inline int rsValue() const { return bits(11, 8); }
    243  inline int shiftAmountValue() const { return bits(11, 7); }
    244 
    245  // With immediate.
    246  inline int rotateValue() const { return bits(11, 8); }
    247  inline int immed8Value() const { return bits(7, 0); }
    248  inline int immed4Value() const { return bits(19, 16); }
    249  inline int immedMovwMovtValue() const {
    250    return immed4Value() << 12 | offset12Value();
    251  }
    252 
    253  // Fields used in Load/Store instructions.
    254  inline int PUValue() const { return bits(24, 23); }
    255  inline int PUField() const { return bitField(24, 23); }
    256  inline int bValue() const { return bit(22); }
    257  inline int wValue() const { return bit(21); }
    258  inline int lValue() const { return bit(20); }
    259 
    260  // With register uses same fields as Data processing instructions above with
    261  // immediate.
    262  inline int offset12Value() const { return bits(11, 0); }
    263 
    264  // Multiple.
    265  inline int rlistValue() const { return bits(15, 0); }
    266 
    267  // Extra loads and stores.
    268  inline int signValue() const { return bit(6); }
    269  inline int hValue() const { return bit(5); }
    270  inline int immedHValue() const { return bits(11, 8); }
    271  inline int immedLValue() const { return bits(3, 0); }
    272 
    273  // Fields used in Branch instructions.
    274  inline int linkValue() const { return bit(24); }
    275  inline int sImmed24Value() const { return ((instructionBits() << 8) >> 8); }
    276 
    277  // Fields used in Software interrupt instructions.
    278  inline SoftwareInterruptCodes svcValue() const {
    279    return static_cast<SoftwareInterruptCodes>(bits(23, 0));
    280  }
    281 
    282  // Test for special encodings of type 0 instructions (extra loads and
    283  // stores, as well as multiplications).
    284  inline bool isSpecialType0() const { return (bit(7) == 1) && (bit(4) == 1); }
    285 
    286  // Test for miscellaneous instructions encodings of type 0 instructions.
    287  inline bool isMiscType0() const {
    288    return bit(24) == 1 && bit(23) == 0 && bit(20) == 0 && (bit(7) == 0);
    289  }
    290 
    291  // Test for a nop instruction, which falls under type 1.
    292  inline bool isNopType1() const { return bits(24, 0) == 0x0120F000; }
    293 
    294  // Test for a yield instruction, which falls under type 1.
    295  inline bool isYieldType1() const { return bits(24, 0) == 0x0120F001; }
    296 
    297  // Test for a nop instruction, which falls under type 1.
    298  inline bool isCsdbType1() const { return bits(24, 0) == 0x0120F014; }
    299 
    300  // Test for a stop instruction.
    301  inline bool isStop() const {
    302    return typeValue() == 7 && bit(24) == 1 && svcValue() >= kStopCode;
    303  }
    304 
    305  // Test for a udf instruction, which falls under type 3.
    306  inline bool isUDF() const {
    307    return (instructionBits() & 0xfff000f0) == 0xe7f000f0;
    308  }
    309 
    310  // Special accessors that test for existence of a value.
    311  inline bool hasS() const { return sValue() == 1; }
    312  inline bool hasB() const { return bValue() == 1; }
    313  inline bool hasW() const { return wValue() == 1; }
    314  inline bool hasL() const { return lValue() == 1; }
    315  inline bool hasU() const { return uValue() == 1; }
    316  inline bool hasSign() const { return signValue() == 1; }
    317  inline bool hasH() const { return hValue() == 1; }
    318  inline bool hasLink() const { return linkValue() == 1; }
    319 
    320  // Decoding the double immediate in the vmov instruction.
    321  double doubleImmedVmov() const;
    322  // Decoding the float32 immediate in the vmov.f32 instruction.
    323  float float32ImmedVmov() const;
    324 
    325 private:
    326  // Join split register codes, depending on single or double precision.
    327  // four_bit is the position of the least-significant bit of the four
    328  // bit specifier. one_bit is the position of the additional single bit
    329  // specifier.
    330  inline int VFPGlueRegValue(VFPRegPrecision pre, int four_bit, int one_bit) {
    331    if (pre == kSinglePrecision) {
    332      return (bits(four_bit + 3, four_bit) << 1) | bit(one_bit);
    333    }
    334    return (bit(one_bit) << 4) | bits(four_bit + 3, four_bit);
    335  }
    336 
    337  SimInstruction() = delete;
    338  SimInstruction(const SimInstruction& other) = delete;
    339  void operator=(const SimInstruction& other) = delete;
    340 };
    341 
    342 double SimInstruction::doubleImmedVmov() const {
    343  // Reconstruct a double from the immediate encoded in the vmov instruction.
    344  //
    345  //   instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh]
    346  //   double: [aBbbbbbb,bbcdefgh,00000000,00000000,
    347  //            00000000,00000000,00000000,00000000]
    348  //
    349  // where B = ~b. Only the high 16 bits are affected.
    350  uint64_t high16;
    351  high16 = (bits(17, 16) << 4) | bits(3, 0);  // xxxxxxxx,xxcdefgh.
    352  high16 |= (0xff * bit(18)) << 6;            // xxbbbbbb,bbxxxxxx.
    353  high16 |= (bit(18) ^ 1) << 14;              // xBxxxxxx,xxxxxxxx.
    354  high16 |= bit(19) << 15;                    // axxxxxxx,xxxxxxxx.
    355 
    356  uint64_t imm = high16 << 48;
    357  return mozilla::BitwiseCast<double>(imm);
    358 }
    359 
    360 float SimInstruction::float32ImmedVmov() const {
    361  // Reconstruct a float32 from the immediate encoded in the vmov instruction.
    362  //
    363  //   instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh]
    364  //   float32: [aBbbbbbc, defgh000, 00000000, 00000000]
    365  //
    366  // where B = ~b. Only the high 16 bits are affected.
    367  uint32_t imm;
    368  imm = (bits(17, 16) << 23) | (bits(3, 0) << 19);  // xxxxxxxc,defgh000.0.0
    369  imm |= (0x1f * bit(18)) << 25;                    // xxbbbbbx,xxxxxxxx.0.0
    370  imm |= (bit(18) ^ 1) << 30;                       // xBxxxxxx,xxxxxxxx.0.0
    371  imm |= bit(19) << 31;                             // axxxxxxx,xxxxxxxx.0.0
    372 
    373  return mozilla::BitwiseCast<float>(imm);
    374 }
    375 
    376 class CachePage {
    377 public:
    378  static const int LINE_VALID = 0;
    379  static const int LINE_INVALID = 1;
    380  static const int kPageShift = 12;
    381  static const int kPageSize = 1 << kPageShift;
    382  static const int kPageMask = kPageSize - 1;
    383  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
    384  static const int kLineLength = 1 << kLineShift;
    385  static const int kLineMask = kLineLength - 1;
    386 
    387  CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
    388  char* validityByte(int offset) {
    389    return &validity_map_[offset >> kLineShift];
    390  }
    391  char* cachedData(int offset) { return &data_[offset]; }
    392 
    393 private:
    394  char data_[kPageSize];  // The cached data.
    395  static const int kValidityMapSize = kPageSize >> kLineShift;
    396  char validity_map_[kValidityMapSize];  // One byte per line.
    397 };
    398 
    399 // Protects the icache() and redirection() properties of the
    400 // Simulator.
    401 class AutoLockSimulatorCache : public LockGuard<Mutex> {
    402  using Base = LockGuard<Mutex>;
    403 
    404 public:
    405  explicit AutoLockSimulatorCache()
    406      : Base(SimulatorProcess::singleton_->cacheLock_) {}
    407 };
    408 
    409 mozilla::Atomic<size_t, mozilla::ReleaseAcquire>
    410    SimulatorProcess::ICacheCheckingDisableCount(
    411        1);  // Checking is disabled by default.
    412 SimulatorProcess* SimulatorProcess::singleton_ = nullptr;
    413 
    414 int64_t Simulator::StopSimAt = -1L;
    415 
    416 Simulator* Simulator::Create() {
    417  auto sim = MakeUnique<Simulator>();
    418  if (!sim) {
    419    return nullptr;
    420  }
    421 
    422  if (!sim->init()) {
    423    return nullptr;
    424  }
    425 
    426  char* stopAtStr = getenv("ARM_SIM_STOP_AT");
    427  int64_t stopAt;
    428  if (stopAtStr && sscanf(stopAtStr, "%lld", &stopAt) == 1) {
    429    fprintf(stderr, "\nStopping simulation at icount %lld\n", stopAt);
    430    Simulator::StopSimAt = stopAt;
    431  }
    432 
    433  return sim.release();
    434 }
    435 
    436 void Simulator::Destroy(Simulator* sim) { js_delete(sim); }
    437 
    438 void Simulator::disassemble(SimInstruction* instr, size_t n) {
    439 #ifdef JS_DISASM_ARM
    440  disasm::NameConverter converter;
    441  disasm::Disassembler dasm(converter);
    442  disasm::EmbeddedVector<char, disasm::ReasonableBufferSize> buffer;
    443  while (n-- > 0) {
    444    dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(instr));
    445    fprintf(stderr, "  0x%08x  %s\n", uint32_t(instr), buffer.start());
    446    instr = reinterpret_cast<SimInstruction*>(
    447        reinterpret_cast<uint8_t*>(instr) + 4);
    448  }
    449 #endif
    450 }
    451 
    452 void Simulator::disasm(SimInstruction* instr) { disassemble(instr, 1); }
    453 
    454 void Simulator::disasm(SimInstruction* instr, size_t n) {
    455  disassemble(instr, n);
    456 }
    457 
    458 void Simulator::disasm(SimInstruction* instr, size_t m, size_t n) {
    459  disassemble(reinterpret_cast<SimInstruction*>(
    460                  reinterpret_cast<uint8_t*>(instr) - m * 4),
    461              n);
    462 }
    463 
    464 // The ArmDebugger class is used by the simulator while debugging simulated ARM
    465 // code.
    466 class ArmDebugger {
    467 public:
    468  explicit ArmDebugger(Simulator* sim) : sim_(sim) {}
    469 
    470  void stop(SimInstruction* instr);
    471  void debug();
    472 
    473 private:
    474  static const Instr kBreakpointInstr =
    475      (Assembler::AL | (7 * (1 << 25)) | (1 * (1 << 24)) | kBreakpoint);
    476  static const Instr kNopInstr = (Assembler::AL | (13 * (1 << 21)));
    477 
    478  Simulator* sim_;
    479 
    480  int32_t getRegisterValue(int regnum);
    481  double getRegisterPairDoubleValue(int regnum);
    482  void getVFPDoubleRegisterValue(int regnum, double* value);
    483  bool getValue(const char* desc, int32_t* value);
    484  bool getVFPDoubleValue(const char* desc, double* value);
    485 
    486  // Set or delete a breakpoint. Returns true if successful.
    487  bool setBreakpoint(SimInstruction* breakpc);
    488  bool deleteBreakpoint(SimInstruction* breakpc);
    489 
    490  // Undo and redo all breakpoints. This is needed to bracket disassembly and
    491  // execution to skip past breakpoints when run from the debugger.
    492  void undoBreakpoints();
    493  void redoBreakpoints();
    494 };
    495 
    496 void ArmDebugger::stop(SimInstruction* instr) {
    497  // Get the stop code.
    498  uint32_t code = instr->svcValue() & kStopCodeMask;
    499  // Retrieve the encoded address, which comes just after this stop.
    500  char* msg =
    501      *reinterpret_cast<char**>(sim_->get_pc() + SimInstruction::kInstrSize);
    502  // Update this stop description.
    503  if (sim_->isWatchedStop(code) && !sim_->watched_stops_[code].desc) {
    504    sim_->watched_stops_[code].desc = msg;
    505  }
    506  // Print the stop message and code if it is not the default code.
    507  if (code != kMaxStopCode) {
    508    printf("Simulator hit stop %u: %s\n", code, msg);
    509  } else {
    510    printf("Simulator hit %s\n", msg);
    511  }
    512  sim_->set_pc(sim_->get_pc() + 2 * SimInstruction::kInstrSize);
    513  debug();
    514 }
    515 
    516 int32_t ArmDebugger::getRegisterValue(int regnum) {
    517  if (regnum == Registers::pc) {
    518    return sim_->get_pc();
    519  }
    520  return sim_->get_register(regnum);
    521 }
    522 
    523 double ArmDebugger::getRegisterPairDoubleValue(int regnum) {
    524  return sim_->get_double_from_register_pair(regnum);
    525 }
    526 
    527 void ArmDebugger::getVFPDoubleRegisterValue(int regnum, double* out) {
    528  sim_->get_double_from_d_register(regnum, out);
    529 }
    530 
    531 bool ArmDebugger::getValue(const char* desc, int32_t* value) {
    532  Register reg = Register::FromName(desc);
    533  if (reg != InvalidReg) {
    534    *value = getRegisterValue(reg.code());
    535    return true;
    536  }
    537  if (strncmp(desc, "0x", 2) == 0) {
    538    return sscanf(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
    539  }
    540  return sscanf(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1;
    541 }
    542 
    543 bool ArmDebugger::getVFPDoubleValue(const char* desc, double* value) {
    544  FloatRegister reg = FloatRegister::FromCode(FloatRegister::FromName(desc));
    545  if (reg.isInvalid()) {
    546    return false;
    547  }
    548 
    549  if (reg.isSingle()) {
    550    float fval;
    551    sim_->get_float_from_s_register(reg.id(), &fval);
    552    *value = fval;
    553    return true;
    554  }
    555 
    556  sim_->get_double_from_d_register(reg.id(), value);
    557  return true;
    558 }
    559 
    560 bool ArmDebugger::setBreakpoint(SimInstruction* breakpc) {
    561  // Check if a breakpoint can be set. If not return without any side-effects.
    562  if (sim_->break_pc_) {
    563    return false;
    564  }
    565 
    566  // Set the breakpoint.
    567  sim_->break_pc_ = breakpc;
    568  sim_->break_instr_ = breakpc->instructionBits();
    569  // Not setting the breakpoint instruction in the code itself. It will be set
    570  // when the debugger shell continues.
    571  return true;
    572 }
    573 
    574 bool ArmDebugger::deleteBreakpoint(SimInstruction* breakpc) {
    575  if (sim_->break_pc_ != nullptr) {
    576    sim_->break_pc_->setInstructionBits(sim_->break_instr_);
    577  }
    578 
    579  sim_->break_pc_ = nullptr;
    580  sim_->break_instr_ = 0;
    581  return true;
    582 }
    583 
    584 void ArmDebugger::undoBreakpoints() {
    585  if (sim_->break_pc_) {
    586    sim_->break_pc_->setInstructionBits(sim_->break_instr_);
    587  }
    588 }
    589 
    590 void ArmDebugger::redoBreakpoints() {
    591  if (sim_->break_pc_) {
    592    sim_->break_pc_->setInstructionBits(kBreakpointInstr);
    593  }
    594 }
    595 
    596 static char* ReadLine(const char* prompt) {
    597  UniqueChars result;
    598  char line_buf[256];
    599  int offset = 0;
    600  bool keep_going = true;
    601  fprintf(stdout, "%s", prompt);
    602  fflush(stdout);
    603  while (keep_going) {
    604    if (fgets(line_buf, sizeof(line_buf), stdin) == nullptr) {
    605      // fgets got an error. Just give up.
    606      return nullptr;
    607    }
    608    int len = strlen(line_buf);
    609    if (len > 0 && line_buf[len - 1] == '\n') {
    610      // Since we read a new line we are done reading the line. This will
    611      // exit the loop after copying this buffer into the result.
    612      keep_going = false;
    613    }
    614    if (!result) {
    615      // Allocate the initial result and make room for the terminating
    616      // '\0'.
    617      result.reset(js_pod_malloc<char>(len + 1));
    618      if (!result) {
    619        return nullptr;
    620      }
    621    } else {
    622      // Allocate a new result with enough room for the new addition.
    623      int new_len = offset + len + 1;
    624      char* new_result = js_pod_malloc<char>(new_len);
    625      if (!new_result) {
    626        return nullptr;
    627      }
    628      // Copy the existing input into the new array and set the new
    629      // array as the result.
    630      memcpy(new_result, result.get(), offset * sizeof(char));
    631      result.reset(new_result);
    632    }
    633    // Copy the newly read line into the result.
    634    memcpy(result.get() + offset, line_buf, len * sizeof(char));
    635    offset += len;
    636  }
    637 
    638  MOZ_ASSERT(result);
    639  result[offset] = '\0';
    640  return result.release();
    641 }
    642 
    643 void ArmDebugger::debug() {
    644  intptr_t last_pc = -1;
    645  bool done = false;
    646 
    647 #define COMMAND_SIZE 63
    648 #define ARG_SIZE 255
    649 
    650 #define STR(a) #a
    651 #define XSTR(a) STR(a)
    652 
    653  char cmd[COMMAND_SIZE + 1];
    654  char arg1[ARG_SIZE + 1];
    655  char arg2[ARG_SIZE + 1];
    656  char* argv[3] = {cmd, arg1, arg2};
    657 
    658  // Make sure to have a proper terminating character if reaching the limit.
    659  cmd[COMMAND_SIZE] = 0;
    660  arg1[ARG_SIZE] = 0;
    661  arg2[ARG_SIZE] = 0;
    662 
    663  // Undo all set breakpoints while running in the debugger shell. This will
    664  // make them invisible to all commands.
    665  undoBreakpoints();
    666 
    667 #ifndef JS_DISASM_ARM
    668  static bool disasm_warning_printed = false;
    669  if (!disasm_warning_printed) {
    670    printf(
    671        "  No ARM disassembler present.  Enable JS_DISASM_ARM in "
    672        "configure.in.");
    673    disasm_warning_printed = true;
    674  }
    675 #endif
    676 
    677  while (!done && !sim_->has_bad_pc()) {
    678    if (last_pc != sim_->get_pc()) {
    679 #ifdef JS_DISASM_ARM
    680      disasm::NameConverter converter;
    681      disasm::Disassembler dasm(converter);
    682      disasm::EmbeddedVector<char, disasm::ReasonableBufferSize> buffer;
    683      dasm.InstructionDecode(buffer,
    684                             reinterpret_cast<uint8_t*>(sim_->get_pc()));
    685      printf("  0x%08x  %s\n", sim_->get_pc(), buffer.start());
    686 #endif
    687      last_pc = sim_->get_pc();
    688    }
    689    char* line = ReadLine("sim> ");
    690    if (line == nullptr) {
    691      break;
    692    } else {
    693      char* last_input = sim_->lastDebuggerInput();
    694      if (strcmp(line, "\n") == 0 && last_input != nullptr) {
    695        line = last_input;
    696      } else {
    697        // Ownership is transferred to sim_;
    698        sim_->setLastDebuggerInput(line);
    699      }
    700 
    701      // Use sscanf to parse the individual parts of the command line. At the
    702      // moment no command expects more than two parameters.
    703      int argc = sscanf(line,
    704                              "%" XSTR(COMMAND_SIZE) "s "
    705                              "%" XSTR(ARG_SIZE) "s "
    706                              "%" XSTR(ARG_SIZE) "s",
    707                              cmd, arg1, arg2);
    708      if (argc < 0) {
    709        continue;
    710      } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
    711        sim_->instructionDecode(
    712            reinterpret_cast<SimInstruction*>(sim_->get_pc()));
    713        sim_->icount_++;
    714      } else if ((strcmp(cmd, "skip") == 0)) {
    715        sim_->set_pc(sim_->get_pc() + 4);
    716        sim_->icount_++;
    717      } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
    718        // Execute the one instruction we broke at with breakpoints
    719        // disabled.
    720        sim_->instructionDecode(
    721            reinterpret_cast<SimInstruction*>(sim_->get_pc()));
    722        sim_->icount_++;
    723        // Leave the debugger shell.
    724        done = true;
    725      } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
    726        if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) {
    727          int32_t value;
    728          double dvalue;
    729          if (strcmp(arg1, "all") == 0) {
    730            for (uint32_t i = 0; i < Registers::Total; i++) {
    731              value = getRegisterValue(i);
    732              printf("%3s: 0x%08x %10d", Registers::GetName(i), value, value);
    733              if ((argc == 3 && strcmp(arg2, "fp") == 0) && i < 8 &&
    734                  (i % 2) == 0) {
    735                dvalue = getRegisterPairDoubleValue(i);
    736                printf(" (%.16g)\n", dvalue);
    737              } else {
    738                printf("\n");
    739              }
    740            }
    741            for (uint32_t i = 0; i < FloatRegisters::TotalPhys; i++) {
    742              getVFPDoubleRegisterValue(i, &dvalue);
    743              uint64_t as_words = mozilla::BitwiseCast<uint64_t>(dvalue);
    744              printf("%3s: %.16g 0x%08x %08x\n",
    745                     FloatRegister::FromCode(i).name(), dvalue,
    746                     static_cast<uint32_t>(as_words >> 32),
    747                     static_cast<uint32_t>(as_words & 0xffffffff));
    748            }
    749          } else {
    750            if (getValue(arg1, &value)) {
    751              printf("%s: 0x%08x %d \n", arg1, value, value);
    752            } else if (getVFPDoubleValue(arg1, &dvalue)) {
    753              uint64_t as_words = mozilla::BitwiseCast<uint64_t>(dvalue);
    754              printf("%s: %.16g 0x%08x %08x\n", arg1, dvalue,
    755                     static_cast<uint32_t>(as_words >> 32),
    756                     static_cast<uint32_t>(as_words & 0xffffffff));
    757            } else {
    758              printf("%s unrecognized\n", arg1);
    759            }
    760          }
    761        } else {
    762          printf("print <register>\n");
    763        }
    764      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
    765        int32_t* cur = nullptr;
    766        int32_t* end = nullptr;
    767        int next_arg = 1;
    768 
    769        if (strcmp(cmd, "stack") == 0) {
    770          cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
    771        } else {  // "mem"
    772          int32_t value;
    773          if (!getValue(arg1, &value)) {
    774            printf("%s unrecognized\n", arg1);
    775            continue;
    776          }
    777          cur = reinterpret_cast<int32_t*>(value);
    778          next_arg++;
    779        }
    780 
    781        int32_t words;
    782        if (argc == next_arg) {
    783          words = 10;
    784        } else {
    785          if (!getValue(argv[next_arg], &words)) {
    786            words = 10;
    787          }
    788        }
    789        end = cur + words;
    790 
    791        while (cur < end) {
    792          printf("  %p:  0x%08x %10d", cur, *cur, *cur);
    793          printf("\n");
    794          cur++;
    795        }
    796      } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
    797 #ifdef JS_DISASM_ARM
    798        uint8_t* prev = nullptr;
    799        uint8_t* cur = nullptr;
    800        uint8_t* end = nullptr;
    801 
    802        if (argc == 1) {
    803          cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
    804          end = cur + (10 * SimInstruction::kInstrSize);
    805        } else if (argc == 2) {
    806          Register reg = Register::FromName(arg1);
    807          if (reg != InvalidReg || strncmp(arg1, "0x", 2) == 0) {
    808            // The argument is an address or a register name.
    809            int32_t value;
    810            if (getValue(arg1, &value)) {
    811              cur = reinterpret_cast<uint8_t*>(value);
    812              // Disassemble 10 instructions at <arg1>.
    813              end = cur + (10 * SimInstruction::kInstrSize);
    814            }
    815          } else {
    816            // The argument is the number of instructions.
    817            int32_t value;
    818            if (getValue(arg1, &value)) {
    819              cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
    820              // Disassemble <arg1> instructions.
    821              end = cur + (value * SimInstruction::kInstrSize);
    822            }
    823          }
    824        } else {
    825          int32_t value1;
    826          int32_t value2;
    827          if (getValue(arg1, &value1) && getValue(arg2, &value2)) {
    828            cur = reinterpret_cast<uint8_t*>(value1);
    829            end = cur + (value2 * SimInstruction::kInstrSize);
    830          }
    831        }
    832        while (cur < end) {
    833          disasm::NameConverter converter;
    834          disasm::Disassembler dasm(converter);
    835          disasm::EmbeddedVector<char, disasm::ReasonableBufferSize> buffer;
    836 
    837          prev = cur;
    838          cur += dasm.InstructionDecode(buffer, cur);
    839          printf("  0x%08x  %s\n", reinterpret_cast<uint32_t>(prev),
    840                 buffer.start());
    841        }
    842 #endif
    843      } else if (strcmp(cmd, "gdb") == 0) {
    844        printf("relinquishing control to gdb\n");
    845 #ifdef _MSC_VER
    846        __debugbreak();
    847 #else
    848        asm("int $3");
    849 #endif
    850        printf("regaining control from gdb\n");
    851      } else if (strcmp(cmd, "break") == 0) {
    852        if (argc == 2) {
    853          int32_t value;
    854          if (getValue(arg1, &value)) {
    855            if (!setBreakpoint(reinterpret_cast<SimInstruction*>(value))) {
    856              printf("setting breakpoint failed\n");
    857            }
    858          } else {
    859            printf("%s unrecognized\n", arg1);
    860          }
    861        } else {
    862          printf("break <address>\n");
    863        }
    864      } else if (strcmp(cmd, "del") == 0) {
    865        if (!deleteBreakpoint(nullptr)) {
    866          printf("deleting breakpoint failed\n");
    867        }
    868      } else if (strcmp(cmd, "flags") == 0) {
    869        printf("N flag: %d; ", sim_->n_flag_);
    870        printf("Z flag: %d; ", sim_->z_flag_);
    871        printf("C flag: %d; ", sim_->c_flag_);
    872        printf("V flag: %d\n", sim_->v_flag_);
    873        printf("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_);
    874        printf("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_);
    875        printf("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
    876        printf("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
    877        printf("INEXACT flag: %d;\n", sim_->inexact_vfp_flag_);
    878      } else if (strcmp(cmd, "stop") == 0) {
    879        int32_t value;
    880        intptr_t stop_pc = sim_->get_pc() - 2 * SimInstruction::kInstrSize;
    881        SimInstruction* stop_instr = reinterpret_cast<SimInstruction*>(stop_pc);
    882        SimInstruction* msg_address = reinterpret_cast<SimInstruction*>(
    883            stop_pc + SimInstruction::kInstrSize);
    884        if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
    885          // Remove the current stop.
    886          if (sim_->isStopInstruction(stop_instr)) {
    887            stop_instr->setInstructionBits(kNopInstr);
    888            msg_address->setInstructionBits(kNopInstr);
    889          } else {
    890            printf("Not at debugger stop.\n");
    891          }
    892        } else if (argc == 3) {
    893          // Print information about all/the specified breakpoint(s).
    894          if (strcmp(arg1, "info") == 0) {
    895            if (strcmp(arg2, "all") == 0) {
    896              printf("Stop information:\n");
    897              for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
    898                sim_->printStopInfo(i);
    899              }
    900            } else if (getValue(arg2, &value)) {
    901              sim_->printStopInfo(value);
    902            } else {
    903              printf("Unrecognized argument.\n");
    904            }
    905          } else if (strcmp(arg1, "enable") == 0) {
    906            // Enable all/the specified breakpoint(s).
    907            if (strcmp(arg2, "all") == 0) {
    908              for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
    909                sim_->enableStop(i);
    910              }
    911            } else if (getValue(arg2, &value)) {
    912              sim_->enableStop(value);
    913            } else {
    914              printf("Unrecognized argument.\n");
    915            }
    916          } else if (strcmp(arg1, "disable") == 0) {
    917            // Disable all/the specified breakpoint(s).
    918            if (strcmp(arg2, "all") == 0) {
    919              for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
    920                sim_->disableStop(i);
    921              }
    922            } else if (getValue(arg2, &value)) {
    923              sim_->disableStop(value);
    924            } else {
    925              printf("Unrecognized argument.\n");
    926            }
    927          }
    928        } else {
    929          printf("Wrong usage. Use help command for more information.\n");
    930        }
    931      } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
    932        printf("cont\n");
    933        printf("  continue execution (alias 'c')\n");
    934        printf("skip\n");
    935        printf("  skip one instruction (set pc to next instruction)\n");
    936        printf("stepi\n");
    937        printf("  step one instruction (alias 'si')\n");
    938        printf("print <register>\n");
    939        printf("  print register content (alias 'p')\n");
    940        printf("  use register name 'all' to print all registers\n");
    941        printf("  add argument 'fp' to print register pair double values\n");
    942        printf("flags\n");
    943        printf("  print flags\n");
    944        printf("stack [<words>]\n");
    945        printf("  dump stack content, default dump 10 words)\n");
    946        printf("mem <address> [<words>]\n");
    947        printf("  dump memory content, default dump 10 words)\n");
    948        printf("disasm [<instructions>]\n");
    949        printf("disasm [<address/register>]\n");
    950        printf("disasm [[<address/register>] <instructions>]\n");
    951        printf("  disassemble code, default is 10 instructions\n");
    952        printf("  from pc (alias 'di')\n");
    953        printf("gdb\n");
    954        printf("  enter gdb\n");
    955        printf("break <address>\n");
    956        printf("  set a break point on the address\n");
    957        printf("del\n");
    958        printf("  delete the breakpoint\n");
    959        printf("stop feature:\n");
    960        printf("  Description:\n");
    961        printf("    Stops are debug instructions inserted by\n");
    962        printf("    the Assembler::stop() function.\n");
    963        printf("    When hitting a stop, the Simulator will\n");
    964        printf("    stop and and give control to the ArmDebugger.\n");
    965        printf("    The first %d stop codes are watched:\n",
    966               Simulator::kNumOfWatchedStops);
    967        printf("    - They can be enabled / disabled: the Simulator\n");
    968        printf("      will / won't stop when hitting them.\n");
    969        printf("    - The Simulator keeps track of how many times they \n");
    970        printf("      are met. (See the info command.) Going over a\n");
    971        printf("      disabled stop still increases its counter. \n");
    972        printf("  Commands:\n");
    973        printf("    stop info all/<code> : print infos about number <code>\n");
    974        printf("      or all stop(s).\n");
    975        printf("    stop enable/disable all/<code> : enables / disables\n");
    976        printf("      all or number <code> stop(s)\n");
    977        printf("    stop unstop\n");
    978        printf("      ignore the stop instruction at the current location\n");
    979        printf("      from now on\n");
    980      } else {
    981        printf("Unknown command: %s\n", cmd);
    982      }
    983    }
    984  }
    985 
    986  // Add all the breakpoints back to stop execution and enter the debugger
    987  // shell when hit.
    988  redoBreakpoints();
    989 
    990 #undef COMMAND_SIZE
    991 #undef ARG_SIZE
    992 
    993 #undef STR
    994 #undef XSTR
    995 }
    996 
    997 static bool AllOnOnePage(uintptr_t start, int size) {
    998  intptr_t start_page = (start & ~CachePage::kPageMask);
    999  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
   1000  return start_page == end_page;
   1001 }
   1002 
   1003 static CachePage* GetCachePageLocked(SimulatorProcess::ICacheMap& i_cache,
   1004                                     void* page) {
   1005  SimulatorProcess::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
   1006  if (p) {
   1007    return p->value();
   1008  }
   1009 
   1010  AutoEnterOOMUnsafeRegion oomUnsafe;
   1011  CachePage* new_page = js_new<CachePage>();
   1012  if (!new_page || !i_cache.add(p, page, new_page)) {
   1013    oomUnsafe.crash("Simulator CachePage");
   1014  }
   1015 
   1016  return new_page;
   1017 }
   1018 
   1019 // Flush from start up to and not including start + size.
   1020 static void FlushOnePageLocked(SimulatorProcess::ICacheMap& i_cache,
   1021                               intptr_t start, int size) {
   1022  MOZ_ASSERT(size <= CachePage::kPageSize);
   1023  MOZ_ASSERT(AllOnOnePage(start, size - 1));
   1024  MOZ_ASSERT((start & CachePage::kLineMask) == 0);
   1025  MOZ_ASSERT((size & CachePage::kLineMask) == 0);
   1026 
   1027  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
   1028  int offset = (start & CachePage::kPageMask);
   1029  CachePage* cache_page = GetCachePageLocked(i_cache, page);
   1030  char* valid_bytemap = cache_page->validityByte(offset);
   1031  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
   1032 }
   1033 
   1034 static void FlushICacheLocked(SimulatorProcess::ICacheMap& i_cache,
   1035                              void* start_addr, size_t size) {
   1036  intptr_t start = reinterpret_cast<intptr_t>(start_addr);
   1037  int intra_line = (start & CachePage::kLineMask);
   1038  start -= intra_line;
   1039  size += intra_line;
   1040  size = ((size - 1) | CachePage::kLineMask) + 1;
   1041  int offset = (start & CachePage::kPageMask);
   1042  while (!AllOnOnePage(start, size - 1)) {
   1043    int bytes_to_flush = CachePage::kPageSize - offset;
   1044    FlushOnePageLocked(i_cache, start, bytes_to_flush);
   1045    start += bytes_to_flush;
   1046    size -= bytes_to_flush;
   1047    MOZ_ASSERT((start & CachePage::kPageMask) == 0);
   1048    offset = 0;
   1049  }
   1050  if (size != 0) {
   1051    FlushOnePageLocked(i_cache, start, size);
   1052  }
   1053 }
   1054 
   1055 /* static */
   1056 void SimulatorProcess::checkICacheLocked(SimInstruction* instr) {
   1057  intptr_t address = reinterpret_cast<intptr_t>(instr);
   1058  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
   1059  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
   1060  int offset = (address & CachePage::kPageMask);
   1061  CachePage* cache_page = GetCachePageLocked(icache(), page);
   1062  char* cache_valid_byte = cache_page->validityByte(offset);
   1063  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
   1064  char* cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask);
   1065 
   1066  if (cache_hit) {
   1067    // Check that the data in memory matches the contents of the I-cache.
   1068    mozilla::DebugOnly<int> cmpret =
   1069        memcmp(reinterpret_cast<void*>(instr), cache_page->cachedData(offset),
   1070               SimInstruction::kInstrSize);
   1071    MOZ_ASSERT(cmpret == 0);
   1072  } else {
   1073    // Cache miss. Load memory into the cache.
   1074    memcpy(cached_line, line, CachePage::kLineLength);
   1075    *cache_valid_byte = CachePage::LINE_VALID;
   1076  }
   1077 }
   1078 
   1079 HashNumber SimulatorProcess::ICacheHasher::hash(const Lookup& l) {
   1080  return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(l)) >> 2;
   1081 }
   1082 
   1083 bool SimulatorProcess::ICacheHasher::match(const Key& k, const Lookup& l) {
   1084  MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0);
   1085  MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0);
   1086  return k == l;
   1087 }
   1088 
   1089 void Simulator::setLastDebuggerInput(char* input) {
   1090  js_free(lastDebuggerInput_);
   1091  lastDebuggerInput_ = input;
   1092 }
   1093 
   1094 /* static */
   1095 void SimulatorProcess::FlushICache(void* start_addr, size_t size) {
   1096  JitSpewCont(JitSpew_CacheFlush, "[%p %zx]", start_addr, size);
   1097  if (!ICacheCheckingDisableCount) {
   1098    AutoLockSimulatorCache als;
   1099    js::jit::FlushICacheLocked(icache(), start_addr, size);
   1100  }
   1101 }
   1102 
   1103 Simulator::Simulator() {
   1104  // Set up simulator support first. Some of this information is needed to
   1105  // setup the architecture state.
   1106 
   1107  // Note, allocation and anything that depends on allocated memory is
   1108  // deferred until init(), in order to handle OOM properly.
   1109 
   1110  stack_ = nullptr;
   1111  stackLimit_ = 0;
   1112  pc_modified_ = false;
   1113  icount_ = 0L;
   1114  break_pc_ = nullptr;
   1115  break_instr_ = 0;
   1116  single_stepping_ = false;
   1117  single_step_callback_ = nullptr;
   1118  single_step_callback_arg_ = nullptr;
   1119  skipCalleeSavedRegsCheck = false;
   1120 
   1121  // Set up architecture state.
   1122  // All registers are initialized to zero to start with.
   1123  for (int i = 0; i < num_registers; i++) {
   1124    registers_[i] = 0;
   1125  }
   1126 
   1127  n_flag_ = false;
   1128  z_flag_ = false;
   1129  c_flag_ = false;
   1130  v_flag_ = false;
   1131 
   1132  for (int i = 0; i < num_d_registers * 2; i++) {
   1133    vfp_registers_[i] = 0;
   1134  }
   1135 
   1136  n_flag_FPSCR_ = false;
   1137  z_flag_FPSCR_ = false;
   1138  c_flag_FPSCR_ = false;
   1139  v_flag_FPSCR_ = false;
   1140  FPSCR_rounding_mode_ = SimRZ;
   1141  FPSCR_default_NaN_mode_ = true;
   1142 
   1143  inv_op_vfp_flag_ = false;
   1144  div_zero_vfp_flag_ = false;
   1145  overflow_vfp_flag_ = false;
   1146  underflow_vfp_flag_ = false;
   1147  inexact_vfp_flag_ = false;
   1148 
   1149  // The lr and pc are initialized to a known bad value that will cause an
   1150  // access violation if the simulator ever tries to execute it.
   1151  registers_[pc] = bad_lr;
   1152  registers_[lr] = bad_lr;
   1153 
   1154  lastDebuggerInput_ = nullptr;
   1155 
   1156  exclusiveMonitorHeld_ = false;
   1157  exclusiveMonitor_ = 0;
   1158 }
   1159 
   1160 bool Simulator::init() {
   1161  // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
   1162  static const size_t stackSize = 2 * 1024 * 1024;
   1163  stack_ = js_pod_malloc<char>(stackSize);
   1164  if (!stack_) {
   1165    return false;
   1166  }
   1167 
   1168  // Leave a safety margin of 1MB to prevent overrunning the stack when
   1169  // pushing values (total stack size is 2MB).
   1170  stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
   1171 
   1172  // The sp is initialized to point to the bottom (high address) of the
   1173  // allocated stack area. To be safe in potential stack underflows we leave
   1174  // some buffer below.
   1175  registers_[sp] = reinterpret_cast<int32_t>(stack_) + stackSize - 64;
   1176 
   1177  return true;
   1178 }
   1179 
   1180 // When the generated code calls a VM function (masm.callWithABI) we need to
   1181 // call that function instead of trying to execute it with the simulator
   1182 // (because it's x86 code instead of arm code). We do that by redirecting the VM
   1183 // call to a svc (Supervisor Call) instruction that is handled by the
   1184 // simulator. We write the original destination of the jump just at a known
   1185 // offset from the svc instruction so the simulator knows what to call.
   1186 class Redirection {
   1187  friend class SimulatorProcess;
   1188 
   1189  // sim's lock must already be held.
   1190  Redirection(void* nativeFunction, ABIFunctionType type)
   1191      : nativeFunction_(nativeFunction),
   1192        swiInstruction_(Assembler::AL | (0xf * (1 << 24)) | kCallRtRedirected),
   1193        type_(type),
   1194        next_(nullptr) {
   1195    next_ = SimulatorProcess::redirection();
   1196    if (!SimulatorProcess::ICacheCheckingDisableCount) {
   1197      FlushICacheLocked(SimulatorProcess::icache(), addressOfSwiInstruction(),
   1198                        SimInstruction::kInstrSize);
   1199    }
   1200    SimulatorProcess::setRedirection(this);
   1201  }
   1202 
   1203 public:
   1204  void* addressOfSwiInstruction() { return &swiInstruction_; }
   1205  void* nativeFunction() const { return nativeFunction_; }
   1206  ABIFunctionType type() const { return type_; }
   1207 
   1208  static Redirection* Get(void* nativeFunction, ABIFunctionType type) {
   1209    AutoLockSimulatorCache als;
   1210 
   1211    Redirection* current = SimulatorProcess::redirection();
   1212    for (; current != nullptr; current = current->next_) {
   1213      if (current->nativeFunction_ == nativeFunction) {
   1214        MOZ_ASSERT(current->type() == type);
   1215        return current;
   1216      }
   1217    }
   1218 
   1219    // Note: we can't use js_new here because the constructor is private.
   1220    AutoEnterOOMUnsafeRegion oomUnsafe;
   1221    Redirection* redir = js_pod_malloc<Redirection>(1);
   1222    if (!redir) {
   1223      oomUnsafe.crash("Simulator redirection");
   1224    }
   1225    new (redir) Redirection(nativeFunction, type);
   1226    return redir;
   1227  }
   1228 
   1229  static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
   1230    uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
   1231    uint8_t* addrOfRedirection =
   1232        addrOfSwi - offsetof(Redirection, swiInstruction_);
   1233    return reinterpret_cast<Redirection*>(addrOfRedirection);
   1234  }
   1235 
   1236 private:
   1237  void* nativeFunction_;
   1238  uint32_t swiInstruction_;
   1239  ABIFunctionType type_;
   1240  Redirection* next_;
   1241 };
   1242 
   1243 Simulator::~Simulator() { js_free(stack_); }
   1244 
   1245 SimulatorProcess::SimulatorProcess()
   1246    : cacheLock_(mutexid::SimulatorCacheLock), redirection_(nullptr) {
   1247  if (getenv("ARM_SIM_ICACHE_CHECKS")) {
   1248    ICacheCheckingDisableCount = 0;
   1249  }
   1250 }
   1251 
   1252 SimulatorProcess::~SimulatorProcess() {
   1253  Redirection* r = redirection_;
   1254  while (r) {
   1255    Redirection* next = r->next_;
   1256    js_delete(r);
   1257    r = next;
   1258  }
   1259 }
   1260 
   1261 /* static */
   1262 void* Simulator::RedirectNativeFunction(void* nativeFunction,
   1263                                        ABIFunctionType type) {
   1264  Redirection* redirection = Redirection::Get(nativeFunction, type);
   1265  return redirection->addressOfSwiInstruction();
   1266 }
   1267 
   1268 // Sets the register in the architecture state. It will also deal with updating
   1269 // Simulator internal state for special registers such as PC.
   1270 void Simulator::set_register(int reg, int32_t value) {
   1271  MOZ_ASSERT(reg >= 0 && reg < num_registers);
   1272  if (reg == pc) {
   1273    pc_modified_ = true;
   1274  }
   1275  registers_[reg] = value;
   1276 }
   1277 
   1278 // Get the register from the architecture state. This function does handle the
   1279 // special case of accessing the PC register.
   1280 int32_t Simulator::get_register(int reg) const {
   1281  MOZ_ASSERT(reg >= 0 && reg < num_registers);
   1282  // Work around GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
   1283  if (reg >= num_registers) return 0;
   1284  return registers_[reg] + ((reg == pc) ? SimInstruction::kPCReadOffset : 0);
   1285 }
   1286 
   1287 double Simulator::get_double_from_register_pair(int reg) {
   1288  MOZ_ASSERT(reg >= 0 && reg < num_registers && (reg % 2) == 0);
   1289 
   1290  // Read the bits from the unsigned integer register_[] array into the double
   1291  // precision floating point value and return it.
   1292  double dm_val = 0.0;
   1293  char buffer[2 * sizeof(vfp_registers_[0])];
   1294  memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
   1295  memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
   1296  return dm_val;
   1297 }
   1298 
   1299 void Simulator::set_register_pair_from_double(int reg, double* value) {
   1300  MOZ_ASSERT(reg >= 0 && reg < num_registers && (reg % 2) == 0);
   1301  memcpy(registers_ + reg, value, sizeof(*value));
   1302 }
   1303 
   1304 void Simulator::set_dw_register(int dreg, const int* dbl) {
   1305  MOZ_ASSERT(dreg >= 0 && dreg < num_d_registers);
   1306  registers_[dreg] = dbl[0];
   1307  registers_[dreg + 1] = dbl[1];
   1308 }
   1309 
   1310 void Simulator::get_d_register(int dreg, uint64_t* value) {
   1311  MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::TotalPhys));
   1312  memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value));
   1313 }
   1314 
   1315 void Simulator::set_d_register(int dreg, const uint64_t* value) {
   1316  MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::TotalPhys));
   1317  memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value));
   1318 }
   1319 
   1320 void Simulator::get_d_register(int dreg, uint32_t* value) {
   1321  MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::TotalPhys));
   1322  memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value) * 2);
   1323 }
   1324 
   1325 void Simulator::set_d_register(int dreg, const uint32_t* value) {
   1326  MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::TotalPhys));
   1327  memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value) * 2);
   1328 }
   1329 
   1330 void Simulator::get_q_register(int qreg, uint64_t* value) {
   1331  MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers);
   1332  memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 2);
   1333 }
   1334 
   1335 void Simulator::set_q_register(int qreg, const uint64_t* value) {
   1336  MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers);
   1337  memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 2);
   1338 }
   1339 
   1340 void Simulator::get_q_register(int qreg, uint32_t* value) {
   1341  MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers);
   1342  memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 4);
   1343 }
   1344 
   1345 void Simulator::set_q_register(int qreg, const uint32_t* value) {
   1346  MOZ_ASSERT((qreg >= 0) && (qreg < num_q_registers));
   1347  memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 4);
   1348 }
   1349 
   1350 void Simulator::set_pc(int32_t value) {
   1351  pc_modified_ = true;
   1352  registers_[pc] = value;
   1353 }
   1354 
   1355 bool Simulator::has_bad_pc() const {
   1356  return registers_[pc] == bad_lr || registers_[pc] == end_sim_pc;
   1357 }
   1358 
   1359 // Raw access to the PC register without the special adjustment when reading.
   1360 int32_t Simulator::get_pc() const { return registers_[pc]; }
   1361 
   1362 void Simulator::set_s_register(int sreg, unsigned int value) {
   1363  MOZ_ASSERT(sreg >= 0 && sreg < num_s_registers);
   1364  vfp_registers_[sreg] = value;
   1365 }
   1366 
   1367 unsigned Simulator::get_s_register(int sreg) const {
   1368  MOZ_ASSERT(sreg >= 0 && sreg < num_s_registers);
   1369  return vfp_registers_[sreg];
   1370 }
   1371 
   1372 template <class InputType, int register_size>
   1373 void Simulator::setVFPRegister(int reg_index, const InputType& value) {
   1374  MOZ_ASSERT(reg_index >= 0);
   1375  MOZ_ASSERT_IF(register_size == 1, reg_index < num_s_registers);
   1376  MOZ_ASSERT_IF(register_size == 2, reg_index < int(FloatRegisters::TotalPhys));
   1377 
   1378  char buffer[register_size * sizeof(vfp_registers_[0])];
   1379  memcpy(buffer, &value, register_size * sizeof(vfp_registers_[0]));
   1380  memcpy(&vfp_registers_[reg_index * register_size], buffer,
   1381         register_size * sizeof(vfp_registers_[0]));
   1382 }
   1383 
   1384 template <class ReturnType, int register_size>
   1385 void Simulator::getFromVFPRegister(int reg_index, ReturnType* out) {
   1386  MOZ_ASSERT(reg_index >= 0);
   1387  MOZ_ASSERT_IF(register_size == 1, reg_index < num_s_registers);
   1388  MOZ_ASSERT_IF(register_size == 2, reg_index < int(FloatRegisters::TotalPhys));
   1389 
   1390  char buffer[register_size * sizeof(vfp_registers_[0])];
   1391  memcpy(buffer, &vfp_registers_[register_size * reg_index],
   1392         register_size * sizeof(vfp_registers_[0]));
   1393  memcpy(out, buffer, register_size * sizeof(vfp_registers_[0]));
   1394 }
   1395 
   1396 // These forced-instantiations are for jsapi-tests. Evidently, nothing
   1397 // requires these to be instantiated.
   1398 template void Simulator::getFromVFPRegister<double, 2>(int reg_index,
   1399                                                       double* out);
   1400 template void Simulator::getFromVFPRegister<float, 1>(int reg_index,
   1401                                                      float* out);
   1402 template void Simulator::setVFPRegister<double, 2>(int reg_index,
   1403                                                   const double& value);
   1404 template void Simulator::setVFPRegister<float, 1>(int reg_index,
   1405                                                  const float& value);
   1406 
   1407 void Simulator::getFpArgs(double* x, double* y, int32_t* z) {
   1408  if (ARMFlags::UseHardFpABI()) {
   1409    get_double_from_d_register(0, x);
   1410    get_double_from_d_register(1, y);
   1411    *z = get_register(0);
   1412  } else {
   1413    *x = get_double_from_register_pair(0);
   1414    *y = get_double_from_register_pair(2);
   1415    *z = get_register(2);
   1416  }
   1417 }
   1418 
   1419 void Simulator::getFpFromStack(int32_t* stack, double* x) {
   1420  MOZ_ASSERT(stack && x);
   1421  char buffer[2 * sizeof(stack[0])];
   1422  memcpy(buffer, stack, 2 * sizeof(stack[0]));
   1423  memcpy(x, buffer, 2 * sizeof(stack[0]));
   1424 }
   1425 
   1426 void Simulator::setCallResultDouble(double result) {
   1427  // The return value is either in r0/r1 or d0.
   1428  if (ARMFlags::UseHardFpABI()) {
   1429    char buffer[2 * sizeof(vfp_registers_[0])];
   1430    memcpy(buffer, &result, sizeof(buffer));
   1431    // Copy result to d0.
   1432    memcpy(vfp_registers_, buffer, sizeof(buffer));
   1433  } else {
   1434    char buffer[2 * sizeof(registers_[0])];
   1435    memcpy(buffer, &result, sizeof(buffer));
   1436    // Copy result to r0 and r1.
   1437    memcpy(registers_, buffer, sizeof(buffer));
   1438  }
   1439 }
   1440 
   1441 void Simulator::setCallResultFloat(float result) {
   1442  if (ARMFlags::UseHardFpABI()) {
   1443    char buffer[sizeof(registers_[0])];
   1444    memcpy(buffer, &result, sizeof(buffer));
   1445    // Copy result to s0.
   1446    memcpy(vfp_registers_, buffer, sizeof(buffer));
   1447  } else {
   1448    char buffer[sizeof(registers_[0])];
   1449    memcpy(buffer, &result, sizeof(buffer));
   1450    // Copy result to r0.
   1451    memcpy(registers_, buffer, sizeof(buffer));
   1452  }
   1453 }
   1454 
   1455 void Simulator::setCallResult(int64_t res) {
   1456  set_register(r0, static_cast<int32_t>(res));
   1457  set_register(r1, static_cast<int32_t>(res >> 32));
   1458 }
   1459 
   1460 void Simulator::exclusiveMonitorSet(uint64_t value) {
   1461  exclusiveMonitor_ = value;
   1462  exclusiveMonitorHeld_ = true;
   1463 }
   1464 
   1465 uint64_t Simulator::exclusiveMonitorGetAndClear(bool* held) {
   1466  *held = exclusiveMonitorHeld_;
   1467  exclusiveMonitorHeld_ = false;
   1468  return *held ? exclusiveMonitor_ : 0;
   1469 }
   1470 
   1471 void Simulator::exclusiveMonitorClear() { exclusiveMonitorHeld_ = false; }
   1472 
   1473 JS::ProfilingFrameIterator::RegisterState Simulator::registerState() {
   1474  wasm::RegisterState state;
   1475  state.pc = (void*)get_pc();
   1476  state.fp = (void*)get_register(fp);
   1477  state.sp = (void*)get_register(sp);
   1478  state.lr = (void*)get_register(lr);
   1479  return state;
   1480 }
   1481 
   1482 uint64_t Simulator::readQ(int32_t addr, SimInstruction* instr,
   1483                          UnalignedPolicy f) {
   1484  if (handleWasmSegFault(addr, 8)) {
   1485    return UINT64_MAX;
   1486  }
   1487 
   1488  if ((addr & 3) == 0 ||
   1489      (f == AllowUnaligned && !ARMFlags::HasAlignmentFault())) {
   1490    uint64_t* ptr = reinterpret_cast<uint64_t*>(addr);
   1491    return *ptr;
   1492  }
   1493 
   1494  // See the comments below in readW.
   1495  if (ARMFlags::FixupFault() &&
   1496      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1497    char* ptr = reinterpret_cast<char*>(addr);
   1498    uint64_t value;
   1499    memcpy(&value, ptr, sizeof(value));
   1500    return value;
   1501  }
   1502 
   1503  printf("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
   1504  MOZ_CRASH();
   1505 }
   1506 
   1507 void Simulator::writeQ(int32_t addr, uint64_t value, SimInstruction* instr,
   1508                       UnalignedPolicy f) {
   1509  if (handleWasmSegFault(addr, 8)) {
   1510    return;
   1511  }
   1512 
   1513  if ((addr & 3) == 0 ||
   1514      (f == AllowUnaligned && !ARMFlags::HasAlignmentFault())) {
   1515    uint64_t* ptr = reinterpret_cast<uint64_t*>(addr);
   1516    *ptr = value;
   1517    return;
   1518  }
   1519 
   1520  // See the comments below in readW.
   1521  if (ARMFlags::FixupFault() &&
   1522      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1523    char* ptr = reinterpret_cast<char*>(addr);
   1524    memcpy(ptr, &value, sizeof(value));
   1525    return;
   1526  }
   1527 
   1528  printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
   1529  MOZ_CRASH();
   1530 }
   1531 
   1532 int Simulator::readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f) {
   1533  if (handleWasmSegFault(addr, 4)) {
   1534    return -1;
   1535  }
   1536 
   1537  if ((addr & 3) == 0 ||
   1538      (f == AllowUnaligned && !ARMFlags::HasAlignmentFault())) {
   1539    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
   1540    return *ptr;
   1541  }
   1542 
   1543  // In WebAssembly, we want unaligned accesses to either raise a signal or
   1544  // do the right thing. Making this simulator properly emulate the behavior
   1545  // of raising a signal is complex, so as a special-case, when in wasm code,
   1546  // we just do the right thing.
   1547  if (ARMFlags::FixupFault() &&
   1548      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1549    char* ptr = reinterpret_cast<char*>(addr);
   1550    int value;
   1551    memcpy(&value, ptr, sizeof(value));
   1552    return value;
   1553  }
   1554 
   1555  printf("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
   1556  MOZ_CRASH();
   1557 }
   1558 
   1559 void Simulator::writeW(int32_t addr, int value, SimInstruction* instr,
   1560                       UnalignedPolicy f) {
   1561  if (handleWasmSegFault(addr, 4)) {
   1562    return;
   1563  }
   1564 
   1565  if ((addr & 3) == 0 ||
   1566      (f == AllowUnaligned && !ARMFlags::HasAlignmentFault())) {
   1567    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
   1568    *ptr = value;
   1569    return;
   1570  }
   1571 
   1572  // See the comments above in readW.
   1573  if (ARMFlags::FixupFault() &&
   1574      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1575    char* ptr = reinterpret_cast<char*>(addr);
   1576    memcpy(ptr, &value, sizeof(value));
   1577    return;
   1578  }
   1579 
   1580  printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
   1581  MOZ_CRASH();
   1582 }
   1583 
   1584 // For the time being, define Relaxed operations in terms of SeqCst
   1585 // operations - we don't yet need Relaxed operations anywhere else in
   1586 // the system, and the distinction is not important to the simulation
   1587 // at the level where we're operating.
   1588 
   1589 template <typename T>
   1590 static T loadRelaxed(SharedMem<T*> addr) {
   1591  return AtomicOperations::loadSeqCst(addr);
   1592 }
   1593 
   1594 template <typename T>
   1595 static T compareExchangeRelaxed(SharedMem<T*> addr, T oldval, T newval) {
   1596  return AtomicOperations::compareExchangeSeqCst(addr, oldval, newval);
   1597 }
   1598 
   1599 int Simulator::readExW(int32_t addr, SimInstruction* instr) {
   1600  if (addr & 3) {
   1601    MOZ_CRASH("Unaligned exclusive read");
   1602  }
   1603 
   1604  if (handleWasmSegFault(addr, 4)) {
   1605    return -1;
   1606  }
   1607 
   1608  SharedMem<int32_t*> ptr =
   1609      SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
   1610  int32_t value = loadRelaxed(ptr);
   1611  exclusiveMonitorSet(value);
   1612  return value;
   1613 }
   1614 
   1615 int32_t Simulator::writeExW(int32_t addr, int value, SimInstruction* instr) {
   1616  if (addr & 3) {
   1617    MOZ_CRASH("Unaligned exclusive write");
   1618  }
   1619 
   1620  if (handleWasmSegFault(addr, 4)) {
   1621    return -1;
   1622  }
   1623 
   1624  SharedMem<int32_t*> ptr =
   1625      SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
   1626  bool held;
   1627  int32_t expected = int32_t(exclusiveMonitorGetAndClear(&held));
   1628  if (!held) {
   1629    return 1;
   1630  }
   1631  int32_t old = compareExchangeRelaxed(ptr, expected, int32_t(value));
   1632  return old != expected;
   1633 }
   1634 
   1635 uint16_t Simulator::readHU(int32_t addr, SimInstruction* instr) {
   1636  if (handleWasmSegFault(addr, 2)) {
   1637    return UINT16_MAX;
   1638  }
   1639 
   1640  // The regexp engine emits unaligned loads, so we don't check for them here
   1641  // like most of the other methods do.
   1642  if ((addr & 1) == 0 || !ARMFlags::HasAlignmentFault()) {
   1643    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
   1644    return *ptr;
   1645  }
   1646 
   1647  // See comments above in readW.
   1648  if (ARMFlags::FixupFault() &&
   1649      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1650    char* ptr = reinterpret_cast<char*>(addr);
   1651    uint16_t value;
   1652    memcpy(&value, ptr, sizeof(value));
   1653    return value;
   1654  }
   1655 
   1656  printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
   1657  MOZ_CRASH();
   1658  return 0;
   1659 }
   1660 
   1661 int16_t Simulator::readH(int32_t addr, SimInstruction* instr) {
   1662  if (handleWasmSegFault(addr, 2)) {
   1663    return -1;
   1664  }
   1665 
   1666  if ((addr & 1) == 0 || !ARMFlags::HasAlignmentFault()) {
   1667    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
   1668    return *ptr;
   1669  }
   1670 
   1671  // See comments above in readW.
   1672  if (ARMFlags::FixupFault() &&
   1673      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1674    char* ptr = reinterpret_cast<char*>(addr);
   1675    int16_t value;
   1676    memcpy(&value, ptr, sizeof(value));
   1677    return value;
   1678  }
   1679 
   1680  printf("Unaligned signed halfword read at 0x%08x\n", addr);
   1681  MOZ_CRASH();
   1682  return 0;
   1683 }
   1684 
   1685 void Simulator::writeH(int32_t addr, uint16_t value, SimInstruction* instr) {
   1686  if (handleWasmSegFault(addr, 2)) {
   1687    return;
   1688  }
   1689 
   1690  if ((addr & 1) == 0 || !ARMFlags::HasAlignmentFault()) {
   1691    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
   1692    *ptr = value;
   1693    return;
   1694  }
   1695 
   1696  // See the comments above in readW.
   1697  if (ARMFlags::FixupFault() &&
   1698      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1699    char* ptr = reinterpret_cast<char*>(addr);
   1700    memcpy(ptr, &value, sizeof(value));
   1701    return;
   1702  }
   1703 
   1704  printf("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
   1705  MOZ_CRASH();
   1706 }
   1707 
   1708 void Simulator::writeH(int32_t addr, int16_t value, SimInstruction* instr) {
   1709  if (handleWasmSegFault(addr, 2)) {
   1710    return;
   1711  }
   1712 
   1713  if ((addr & 1) == 0 || !ARMFlags::HasAlignmentFault()) {
   1714    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
   1715    *ptr = value;
   1716    return;
   1717  }
   1718 
   1719  // See the comments above in readW.
   1720  if (ARMFlags::FixupFault() &&
   1721      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1722    char* ptr = reinterpret_cast<char*>(addr);
   1723    memcpy(ptr, &value, sizeof(value));
   1724    return;
   1725  }
   1726 
   1727  printf("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
   1728  MOZ_CRASH();
   1729 }
   1730 
   1731 uint16_t Simulator::readExHU(int32_t addr, SimInstruction* instr) {
   1732  if (addr & 1) {
   1733    MOZ_CRASH("Unaligned exclusive read");
   1734  }
   1735 
   1736  if (handleWasmSegFault(addr, 2)) {
   1737    return UINT16_MAX;
   1738  }
   1739 
   1740  SharedMem<uint16_t*> ptr =
   1741      SharedMem<uint16_t*>::shared(reinterpret_cast<uint16_t*>(addr));
   1742  uint16_t value = loadRelaxed(ptr);
   1743  exclusiveMonitorSet(value);
   1744  return value;
   1745 }
   1746 
   1747 int32_t Simulator::writeExH(int32_t addr, uint16_t value,
   1748                            SimInstruction* instr) {
   1749  if (addr & 1) {
   1750    MOZ_CRASH("Unaligned exclusive write");
   1751  }
   1752 
   1753  if (handleWasmSegFault(addr, 2)) {
   1754    return -1;
   1755  }
   1756 
   1757  SharedMem<uint16_t*> ptr =
   1758      SharedMem<uint16_t*>::shared(reinterpret_cast<uint16_t*>(addr));
   1759  bool held;
   1760  uint16_t expected = uint16_t(exclusiveMonitorGetAndClear(&held));
   1761  if (!held) {
   1762    return 1;
   1763  }
   1764  uint16_t old = compareExchangeRelaxed(ptr, expected, value);
   1765  return old != expected;
   1766 }
   1767 
   1768 uint8_t Simulator::readBU(int32_t addr) {
   1769  if (handleWasmSegFault(addr, 1)) {
   1770    return UINT8_MAX;
   1771  }
   1772 
   1773  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
   1774  return *ptr;
   1775 }
   1776 
   1777 uint8_t Simulator::readExBU(int32_t addr) {
   1778  if (handleWasmSegFault(addr, 1)) {
   1779    return UINT8_MAX;
   1780  }
   1781 
   1782  SharedMem<uint8_t*> ptr =
   1783      SharedMem<uint8_t*>::shared(reinterpret_cast<uint8_t*>(addr));
   1784  uint8_t value = loadRelaxed(ptr);
   1785  exclusiveMonitorSet(value);
   1786  return value;
   1787 }
   1788 
   1789 int32_t Simulator::writeExB(int32_t addr, uint8_t value) {
   1790  if (handleWasmSegFault(addr, 1)) {
   1791    return -1;
   1792  }
   1793 
   1794  SharedMem<uint8_t*> ptr =
   1795      SharedMem<uint8_t*>::shared(reinterpret_cast<uint8_t*>(addr));
   1796  bool held;
   1797  uint8_t expected = uint8_t(exclusiveMonitorGetAndClear(&held));
   1798  if (!held) {
   1799    return 1;
   1800  }
   1801  uint8_t old = compareExchangeRelaxed(ptr, expected, value);
   1802  return old != expected;
   1803 }
   1804 
   1805 int8_t Simulator::readB(int32_t addr) {
   1806  if (handleWasmSegFault(addr, 1)) {
   1807    return -1;
   1808  }
   1809 
   1810  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
   1811  return *ptr;
   1812 }
   1813 
   1814 void Simulator::writeB(int32_t addr, uint8_t value) {
   1815  if (handleWasmSegFault(addr, 1)) {
   1816    return;
   1817  }
   1818 
   1819  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
   1820  *ptr = value;
   1821 }
   1822 
   1823 void Simulator::writeB(int32_t addr, int8_t value) {
   1824  if (handleWasmSegFault(addr, 1)) {
   1825    return;
   1826  }
   1827 
   1828  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
   1829  *ptr = value;
   1830 }
   1831 
   1832 int32_t* Simulator::readDW(int32_t addr) {
   1833  if (handleWasmSegFault(addr, 8)) {
   1834    return nullptr;
   1835  }
   1836 
   1837  if ((addr & 3) == 0) {
   1838    int32_t* ptr = reinterpret_cast<int32_t*>(addr);
   1839    return ptr;
   1840  }
   1841 
   1842  printf("Unaligned read at 0x%08x\n", addr);
   1843  MOZ_CRASH();
   1844 }
   1845 
   1846 void Simulator::writeDW(int32_t addr, int32_t value1, int32_t value2) {
   1847  if (handleWasmSegFault(addr, 8)) {
   1848    return;
   1849  }
   1850 
   1851  if ((addr & 3) == 0) {
   1852    int32_t* ptr = reinterpret_cast<int32_t*>(addr);
   1853    *ptr++ = value1;
   1854    *ptr = value2;
   1855    return;
   1856  }
   1857 
   1858  printf("Unaligned write at 0x%08x\n", addr);
   1859  MOZ_CRASH();
   1860 }
   1861 
   1862 int32_t Simulator::readExDW(int32_t addr, int32_t* hibits) {
   1863  if (addr & 3) {
   1864    MOZ_CRASH("Unaligned exclusive read");
   1865  }
   1866 
   1867  if (handleWasmSegFault(addr, 8)) {
   1868    return -1;
   1869  }
   1870 
   1871  SharedMem<uint64_t*> ptr =
   1872      SharedMem<uint64_t*>::shared(reinterpret_cast<uint64_t*>(addr));
   1873  // The spec says that the low part of value shall be read from addr and
   1874  // the high part shall be read from addr+4.  On a little-endian system
   1875  // where we read a 64-bit quadword the low part of the value will be in
   1876  // the low part of the quadword, and the high part of the value in the
   1877  // high part of the quadword.
   1878  uint64_t value = loadRelaxed(ptr);
   1879  exclusiveMonitorSet(value);
   1880  *hibits = int32_t(value >> 32);
   1881  return int32_t(value);
   1882 }
   1883 
   1884 int32_t Simulator::writeExDW(int32_t addr, int32_t value1, int32_t value2) {
   1885  if (addr & 3) {
   1886    MOZ_CRASH("Unaligned exclusive write");
   1887  }
   1888 
   1889  if (handleWasmSegFault(addr, 8)) {
   1890    return -1;
   1891  }
   1892 
   1893  SharedMem<uint64_t*> ptr =
   1894      SharedMem<uint64_t*>::shared(reinterpret_cast<uint64_t*>(addr));
   1895  // The spec says that value1 shall be stored at addr and value2 at
   1896  // addr+4.  On a little-endian system that means constructing a 64-bit
   1897  // value where value1 is in the low half of a 64-bit quadword and value2
   1898  // is in the high half of the quadword.
   1899  uint64_t value = (uint64_t(value2) << 32) | uint32_t(value1);
   1900  bool held;
   1901  uint64_t expected = exclusiveMonitorGetAndClear(&held);
   1902  if (!held) {
   1903    return 1;
   1904  }
   1905  uint64_t old = compareExchangeRelaxed(ptr, expected, value);
   1906  return old != expected;
   1907 }
   1908 
   1909 uintptr_t Simulator::stackLimit() const { return stackLimit_; }
   1910 
   1911 uintptr_t* Simulator::addressOfStackLimit() { return &stackLimit_; }
   1912 
   1913 bool Simulator::overRecursed(uintptr_t newsp) const {
   1914  if (newsp == 0) {
   1915    newsp = get_register(sp);
   1916  }
   1917  return newsp <= stackLimit();
   1918 }
   1919 
   1920 bool Simulator::overRecursedWithExtra(uint32_t extra) const {
   1921  uintptr_t newsp = get_register(sp) - extra;
   1922  return newsp <= stackLimit();
   1923 }
   1924 
   1925 // Checks if the current instruction should be executed based on its condition
   1926 // bits.
   1927 bool Simulator::conditionallyExecute(SimInstruction* instr) {
   1928  switch (instr->conditionField()) {
   1929    case Assembler::EQ:
   1930      return z_flag_;
   1931    case Assembler::NE:
   1932      return !z_flag_;
   1933    case Assembler::CS:
   1934      return c_flag_;
   1935    case Assembler::CC:
   1936      return !c_flag_;
   1937    case Assembler::MI:
   1938      return n_flag_;
   1939    case Assembler::PL:
   1940      return !n_flag_;
   1941    case Assembler::VS:
   1942      return v_flag_;
   1943    case Assembler::VC:
   1944      return !v_flag_;
   1945    case Assembler::HI:
   1946      return c_flag_ && !z_flag_;
   1947    case Assembler::LS:
   1948      return !c_flag_ || z_flag_;
   1949    case Assembler::GE:
   1950      return n_flag_ == v_flag_;
   1951    case Assembler::LT:
   1952      return n_flag_ != v_flag_;
   1953    case Assembler::GT:
   1954      return !z_flag_ && (n_flag_ == v_flag_);
   1955    case Assembler::LE:
   1956      return z_flag_ || (n_flag_ != v_flag_);
   1957    case Assembler::AL:
   1958      return true;
   1959    default:
   1960      MOZ_CRASH();
   1961  }
   1962  return false;
   1963 }
   1964 
   1965 // Calculate and set the Negative and Zero flags.
   1966 void Simulator::setNZFlags(int32_t val) {
   1967  n_flag_ = (val < 0);
   1968  z_flag_ = (val == 0);
   1969 }
   1970 
   1971 // Set the Carry flag.
   1972 void Simulator::setCFlag(bool val) { c_flag_ = val; }
   1973 
   1974 // Set the oVerflow flag.
   1975 void Simulator::setVFlag(bool val) { v_flag_ = val; }
   1976 
   1977 // Calculate C flag value for additions.
   1978 bool Simulator::carryFrom(int32_t left, int32_t right, int32_t carry) {
   1979  uint32_t uleft = static_cast<uint32_t>(left);
   1980  uint32_t uright = static_cast<uint32_t>(right);
   1981  uint32_t urest = 0xffffffffU - uleft;
   1982  return (uright > urest) ||
   1983         (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
   1984 }
   1985 
   1986 // Calculate C flag value for subtractions.
   1987 bool Simulator::borrowFrom(int32_t left, int32_t right) {
   1988  uint32_t uleft = static_cast<uint32_t>(left);
   1989  uint32_t uright = static_cast<uint32_t>(right);
   1990  return (uright > uleft);
   1991 }
   1992 
   1993 // Calculate V flag value for additions and subtractions.
   1994 bool Simulator::overflowFrom(int32_t alu_out, int32_t left, int32_t right,
   1995                             bool addition) {
   1996  bool overflow;
   1997  if (addition) {
   1998    // Operands have the same sign.
   1999    overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
   2000               // And operands and result have different sign.
   2001               && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
   2002  } else {
   2003    // Operands have different signs.
   2004    overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
   2005               // And first operand and result have different signs.
   2006               && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
   2007  }
   2008  return overflow;
   2009 }
   2010 
   2011 // Support for VFP comparisons.
   2012 void Simulator::compute_FPSCR_Flags(double val1, double val2) {
   2013  if (std::isnan(val1) || std::isnan(val2)) {
   2014    n_flag_FPSCR_ = false;
   2015    z_flag_FPSCR_ = false;
   2016    c_flag_FPSCR_ = true;
   2017    v_flag_FPSCR_ = true;
   2018    // All non-NaN cases.
   2019  } else if (val1 == val2) {
   2020    n_flag_FPSCR_ = false;
   2021    z_flag_FPSCR_ = true;
   2022    c_flag_FPSCR_ = true;
   2023    v_flag_FPSCR_ = false;
   2024  } else if (val1 < val2) {
   2025    n_flag_FPSCR_ = true;
   2026    z_flag_FPSCR_ = false;
   2027    c_flag_FPSCR_ = false;
   2028    v_flag_FPSCR_ = false;
   2029  } else {
   2030    // Case when (val1 > val2).
   2031    n_flag_FPSCR_ = false;
   2032    z_flag_FPSCR_ = false;
   2033    c_flag_FPSCR_ = true;
   2034    v_flag_FPSCR_ = false;
   2035  }
   2036 }
   2037 
   2038 void Simulator::copy_FPSCR_to_APSR() {
   2039  n_flag_ = n_flag_FPSCR_;
   2040  z_flag_ = z_flag_FPSCR_;
   2041  c_flag_ = c_flag_FPSCR_;
   2042  v_flag_ = v_flag_FPSCR_;
   2043 }
   2044 
   2045 // Addressing Mode 1 - Data-processing operands:
   2046 // Get the value based on the shifter_operand with register.
   2047 int32_t Simulator::getShiftRm(SimInstruction* instr, bool* carry_out) {
   2048  ShiftType shift = instr->shifttypeValue();
   2049  int shift_amount = instr->shiftAmountValue();
   2050  int32_t result = get_register(instr->rmValue());
   2051  if (instr->bit(4) == 0) {
   2052    // By immediate.
   2053    if (shift == ROR && shift_amount == 0) {
   2054      MOZ_CRASH("NYI");
   2055      return result;
   2056    }
   2057    if ((shift == LSR || shift == ASR) && shift_amount == 0) {
   2058      shift_amount = 32;
   2059    }
   2060    switch (shift) {
   2061      case ASR: {
   2062        if (shift_amount == 0) {
   2063          if (result < 0) {
   2064            result = 0xffffffff;
   2065            *carry_out = true;
   2066          } else {
   2067            result = 0;
   2068            *carry_out = false;
   2069          }
   2070        } else {
   2071          result >>= (shift_amount - 1);
   2072          *carry_out = (result & 1) == 1;
   2073          result >>= 1;
   2074        }
   2075        break;
   2076      }
   2077 
   2078      case LSL: {
   2079        if (shift_amount == 0) {
   2080          *carry_out = c_flag_;
   2081        } else {
   2082          result <<= (shift_amount - 1);
   2083          *carry_out = (result < 0);
   2084          result <<= 1;
   2085        }
   2086        break;
   2087      }
   2088 
   2089      case LSR: {
   2090        if (shift_amount == 0) {
   2091          result = 0;
   2092          *carry_out = c_flag_;
   2093        } else {
   2094          uint32_t uresult = static_cast<uint32_t>(result);
   2095          uresult >>= (shift_amount - 1);
   2096          *carry_out = (uresult & 1) == 1;
   2097          uresult >>= 1;
   2098          result = static_cast<int32_t>(uresult);
   2099        }
   2100        break;
   2101      }
   2102 
   2103      case ROR: {
   2104        if (shift_amount == 0) {
   2105          *carry_out = c_flag_;
   2106        } else {
   2107          uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
   2108          uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
   2109          result = right | left;
   2110          *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
   2111        }
   2112        break;
   2113      }
   2114 
   2115      default:
   2116        MOZ_CRASH();
   2117    }
   2118  } else {
   2119    // By register.
   2120    int rs = instr->rsValue();
   2121    shift_amount = get_register(rs) & 0xff;
   2122    switch (shift) {
   2123      case ASR: {
   2124        if (shift_amount == 0) {
   2125          *carry_out = c_flag_;
   2126        } else if (shift_amount < 32) {
   2127          result >>= (shift_amount - 1);
   2128          *carry_out = (result & 1) == 1;
   2129          result >>= 1;
   2130        } else {
   2131          MOZ_ASSERT(shift_amount >= 32);
   2132          if (result < 0) {
   2133            *carry_out = true;
   2134            result = 0xffffffff;
   2135          } else {
   2136            *carry_out = false;
   2137            result = 0;
   2138          }
   2139        }
   2140        break;
   2141      }
   2142 
   2143      case LSL: {
   2144        if (shift_amount == 0) {
   2145          *carry_out = c_flag_;
   2146        } else if (shift_amount < 32) {
   2147          result <<= (shift_amount - 1);
   2148          *carry_out = (result < 0);
   2149          result <<= 1;
   2150        } else if (shift_amount == 32) {
   2151          *carry_out = (result & 1) == 1;
   2152          result = 0;
   2153        } else {
   2154          MOZ_ASSERT(shift_amount > 32);
   2155          *carry_out = false;
   2156          result = 0;
   2157        }
   2158        break;
   2159      }
   2160 
   2161      case LSR: {
   2162        if (shift_amount == 0) {
   2163          *carry_out = c_flag_;
   2164        } else if (shift_amount < 32) {
   2165          uint32_t uresult = static_cast<uint32_t>(result);
   2166          uresult >>= (shift_amount - 1);
   2167          *carry_out = (uresult & 1) == 1;
   2168          uresult >>= 1;
   2169          result = static_cast<int32_t>(uresult);
   2170        } else if (shift_amount == 32) {
   2171          *carry_out = (result < 0);
   2172          result = 0;
   2173        } else {
   2174          *carry_out = false;
   2175          result = 0;
   2176        }
   2177        break;
   2178      }
   2179 
   2180      case ROR: {
   2181        if (shift_amount == 0) {
   2182          *carry_out = c_flag_;
   2183        } else {
   2184          uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
   2185          uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
   2186          result = right | left;
   2187          *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
   2188        }
   2189        break;
   2190      }
   2191 
   2192      default:
   2193        MOZ_CRASH();
   2194    }
   2195  }
   2196  return result;
   2197 }
   2198 
   2199 // Addressing Mode 1 - Data-processing operands:
   2200 // Get the value based on the shifter_operand with immediate.
   2201 int32_t Simulator::getImm(SimInstruction* instr, bool* carry_out) {
   2202  int rotate = instr->rotateValue() * 2;
   2203  int immed8 = instr->immed8Value();
   2204  int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
   2205  *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
   2206  return imm;
   2207 }
   2208 
   2209 int32_t Simulator::processPU(SimInstruction* instr, int num_regs, int reg_size,
   2210                             intptr_t* start_address, intptr_t* end_address) {
   2211  int rn = instr->rnValue();
   2212  int32_t rn_val = get_register(rn);
   2213  switch (instr->PUField()) {
   2214    case da_x:
   2215      MOZ_CRASH();
   2216      break;
   2217    case ia_x:
   2218      *start_address = rn_val;
   2219      *end_address = rn_val + (num_regs * reg_size) - reg_size;
   2220      rn_val = rn_val + (num_regs * reg_size);
   2221      break;
   2222    case db_x:
   2223      *start_address = rn_val - (num_regs * reg_size);
   2224      *end_address = rn_val - reg_size;
   2225      rn_val = *start_address;
   2226      break;
   2227    case ib_x:
   2228      *start_address = rn_val + reg_size;
   2229      *end_address = rn_val + (num_regs * reg_size);
   2230      rn_val = *end_address;
   2231      break;
   2232    default:
   2233      MOZ_CRASH();
   2234  }
   2235  return rn_val;
   2236 }
   2237 
   2238 // Addressing Mode 4 - Load and Store Multiple
   2239 void Simulator::handleRList(SimInstruction* instr, bool load) {
   2240  int rlist = instr->rlistValue();
   2241  int num_regs = mozilla::CountPopulation32(rlist);
   2242 
   2243  intptr_t start_address = 0;
   2244  intptr_t end_address = 0;
   2245  int32_t rn_val =
   2246      processPU(instr, num_regs, sizeof(void*), &start_address, &end_address);
   2247  intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
   2248 
   2249  // Catch null pointers a little earlier.
   2250  MOZ_ASSERT(start_address > 8191 || start_address < 0);
   2251 
   2252  int reg = 0;
   2253  while (rlist != 0) {
   2254    if ((rlist & 1) != 0) {
   2255      if (load) {
   2256        set_register(reg, *address);
   2257      } else {
   2258        *address = get_register(reg);
   2259      }
   2260      address += 1;
   2261    }
   2262    reg++;
   2263    rlist >>= 1;
   2264  }
   2265  MOZ_ASSERT(end_address == ((intptr_t)address) - 4);
   2266  if (instr->hasW()) {
   2267    set_register(instr->rnValue(), rn_val);
   2268  }
   2269 }
   2270 
   2271 // Addressing Mode 6 - Load and Store Multiple Coprocessor registers.
   2272 void Simulator::handleVList(SimInstruction* instr) {
   2273  VFPRegPrecision precision =
   2274      (instr->szValue() == 0) ? kSinglePrecision : kDoublePrecision;
   2275  int operand_size = (precision == kSinglePrecision) ? 4 : 8;
   2276  bool load = (instr->VLValue() == 0x1);
   2277 
   2278  int vd;
   2279  int num_regs;
   2280  vd = instr->VFPDRegValue(precision);
   2281  if (precision == kSinglePrecision) {
   2282    num_regs = instr->immed8Value();
   2283  } else {
   2284    num_regs = instr->immed8Value() / 2;
   2285  }
   2286 
   2287  intptr_t start_address = 0;
   2288  intptr_t end_address = 0;
   2289  int32_t rn_val =
   2290      processPU(instr, num_regs, operand_size, &start_address, &end_address);
   2291 
   2292  intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
   2293  for (int reg = vd; reg < vd + num_regs; reg++) {
   2294    if (precision == kSinglePrecision) {
   2295      if (load) {
   2296        set_s_register_from_sinteger(
   2297            reg, readW(reinterpret_cast<int32_t>(address), instr));
   2298      } else {
   2299        writeW(reinterpret_cast<int32_t>(address),
   2300               get_sinteger_from_s_register(reg), instr);
   2301      }
   2302      address += 1;
   2303    } else {
   2304      if (load) {
   2305        int32_t data[] = {readW(reinterpret_cast<int32_t>(address), instr),
   2306                          readW(reinterpret_cast<int32_t>(address + 1), instr)};
   2307        double d;
   2308        memcpy(&d, data, 8);
   2309        set_d_register_from_double(reg, d);
   2310      } else {
   2311        int32_t data[2];
   2312        double d;
   2313        get_double_from_d_register(reg, &d);
   2314        memcpy(data, &d, 8);
   2315        writeW(reinterpret_cast<int32_t>(address), data[0], instr);
   2316        writeW(reinterpret_cast<int32_t>(address + 1), data[1], instr);
   2317      }
   2318      address += 2;
   2319    }
   2320  }
   2321  MOZ_ASSERT(reinterpret_cast<intptr_t>(address) - operand_size == end_address);
   2322  if (instr->hasW()) {
   2323    set_register(instr->rnValue(), rn_val);
   2324  }
   2325 }
   2326 
   2327 ABI_FUNCTION_TYPE_SIM_PROTOTYPES
   2328 
   2329 // Fill the volatile registers with scratch values.
   2330 //
   2331 // Some of the ABI calls assume that the float registers are not scratched,
   2332 // even though the ABI defines them as volatile - a performance
   2333 // optimization. These are all calls passing operands in integer registers,
   2334 // so for now the simulator does not scratch any float registers for these
   2335 // calls. Should try to narrow it further in future.
   2336 //
   2337 void Simulator::scratchVolatileRegisters(void* target) {
   2338  // The ARM backend makes calls to __aeabi_idivmod and
   2339  // __aeabi_uidivmod assuming that the float registers are
   2340  // non-volatile as a performance optimization, so the float
   2341  // registers must not be scratch when calling these.
   2342  bool scratchFloat = target != __aeabi_idivmod && target != __aeabi_uidivmod;
   2343  int32_t scratch_value = 0xa5a5a5a5 ^ uint32_t(icount_);
   2344  set_register(r0, scratch_value);
   2345  set_register(r1, scratch_value);
   2346  set_register(r2, scratch_value);
   2347  set_register(r3, scratch_value);
   2348  set_register(r12, scratch_value);  // Intra-Procedure-call scratch register.
   2349  set_register(r14, scratch_value);  // Link register.
   2350 
   2351  if (scratchFloat) {
   2352    uint64_t scratch_value_d =
   2353        0x5a5a5a5a5a5a5a5aLU ^ uint64_t(icount_) ^ (uint64_t(icount_) << 30);
   2354    for (uint32_t i = d0; i < d8; i++) {
   2355      set_d_register(i, &scratch_value_d);
   2356    }
   2357    for (uint32_t i = d16; i < FloatRegisters::TotalPhys; i++) {
   2358      set_d_register(i, &scratch_value_d);
   2359    }
   2360  }
   2361 }
   2362 
   2363 static int64_t MakeInt64(int32_t first, int32_t second) {
   2364  // Little-endian order.
   2365  return ((int64_t)second << 32) | (uint32_t)first;
   2366 }
   2367 
   2368 // Software interrupt instructions are used by the simulator to call into C++.
   2369 void Simulator::softwareInterrupt(SimInstruction* instr) {
   2370  int svc = instr->svcValue();
   2371  switch (svc) {
   2372    case kCallRtRedirected: {
   2373      Redirection* redirection = Redirection::FromSwiInstruction(instr);
   2374      int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
   2375      int32_t a0 = get_register(r0);
   2376      int32_t a1 = get_register(r1);
   2377      int32_t a2 = get_register(r2);
   2378      int32_t a3 = get_register(r3);
   2379      float s0, s1, s2, s3, s4;
   2380      get_float_from_s_register(0, &s0);
   2381      get_float_from_s_register(0, &s1);
   2382      get_float_from_s_register(0, &s2);
   2383      get_float_from_s_register(0, &s3);
   2384      get_float_from_s_register(0, &s4);
   2385      double d0, d1, d2, d3, d4;
   2386      get_double_from_d_register(0, &d0);
   2387      get_double_from_d_register(1, &d1);
   2388      get_double_from_d_register(2, &d2);
   2389      get_double_from_d_register(3, &d3);
   2390      get_double_from_d_register(4, &d4);
   2391 
   2392      int32_t saved_lr = get_register(lr);
   2393      intptr_t external =
   2394          reinterpret_cast<intptr_t>(redirection->nativeFunction());
   2395 
   2396      bool stack_aligned = (get_register(sp) & (ABIStackAlignment - 1)) == 0;
   2397      if (!stack_aligned) {
   2398        fprintf(stderr, "Runtime call with unaligned stack!\n");
   2399        MOZ_CRASH();
   2400      }
   2401 
   2402      if (single_stepping_) {
   2403        single_step_callback_(single_step_callback_arg_, this, nullptr);
   2404      }
   2405 
   2406      switch (redirection->type()) {
   2407        ABI_FUNCTION_TYPE_ARM32_SIM_DISPATCH
   2408        default:
   2409          MOZ_CRASH("call");
   2410      }
   2411 
   2412      if (single_stepping_) {
   2413        single_step_callback_(single_step_callback_arg_, this, nullptr);
   2414      }
   2415 
   2416      set_register(lr, saved_lr);
   2417      set_pc(get_register(lr));
   2418      break;
   2419    }
   2420    case kBreakpoint: {
   2421      ArmDebugger dbg(this);
   2422      dbg.debug();
   2423      break;
   2424    }
   2425    default: {  // Stop uses all codes greater than 1 << 23.
   2426      if (svc >= (1 << 23)) {
   2427        uint32_t code = svc & kStopCodeMask;
   2428        if (isWatchedStop(code)) {
   2429          increaseStopCounter(code);
   2430        }
   2431 
   2432        // Stop if it is enabled, otherwise go on jumping over the stop and
   2433        // the message address.
   2434        if (isEnabledStop(code)) {
   2435          ArmDebugger dbg(this);
   2436          dbg.stop(instr);
   2437        } else {
   2438          set_pc(get_pc() + 2 * SimInstruction::kInstrSize);
   2439        }
   2440      } else {
   2441        // This is not a valid svc code.
   2442        MOZ_CRASH();
   2443        break;
   2444      }
   2445    }
   2446  }
   2447 }
   2448 
   2449 void Simulator::canonicalizeNaN(double* value) {
   2450  if (!wasm::CodeExists && !wasm::LookupCodeBlock(get_pc_as<void*>()) &&
   2451      FPSCR_default_NaN_mode_) {
   2452    *value = JS::CanonicalizeNaN(*value);
   2453  }
   2454 }
   2455 
   2456 void Simulator::canonicalizeNaN(float* value) {
   2457  if (!wasm::CodeExists && !wasm::LookupCodeBlock(get_pc_as<void*>()) &&
   2458      FPSCR_default_NaN_mode_) {
   2459    *value = JS::CanonicalizeNaN(*value);
   2460  }
   2461 }
   2462 
   2463 // Stop helper functions.
   2464 bool Simulator::isStopInstruction(SimInstruction* instr) {
   2465  return (instr->bits(27, 24) == 0xF) && (instr->svcValue() >= kStopCode);
   2466 }
   2467 
   2468 bool Simulator::isWatchedStop(uint32_t code) {
   2469  MOZ_ASSERT(code <= kMaxStopCode);
   2470  return code < kNumOfWatchedStops;
   2471 }
   2472 
   2473 bool Simulator::isEnabledStop(uint32_t code) {
   2474  MOZ_ASSERT(code <= kMaxStopCode);
   2475  // Unwatched stops are always enabled.
   2476  return !isWatchedStop(code) ||
   2477         !(watched_stops_[code].count & kStopDisabledBit);
   2478 }
   2479 
   2480 void Simulator::enableStop(uint32_t code) {
   2481  MOZ_ASSERT(isWatchedStop(code));
   2482  if (!isEnabledStop(code)) {
   2483    watched_stops_[code].count &= ~kStopDisabledBit;
   2484  }
   2485 }
   2486 
   2487 void Simulator::disableStop(uint32_t code) {
   2488  MOZ_ASSERT(isWatchedStop(code));
   2489  if (isEnabledStop(code)) {
   2490    watched_stops_[code].count |= kStopDisabledBit;
   2491  }
   2492 }
   2493 
   2494 void Simulator::increaseStopCounter(uint32_t code) {
   2495  MOZ_ASSERT(code <= kMaxStopCode);
   2496  MOZ_ASSERT(isWatchedStop(code));
   2497  if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
   2498    printf(
   2499        "Stop counter for code %i has overflowed.\n"
   2500        "Enabling this code and reseting the counter to 0.\n",
   2501        code);
   2502    watched_stops_[code].count = 0;
   2503    enableStop(code);
   2504  } else {
   2505    watched_stops_[code].count++;
   2506  }
   2507 }
   2508 
   2509 // Print a stop status.
   2510 void Simulator::printStopInfo(uint32_t code) {
   2511  MOZ_ASSERT(code <= kMaxStopCode);
   2512  if (!isWatchedStop(code)) {
   2513    printf("Stop not watched.");
   2514  } else {
   2515    const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
   2516    int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
   2517    // Don't print the state of unused breakpoints.
   2518    if (count != 0) {
   2519      if (watched_stops_[code].desc) {
   2520        printf("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code,
   2521               state, count, watched_stops_[code].desc);
   2522      } else {
   2523        printf("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state,
   2524               count);
   2525      }
   2526    }
   2527  }
   2528 }
   2529 
   2530 // Instruction types 0 and 1 are both rolled into one function because they only
   2531 // differ in the handling of the shifter_operand.
   2532 void Simulator::decodeType01(SimInstruction* instr) {
   2533  int type = instr->typeValue();
   2534  if (type == 0 && instr->isSpecialType0()) {
   2535    // Multiply instruction or extra loads and stores.
   2536    if (instr->bits(7, 4) == 9) {
   2537      if (instr->bit(24) == 0) {
   2538        // Raw field decoding here. Multiply instructions have their Rd
   2539        // in funny places.
   2540        int rn = instr->rnValue();
   2541        int rm = instr->rmValue();
   2542        int rs = instr->rsValue();
   2543        int32_t rs_val = get_register(rs);
   2544        int32_t rm_val = get_register(rm);
   2545        if (instr->bit(23) == 0) {
   2546          if (instr->bit(21) == 0) {
   2547            // The MUL instruction description (A 4.1.33) refers to
   2548            // Rd as being the destination for the operation, but it
   2549            // confusingly uses the Rn field to encode it.
   2550            int rd = rn;  // Remap the rn field to the Rd register.
   2551            int32_t alu_out = rm_val * rs_val;
   2552            set_register(rd, alu_out);
   2553            if (instr->hasS()) {
   2554              setNZFlags(alu_out);
   2555            }
   2556          } else {
   2557            int rd = instr->rdValue();
   2558            int32_t acc_value = get_register(rd);
   2559            if (instr->bit(22) == 0) {
   2560              // The MLA instruction description (A 4.1.28) refers
   2561              // to the order of registers as "Rd, Rm, Rs,
   2562              // Rn". But confusingly it uses the Rn field to
   2563              // encode the Rd register and the Rd field to encode
   2564              // the Rn register.
   2565              int32_t mul_out = rm_val * rs_val;
   2566              int32_t result = acc_value + mul_out;
   2567              set_register(rn, result);
   2568            } else {
   2569              int32_t mul_out = rm_val * rs_val;
   2570              int32_t result = acc_value - mul_out;
   2571              set_register(rn, result);
   2572            }
   2573          }
   2574        } else {
   2575          // The signed/long multiply instructions use the terms RdHi
   2576          // and RdLo when referring to the target registers. They are
   2577          // mapped to the Rn and Rd fields as follows:
   2578          // RdLo == Rd
   2579          // RdHi == Rn (This is confusingly stored in variable rd here
   2580          //             because the mul instruction from above uses the
   2581          //             Rn field to encode the Rd register. Good luck figuring
   2582          //             this out without reading the ARM instruction manual
   2583          //             at a very detailed level.)
   2584          int rd_hi = rn;  // Remap the rn field to the RdHi register.
   2585          int rd_lo = instr->rdValue();
   2586          int32_t hi_res = 0;
   2587          int32_t lo_res = 0;
   2588          if (instr->bit(22) == 1) {
   2589            int64_t left_op = static_cast<int32_t>(rm_val);
   2590            int64_t right_op = static_cast<int32_t>(rs_val);
   2591            uint64_t result = left_op * right_op;
   2592            hi_res = static_cast<int32_t>(result >> 32);
   2593            lo_res = static_cast<int32_t>(result & 0xffffffff);
   2594          } else {
   2595            // Unsigned multiply.
   2596            uint64_t left_op = static_cast<uint32_t>(rm_val);
   2597            uint64_t right_op = static_cast<uint32_t>(rs_val);
   2598            uint64_t result = left_op * right_op;
   2599            hi_res = static_cast<int32_t>(result >> 32);
   2600            lo_res = static_cast<int32_t>(result & 0xffffffff);
   2601          }
   2602          set_register(rd_lo, lo_res);
   2603          set_register(rd_hi, hi_res);
   2604          if (instr->hasS()) {
   2605            MOZ_CRASH();
   2606          }
   2607        }
   2608      } else {
   2609        if (instr->bits(excl::ExclusiveOpHi, excl::ExclusiveOpLo) ==
   2610            excl::ExclusiveOpcode) {
   2611          // Load-exclusive / store-exclusive.
   2612          if (instr->bit(excl::ExclusiveLoad)) {
   2613            int rn = instr->rnValue();
   2614            int rt = instr->rtValue();
   2615            int32_t address = get_register(rn);
   2616            switch (instr->bits(excl::ExclusiveSizeHi, excl::ExclusiveSizeLo)) {
   2617              case excl::ExclusiveWord:
   2618                set_register(rt, readExW(address, instr));
   2619                break;
   2620              case excl::ExclusiveDouble: {
   2621                MOZ_ASSERT((rt % 2) == 0);
   2622                int32_t hibits;
   2623                int32_t lobits = readExDW(address, &hibits);
   2624                set_register(rt, lobits);
   2625                set_register(rt + 1, hibits);
   2626                break;
   2627              }
   2628              case excl::ExclusiveByte:
   2629                set_register(rt, readExBU(address));
   2630                break;
   2631              case excl::ExclusiveHalf:
   2632                set_register(rt, readExHU(address, instr));
   2633                break;
   2634            }
   2635          } else {
   2636            int rn = instr->rnValue();
   2637            int rd = instr->rdValue();
   2638            int rt = instr->bits(3, 0);
   2639            int32_t address = get_register(rn);
   2640            int32_t value = get_register(rt);
   2641            int32_t result = 0;
   2642            switch (instr->bits(excl::ExclusiveSizeHi, excl::ExclusiveSizeLo)) {
   2643              case excl::ExclusiveWord:
   2644                result = writeExW(address, value, instr);
   2645                break;
   2646              case excl::ExclusiveDouble: {
   2647                MOZ_ASSERT((rt % 2) == 0);
   2648                int32_t value2 = get_register(rt + 1);
   2649                result = writeExDW(address, value, value2);
   2650                break;
   2651              }
   2652              case excl::ExclusiveByte:
   2653                result = writeExB(address, (uint8_t)value);
   2654                break;
   2655              case excl::ExclusiveHalf:
   2656                result = writeExH(address, (uint16_t)value, instr);
   2657                break;
   2658            }
   2659            set_register(rd, result);
   2660          }
   2661        } else {
   2662          MOZ_CRASH();  // Not used atm
   2663        }
   2664      }
   2665    } else {
   2666      // Extra load/store instructions.
   2667      int rd = instr->rdValue();
   2668      int rn = instr->rnValue();
   2669      int32_t rn_val = get_register(rn);
   2670      int32_t addr = 0;
   2671      if (instr->bit(22) == 0) {
   2672        int rm = instr->rmValue();
   2673        int32_t rm_val = get_register(rm);
   2674        switch (instr->PUField()) {
   2675          case da_x:
   2676            MOZ_ASSERT(!instr->hasW());
   2677            addr = rn_val;
   2678            rn_val -= rm_val;
   2679            set_register(rn, rn_val);
   2680            break;
   2681          case ia_x:
   2682            MOZ_ASSERT(!instr->hasW());
   2683            addr = rn_val;
   2684            rn_val += rm_val;
   2685            set_register(rn, rn_val);
   2686            break;
   2687          case db_x:
   2688            rn_val -= rm_val;
   2689            addr = rn_val;
   2690            if (instr->hasW()) {
   2691              set_register(rn, rn_val);
   2692            }
   2693            break;
   2694          case ib_x:
   2695            rn_val += rm_val;
   2696            addr = rn_val;
   2697            if (instr->hasW()) {
   2698              set_register(rn, rn_val);
   2699            }
   2700            break;
   2701          default:
   2702            // The PU field is a 2-bit field.
   2703            MOZ_CRASH();
   2704            break;
   2705        }
   2706      } else {
   2707        int32_t imm_val = (instr->immedHValue() << 4) | instr->immedLValue();
   2708        switch (instr->PUField()) {
   2709          case da_x:
   2710            MOZ_ASSERT(!instr->hasW());
   2711            addr = rn_val;
   2712            rn_val -= imm_val;
   2713            set_register(rn, rn_val);
   2714            break;
   2715          case ia_x:
   2716            MOZ_ASSERT(!instr->hasW());
   2717            addr = rn_val;
   2718            rn_val += imm_val;
   2719            set_register(rn, rn_val);
   2720            break;
   2721          case db_x:
   2722            rn_val -= imm_val;
   2723            addr = rn_val;
   2724            if (instr->hasW()) {
   2725              set_register(rn, rn_val);
   2726            }
   2727            break;
   2728          case ib_x:
   2729            rn_val += imm_val;
   2730            addr = rn_val;
   2731            if (instr->hasW()) {
   2732              set_register(rn, rn_val);
   2733            }
   2734            break;
   2735          default:
   2736            // The PU field is a 2-bit field.
   2737            MOZ_CRASH();
   2738            break;
   2739        }
   2740      }
   2741      if ((instr->bits(7, 4) & 0xd) == 0xd && instr->bit(20) == 0) {
   2742        MOZ_ASSERT((rd % 2) == 0);
   2743        if (instr->hasH()) {
   2744          // The strd instruction.
   2745          int32_t value1 = get_register(rd);
   2746          int32_t value2 = get_register(rd + 1);
   2747          writeDW(addr, value1, value2);
   2748        } else {
   2749          // The ldrd instruction.
   2750          int* rn_data = readDW(addr);
   2751          if (rn_data) {
   2752            set_dw_register(rd, rn_data);
   2753          }
   2754        }
   2755      } else if (instr->hasH()) {
   2756        if (instr->hasSign()) {
   2757          if (instr->hasL()) {
   2758            int16_t val = readH(addr, instr);
   2759            set_register(rd, val);
   2760          } else {
   2761            int16_t val = get_register(rd);
   2762            writeH(addr, val, instr);
   2763          }
   2764        } else {
   2765          if (instr->hasL()) {
   2766            uint16_t val = readHU(addr, instr);
   2767            set_register(rd, val);
   2768          } else {
   2769            uint16_t val = get_register(rd);
   2770            writeH(addr, val, instr);
   2771          }
   2772        }
   2773      } else {
   2774        // Signed byte loads.
   2775        MOZ_ASSERT(instr->hasSign());
   2776        MOZ_ASSERT(instr->hasL());
   2777        int8_t val = readB(addr);
   2778        set_register(rd, val);
   2779      }
   2780      return;
   2781    }
   2782  } else if ((type == 0) && instr->isMiscType0()) {
   2783    if (instr->bits(7, 4) == 0) {
   2784      if (instr->bit(21) == 0) {
   2785        // mrs
   2786        int rd = instr->rdValue();
   2787        uint32_t flags;
   2788        if (instr->bit(22) == 0) {
   2789          // CPSR. Note: The Q flag is not yet implemented!
   2790          flags = (n_flag_ << 31) | (z_flag_ << 30) | (c_flag_ << 29) |
   2791                  (v_flag_ << 28);
   2792        } else {
   2793          // SPSR
   2794          MOZ_CRASH();
   2795        }
   2796        set_register(rd, flags);
   2797      } else {
   2798        // msr
   2799        if (instr->bits(27, 23) == 2) {
   2800          // Register operand. For now we only emit mask 0b1100.
   2801          int rm = instr->rmValue();
   2802          mozilla::DebugOnly<uint32_t> mask = instr->bits(19, 16);
   2803          MOZ_ASSERT(mask == (3 << 2));
   2804 
   2805          uint32_t flags = get_register(rm);
   2806          n_flag_ = (flags >> 31) & 1;
   2807          z_flag_ = (flags >> 30) & 1;
   2808          c_flag_ = (flags >> 29) & 1;
   2809          v_flag_ = (flags >> 28) & 1;
   2810        } else {
   2811          MOZ_CRASH();
   2812        }
   2813      }
   2814    } else if (instr->bits(22, 21) == 1) {
   2815      int rm = instr->rmValue();
   2816      switch (instr->bits(7, 4)) {
   2817        case 1:  // BX
   2818          set_pc(get_register(rm));
   2819          break;
   2820        case 3: {  // BLX
   2821          uint32_t old_pc = get_pc();
   2822          set_pc(get_register(rm));
   2823          set_register(lr, old_pc + SimInstruction::kInstrSize);
   2824          break;
   2825        }
   2826        case 7: {  // BKPT
   2827          fprintf(stderr, "Simulator hit BKPT.\n");
   2828          if (getenv("ARM_SIM_DEBUGGER")) {
   2829            ArmDebugger dbg(this);
   2830            dbg.debug();
   2831          } else {
   2832            fprintf(stderr,
   2833                    "Use ARM_SIM_DEBUGGER=1 to enter the builtin debugger.\n");
   2834            MOZ_CRASH("ARM simulator breakpoint");
   2835          }
   2836          break;
   2837        }
   2838        default:
   2839          MOZ_CRASH();
   2840      }
   2841    } else if (instr->bits(22, 21) == 3) {
   2842      int rm = instr->rmValue();
   2843      int rd = instr->rdValue();
   2844      switch (instr->bits(7, 4)) {
   2845        case 1: {  // CLZ
   2846          uint32_t bits = get_register(rm);
   2847          int leading_zeros = 0;
   2848          if (bits == 0) {
   2849            leading_zeros = 32;
   2850          } else {
   2851            leading_zeros = mozilla::CountLeadingZeroes32(bits);
   2852          }
   2853          set_register(rd, leading_zeros);
   2854          break;
   2855        }
   2856        default:
   2857          MOZ_CRASH();
   2858          break;
   2859      }
   2860    } else {
   2861      printf("%08x\n", instr->instructionBits());
   2862      MOZ_CRASH();
   2863    }
   2864  } else if ((type == 1) && instr->isNopType1()) {
   2865    // NOP.
   2866  } else if ((type == 1) && instr->isYieldType1()) {
   2867    AtomicOperations::pause();
   2868  } else if ((type == 1) && instr->isCsdbType1()) {
   2869    // Speculation barrier. (No-op for the simulator)
   2870  } else {
   2871    int rd = instr->rdValue();
   2872    int rn = instr->rnValue();
   2873    // Use uint32_t here for integer overflow in operations below not to be
   2874    // undefined behavior, leading to our own calculations of overflow being
   2875    // messed up by the compiler.
   2876    uint32_t rn_val = get_register(rn);
   2877    uint32_t shifter_operand = 0;
   2878    bool shifter_carry_out = 0;
   2879    if (type == 0) {
   2880      shifter_operand = getShiftRm(instr, &shifter_carry_out);
   2881    } else {
   2882      MOZ_ASSERT(instr->typeValue() == 1);
   2883      shifter_operand = getImm(instr, &shifter_carry_out);
   2884    }
   2885    int32_t alu_out;
   2886    switch (instr->opcodeField()) {
   2887      case OpAnd:
   2888        alu_out = rn_val & shifter_operand;
   2889        set_register(rd, alu_out);
   2890        if (instr->hasS()) {
   2891          setNZFlags(alu_out);
   2892          setCFlag(shifter_carry_out);
   2893        }
   2894        break;
   2895      case OpEor:
   2896        alu_out = rn_val ^ shifter_operand;
   2897        set_register(rd, alu_out);
   2898        if (instr->hasS()) {
   2899          setNZFlags(alu_out);
   2900          setCFlag(shifter_carry_out);
   2901        }
   2902        break;
   2903      case OpSub:
   2904        alu_out = rn_val - shifter_operand;
   2905        set_register(rd, alu_out);
   2906        if (instr->hasS()) {
   2907          setNZFlags(alu_out);
   2908          setCFlag(!borrowFrom(rn_val, shifter_operand));
   2909          setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, false));
   2910        }
   2911        break;
   2912      case OpRsb:
   2913        alu_out = shifter_operand - rn_val;
   2914        set_register(rd, alu_out);
   2915        if (instr->hasS()) {
   2916          setNZFlags(alu_out);
   2917          setCFlag(!borrowFrom(shifter_operand, rn_val));
   2918          setVFlag(overflowFrom(alu_out, shifter_operand, rn_val, false));
   2919        }
   2920        break;
   2921      case OpAdd:
   2922        alu_out = rn_val + shifter_operand;
   2923        set_register(rd, alu_out);
   2924        if (instr->hasS()) {
   2925          setNZFlags(alu_out);
   2926          setCFlag(carryFrom(rn_val, shifter_operand));
   2927          setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true));
   2928        }
   2929        break;
   2930      case OpAdc:
   2931        alu_out = rn_val + shifter_operand + getCarry();
   2932        set_register(rd, alu_out);
   2933        if (instr->hasS()) {
   2934          setNZFlags(alu_out);
   2935          setCFlag(carryFrom(rn_val, shifter_operand, getCarry()));
   2936          setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true));
   2937        }
   2938        break;
   2939      case OpSbc:
   2940        alu_out = rn_val - shifter_operand - (getCarry() == 0 ? 1 : 0);
   2941        set_register(rd, alu_out);
   2942        if (instr->hasS()) {
   2943          MOZ_CRASH();
   2944        }
   2945        break;
   2946      case OpRsc:
   2947        alu_out = shifter_operand - rn_val - (getCarry() == 0 ? 1 : 0);
   2948        set_register(rd, alu_out);
   2949        if (instr->hasS()) {
   2950          MOZ_CRASH();
   2951        }
   2952        break;
   2953      case OpTst:
   2954        if (instr->hasS()) {
   2955          alu_out = rn_val & shifter_operand;
   2956          setNZFlags(alu_out);
   2957          setCFlag(shifter_carry_out);
   2958        } else {
   2959          alu_out = instr->immedMovwMovtValue();
   2960          set_register(rd, alu_out);
   2961        }
   2962        break;
   2963      case OpTeq:
   2964        if (instr->hasS()) {
   2965          alu_out = rn_val ^ shifter_operand;
   2966          setNZFlags(alu_out);
   2967          setCFlag(shifter_carry_out);
   2968        } else {
   2969          // Other instructions matching this pattern are handled in the
   2970          // miscellaneous instructions part above.
   2971          MOZ_CRASH();
   2972        }
   2973        break;
   2974      case OpCmp:
   2975        if (instr->hasS()) {
   2976          alu_out = rn_val - shifter_operand;
   2977          setNZFlags(alu_out);
   2978          setCFlag(!borrowFrom(rn_val, shifter_operand));
   2979          setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, false));
   2980        } else {
   2981          alu_out =
   2982              (get_register(rd) & 0xffff) | (instr->immedMovwMovtValue() << 16);
   2983          set_register(rd, alu_out);
   2984        }
   2985        break;
   2986      case OpCmn:
   2987        if (instr->hasS()) {
   2988          alu_out = rn_val + shifter_operand;
   2989          setNZFlags(alu_out);
   2990          setCFlag(carryFrom(rn_val, shifter_operand));
   2991          setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true));
   2992        } else {
   2993          // Other instructions matching this pattern are handled in the
   2994          // miscellaneous instructions part above.
   2995          MOZ_CRASH();
   2996        }
   2997        break;
   2998      case OpOrr:
   2999        alu_out = rn_val | shifter_operand;
   3000        set_register(rd, alu_out);
   3001        if (instr->hasS()) {
   3002          setNZFlags(alu_out);
   3003          setCFlag(shifter_carry_out);
   3004        }
   3005        break;
   3006      case OpMov:
   3007        alu_out = shifter_operand;
   3008        set_register(rd, alu_out);
   3009        if (instr->hasS()) {
   3010          setNZFlags(alu_out);
   3011          setCFlag(shifter_carry_out);
   3012        }
   3013        break;
   3014      case OpBic:
   3015        alu_out = rn_val & ~shifter_operand;
   3016        set_register(rd, alu_out);
   3017        if (instr->hasS()) {
   3018          setNZFlags(alu_out);
   3019          setCFlag(shifter_carry_out);
   3020        }
   3021        break;
   3022      case OpMvn:
   3023        alu_out = ~shifter_operand;
   3024        set_register(rd, alu_out);
   3025        if (instr->hasS()) {
   3026          setNZFlags(alu_out);
   3027          setCFlag(shifter_carry_out);
   3028        }
   3029        break;
   3030      default:
   3031        MOZ_CRASH();
   3032        break;
   3033    }
   3034  }
   3035 }
   3036 
   3037 void Simulator::decodeType2(SimInstruction* instr) {
   3038  int rd = instr->rdValue();
   3039  int rn = instr->rnValue();
   3040  int32_t rn_val = get_register(rn);
   3041  int32_t im_val = instr->offset12Value();
   3042  int32_t addr = 0;
   3043  switch (instr->PUField()) {
   3044    case da_x:
   3045      MOZ_ASSERT(!instr->hasW());
   3046      addr = rn_val;
   3047      rn_val -= im_val;
   3048      set_register(rn, rn_val);
   3049      break;
   3050    case ia_x:
   3051      MOZ_ASSERT(!instr->hasW());
   3052      addr = rn_val;
   3053      rn_val += im_val;
   3054      set_register(rn, rn_val);
   3055      break;
   3056    case db_x:
   3057      rn_val -= im_val;
   3058      addr = rn_val;
   3059      if (instr->hasW()) {
   3060        set_register(rn, rn_val);
   3061      }
   3062      break;
   3063    case ib_x:
   3064      rn_val += im_val;
   3065      addr = rn_val;
   3066      if (instr->hasW()) {
   3067        set_register(rn, rn_val);
   3068      }
   3069      break;
   3070    default:
   3071      MOZ_CRASH();
   3072      break;
   3073  }
   3074  if (instr->hasB()) {
   3075    if (instr->hasL()) {
   3076      uint8_t val = readBU(addr);
   3077      set_register(rd, val);
   3078    } else {
   3079      uint8_t val = get_register(rd);
   3080      writeB(addr, val);
   3081    }
   3082  } else {
   3083    if (instr->hasL()) {
   3084      set_register(rd, readW(addr, instr, AllowUnaligned));
   3085    } else {
   3086      writeW(addr, get_register(rd), instr, AllowUnaligned);
   3087    }
   3088  }
   3089 }
   3090 
   3091 static uint32_t rotateBytes(uint32_t val, int32_t rotate) {
   3092  switch (rotate) {
   3093    default:
   3094      return val;
   3095    case 1:
   3096      return (val >> 8) | (val << 24);
   3097    case 2:
   3098      return (val >> 16) | (val << 16);
   3099    case 3:
   3100      return (val >> 24) | (val << 8);
   3101  }
   3102 }
   3103 
   3104 void Simulator::decodeType3(SimInstruction* instr) {
   3105  if (MOZ_UNLIKELY(instr->isUDF())) {
   3106    uint8_t* newPC;
   3107    if (wasm::HandleIllegalInstruction(registerState(), &newPC)) {
   3108      set_pc((int32_t)newPC);
   3109      return;
   3110    }
   3111    MOZ_CRASH("illegal instruction encountered");
   3112  }
   3113 
   3114  int rd = instr->rdValue();
   3115  int rn = instr->rnValue();
   3116  int32_t rn_val = get_register(rn);
   3117  bool shifter_carry_out = 0;
   3118  int32_t shifter_operand = getShiftRm(instr, &shifter_carry_out);
   3119  int32_t addr = 0;
   3120  switch (instr->PUField()) {
   3121    case da_x:
   3122      MOZ_ASSERT(!instr->hasW());
   3123      MOZ_CRASH();
   3124      break;
   3125    case ia_x: {
   3126      if (instr->bit(4) == 0) {
   3127        // Memop.
   3128      } else {
   3129        if (instr->bit(5) == 0) {
   3130          switch (instr->bits(22, 21)) {
   3131            case 0:
   3132              if (instr->bit(20) == 0) {
   3133                if (instr->bit(6) == 0) {
   3134                  // Pkhbt.
   3135                  uint32_t rn_val = get_register(rn);
   3136                  uint32_t rm_val = get_register(instr->rmValue());
   3137                  int32_t shift = instr->bits(11, 7);
   3138                  rm_val <<= shift;
   3139                  set_register(rd, (rn_val & 0xFFFF) | (rm_val & 0xFFFF0000U));
   3140                } else {
   3141                  // Pkhtb.
   3142                  uint32_t rn_val = get_register(rn);
   3143                  int32_t rm_val = get_register(instr->rmValue());
   3144                  int32_t shift = instr->bits(11, 7);
   3145                  if (shift == 0) {
   3146                    shift = 32;
   3147                  }
   3148                  rm_val >>= shift;
   3149                  set_register(rd, (rn_val & 0xFFFF0000U) | (rm_val & 0xFFFF));
   3150                }
   3151              } else {
   3152                MOZ_CRASH();
   3153              }
   3154              break;
   3155            case 1:
   3156              MOZ_CRASH();
   3157              break;
   3158            case 2:
   3159              MOZ_CRASH();
   3160              break;
   3161            case 3: {
   3162              // Usat.
   3163              int32_t sat_pos = instr->bits(20, 16);
   3164              int32_t sat_val = (1 << sat_pos) - 1;
   3165              int32_t shift = instr->bits(11, 7);
   3166              int32_t shift_type = instr->bit(6);
   3167              int32_t rm_val = get_register(instr->rmValue());
   3168              if (shift_type == 0) {  // LSL
   3169                rm_val <<= shift;
   3170              } else {  // ASR
   3171                rm_val >>= shift;
   3172              }
   3173 
   3174              // If saturation occurs, the Q flag should be set in the
   3175              // CPSR. There is no Q flag yet, and no instruction (MRS)
   3176              // to read the CPSR directly.
   3177              if (rm_val > sat_val) {
   3178                rm_val = sat_val;
   3179              } else if (rm_val < 0) {
   3180                rm_val = 0;
   3181              }
   3182              set_register(rd, rm_val);
   3183              break;
   3184            }
   3185          }
   3186        } else {
   3187          switch (instr->bits(22, 21)) {
   3188            case 0:
   3189              MOZ_CRASH();
   3190              break;
   3191            case 1:
   3192              if (instr->bits(7, 4) == 7 && instr->bits(19, 16) == 15) {
   3193                uint32_t rm_val = rotateBytes(get_register(instr->rmValue()),
   3194                                              instr->bits(11, 10));
   3195                if (instr->bit(20)) {
   3196                  // Sxth.
   3197                  set_register(rd, (int32_t)(int16_t)(rm_val & 0xFFFF));
   3198                } else {
   3199                  // Sxtb.
   3200                  set_register(rd, (int32_t)(int8_t)(rm_val & 0xFF));
   3201                }
   3202              } else if (instr->bits(20, 16) == 0b1'1111 &&
   3203                         instr->bits(11, 4) == 0b1111'0011) {
   3204                // Rev
   3205                uint32_t rm_val = get_register(instr->rmValue());
   3206 
   3207                static_assert(MOZ_LITTLE_ENDIAN());
   3208                set_register(rd,
   3209                             mozilla::NativeEndian::swapToBigEndian(rm_val));
   3210              } else if (instr->bits(20, 16) == 0b1'1111 &&
   3211                         instr->bits(11, 4) == 0b1111'1011) {
   3212                // Rev16
   3213                uint32_t rm_val = get_register(instr->rmValue());
   3214 
   3215                static_assert(MOZ_LITTLE_ENDIAN());
   3216                uint32_t hi = mozilla::NativeEndian::swapToBigEndian(
   3217                    uint16_t(rm_val >> 16));
   3218                uint32_t lo =
   3219                    mozilla::NativeEndian::swapToBigEndian(uint16_t(rm_val));
   3220                set_register(rd, (hi << 16) | lo);
   3221              } else {
   3222                MOZ_CRASH();
   3223              }
   3224              break;
   3225            case 2:
   3226              if ((instr->bit(20) == 0) && (instr->bits(9, 6) == 1)) {
   3227                if (instr->bits(19, 16) == 0xF) {
   3228                  // Uxtb16.
   3229                  uint32_t rm_val = rotateBytes(get_register(instr->rmValue()),
   3230                                                instr->bits(11, 10));
   3231                  set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
   3232                } else {
   3233                  MOZ_CRASH();
   3234                }
   3235              } else {
   3236                MOZ_CRASH();
   3237              }
   3238              break;
   3239            case 3:
   3240              if ((instr->bit(20) == 0) && (instr->bits(9, 6) == 1)) {
   3241                if (instr->bits(19, 16) == 0xF) {
   3242                  // Uxtb.
   3243                  uint32_t rm_val = rotateBytes(get_register(instr->rmValue()),
   3244                                                instr->bits(11, 10));
   3245                  set_register(rd, (rm_val & 0xFF));
   3246                } else {
   3247                  // Uxtab.
   3248                  uint32_t rn_val = get_register(rn);
   3249                  uint32_t rm_val = rotateBytes(get_register(instr->rmValue()),
   3250                                                instr->bits(11, 10));
   3251                  set_register(rd, rn_val + (rm_val & 0xFF));
   3252                }
   3253              } else if ((instr->bit(20) == 1) && (instr->bits(9, 6) == 1)) {
   3254                if (instr->bits(19, 16) == 0xF) {
   3255                  // Uxth.
   3256                  uint32_t rm_val = rotateBytes(get_register(instr->rmValue()),
   3257                                                instr->bits(11, 10));
   3258                  set_register(rd, (rm_val & 0xFFFF));
   3259                } else {
   3260                  // Uxtah.
   3261                  uint32_t rn_val = get_register(rn);
   3262                  uint32_t rm_val = rotateBytes(get_register(instr->rmValue()),
   3263                                                instr->bits(11, 10));
   3264                  set_register(rd, rn_val + (rm_val & 0xFFFF));
   3265                }
   3266              } else if (instr->bits(20, 16) == 0b1'1111 &&
   3267                         instr->bits(11, 4) == 0b1111'1011) {
   3268                // Revsh
   3269                uint32_t rm_val = get_register(instr->rmValue());
   3270 
   3271                static_assert(MOZ_LITTLE_ENDIAN());
   3272                set_register(
   3273                    rd, int32_t(int16_t(mozilla::NativeEndian::swapToBigEndian(
   3274                            uint16_t(rm_val)))));
   3275              } else {
   3276                MOZ_CRASH();
   3277              }
   3278              break;
   3279          }
   3280        }
   3281        return;
   3282      }
   3283      break;
   3284    }
   3285    case db_x: {  // sudiv
   3286      if (instr->bit(22) == 0x0 && instr->bit(20) == 0x1 &&
   3287          instr->bits(15, 12) == 0x0f && instr->bits(7, 4) == 0x1) {
   3288        if (!instr->hasW()) {
   3289          // sdiv (in V8 notation matching ARM ISA format) rn = rm/rs.
   3290          int rm = instr->rmValue();
   3291          int32_t rm_val = get_register(rm);
   3292          int rs = instr->rsValue();
   3293          int32_t rs_val = get_register(rs);
   3294          int32_t ret_val = 0;
   3295          MOZ_ASSERT(rs_val != 0);
   3296          if ((rm_val == INT32_MIN) && (rs_val == -1)) {
   3297            ret_val = INT32_MIN;
   3298          } else {
   3299            ret_val = rm_val / rs_val;
   3300          }
   3301          set_register(rn, ret_val);
   3302          return;
   3303        } else {
   3304          // udiv (in V8 notation matching ARM ISA format) rn = rm/rs.
   3305          int rm = instr->rmValue();
   3306          uint32_t rm_val = get_register(rm);
   3307          int rs = instr->rsValue();
   3308          uint32_t rs_val = get_register(rs);
   3309          uint32_t ret_val = 0;
   3310          MOZ_ASSERT(rs_val != 0);
   3311          ret_val = rm_val / rs_val;
   3312          set_register(rn, ret_val);
   3313          return;
   3314        }
   3315      }
   3316 
   3317      addr = rn_val - shifter_operand;
   3318      if (instr->hasW()) {
   3319        set_register(rn, addr);
   3320      }
   3321      break;
   3322    }
   3323    case ib_x: {
   3324      if (instr->hasW() && (instr->bits(6, 4) == 0x5)) {
   3325        uint32_t widthminus1 = static_cast<uint32_t>(instr->bits(20, 16));
   3326        uint32_t lsbit = static_cast<uint32_t>(instr->bits(11, 7));
   3327        uint32_t msbit = widthminus1 + lsbit;
   3328        if (msbit <= 31) {
   3329          if (instr->bit(22)) {
   3330            // ubfx - unsigned bitfield extract.
   3331            uint32_t rm_val =
   3332                static_cast<uint32_t>(get_register(instr->rmValue()));
   3333            uint32_t extr_val = rm_val << (31 - msbit);
   3334            extr_val = extr_val >> (31 - widthminus1);
   3335            set_register(instr->rdValue(), extr_val);
   3336          } else {
   3337            // sbfx - signed bitfield extract.
   3338            int32_t rm_val = get_register(instr->rmValue());
   3339            int32_t extr_val = rm_val << (31 - msbit);
   3340            extr_val = extr_val >> (31 - widthminus1);
   3341            set_register(instr->rdValue(), extr_val);
   3342          }
   3343        } else {
   3344          MOZ_CRASH();
   3345        }
   3346        return;
   3347      } else if (!instr->hasW() && (instr->bits(6, 4) == 0x1)) {
   3348        uint32_t lsbit = static_cast<uint32_t>(instr->bits(11, 7));
   3349        uint32_t msbit = static_cast<uint32_t>(instr->bits(20, 16));
   3350        if (msbit >= lsbit) {
   3351          // bfc or bfi - bitfield clear/insert.
   3352          uint32_t rd_val =
   3353              static_cast<uint32_t>(get_register(instr->rdValue()));
   3354          uint32_t bitcount = msbit - lsbit + 1;
   3355          uint32_t mask = (1 << bitcount) - 1;
   3356          rd_val &= ~(mask << lsbit);
   3357          if (instr->rmValue() != 15) {
   3358            // bfi - bitfield insert.
   3359            uint32_t rm_val =
   3360                static_cast<uint32_t>(get_register(instr->rmValue()));
   3361            rm_val &= mask;
   3362            rd_val |= rm_val << lsbit;
   3363          }
   3364          set_register(instr->rdValue(), rd_val);
   3365        } else {
   3366          MOZ_CRASH();
   3367        }
   3368        return;
   3369      } else {
   3370        addr = rn_val + shifter_operand;
   3371        if (instr->hasW()) {
   3372          set_register(rn, addr);
   3373        }
   3374      }
   3375      break;
   3376    }
   3377    default:
   3378      MOZ_CRASH();
   3379      break;
   3380  }
   3381  if (instr->hasB()) {
   3382    if (instr->hasL()) {
   3383      uint8_t byte = readB(addr);
   3384      set_register(rd, byte);
   3385    } else {
   3386      uint8_t byte = get_register(rd);
   3387      writeB(addr, byte);
   3388    }
   3389  } else {
   3390    if (instr->hasL()) {
   3391      set_register(rd, readW(addr, instr, AllowUnaligned));
   3392    } else {
   3393      writeW(addr, get_register(rd), instr, AllowUnaligned);
   3394    }
   3395  }
   3396 }
   3397 
   3398 void Simulator::decodeType4(SimInstruction* instr) {
   3399  // Only allowed to be set in privileged mode.
   3400  MOZ_ASSERT(instr->bit(22) == 0);
   3401  bool load = instr->hasL();
   3402  handleRList(instr, load);
   3403 }
   3404 
   3405 void Simulator::decodeType5(SimInstruction* instr) {
   3406  int off = instr->sImmed24Value() << 2;
   3407  intptr_t pc_address = get_pc();
   3408  if (instr->hasLink()) {
   3409    set_register(lr, pc_address + SimInstruction::kInstrSize);
   3410  }
   3411  int pc_reg = get_register(pc);
   3412  set_pc(pc_reg + off);
   3413 }
   3414 
   3415 void Simulator::decodeType6(SimInstruction* instr) {
   3416  decodeType6CoprocessorIns(instr);
   3417 }
   3418 
   3419 void Simulator::decodeType7(SimInstruction* instr) {
   3420  if (instr->bit(24) == 1) {
   3421    softwareInterrupt(instr);
   3422  } else if (instr->bit(4) == 1 && instr->bits(11, 9) != 5) {
   3423    decodeType7CoprocessorIns(instr);
   3424  } else {
   3425    decodeTypeVFP(instr);
   3426  }
   3427 }
   3428 
   3429 void Simulator::decodeType7CoprocessorIns(SimInstruction* instr) {
   3430  if (instr->bit(20) == 0) {
   3431    // MCR, MCR2
   3432    if (instr->coprocessorValue() == 15) {
   3433      int opc1 = instr->bits(23, 21);
   3434      int opc2 = instr->bits(7, 5);
   3435      int CRn = instr->bits(19, 16);
   3436      int CRm = instr->bits(3, 0);
   3437      if (opc1 == 0 && opc2 == 4 && CRn == 7 && CRm == 10) {
   3438        // ARMv6 DSB instruction.  We do not use DSB.
   3439        MOZ_CRASH("DSB not implemented");
   3440      } else if (opc1 == 0 && opc2 == 5 && CRn == 7 && CRm == 10) {
   3441        // ARMv6 DMB instruction.
   3442        AtomicOperations::fenceSeqCst();
   3443      } else if (opc1 == 0 && opc2 == 4 && CRn == 7 && CRm == 5) {
   3444        // ARMv6 ISB instruction.  We do not use ISB.
   3445        MOZ_CRASH("ISB not implemented");
   3446      } else {
   3447        MOZ_CRASH();
   3448      }
   3449    } else {
   3450      MOZ_CRASH();
   3451    }
   3452  } else {
   3453    // MRC, MRC2
   3454    MOZ_CRASH();
   3455  }
   3456 }
   3457 
   3458 void Simulator::decodeTypeVFP(SimInstruction* instr) {
   3459  MOZ_ASSERT(instr->typeValue() == 7 && instr->bit(24) == 0);
   3460  MOZ_ASSERT(instr->bits(11, 9) == 0x5);
   3461 
   3462  // Obtain double precision register codes.
   3463  VFPRegPrecision precision =
   3464      (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision;
   3465  int vm = instr->VFPMRegValue(precision);
   3466  int vd = instr->VFPDRegValue(precision);
   3467  int vn = instr->VFPNRegValue(precision);
   3468 
   3469  if (instr->bit(4) == 0) {
   3470    if (instr->opc1Value() == 0x7) {
   3471      // Other data processing instructions.
   3472      if ((instr->opc2Value() == 0x0) && (instr->opc3Value() == 0x1)) {
   3473        // vmov register to register.
   3474        if (instr->szValue() == 0x1) {
   3475          int m = instr->VFPMRegValue(kDoublePrecision);
   3476          int d = instr->VFPDRegValue(kDoublePrecision);
   3477          double temp;
   3478          get_double_from_d_register(m, &temp);
   3479          set_d_register_from_double(d, temp);
   3480        } else {
   3481          int m = instr->VFPMRegValue(kSinglePrecision);
   3482          int d = instr->VFPDRegValue(kSinglePrecision);
   3483          float temp;
   3484          get_float_from_s_register(m, &temp);
   3485          set_s_register_from_float(d, temp);
   3486        }
   3487      } else if ((instr->opc2Value() == 0x0) && (instr->opc3Value() == 0x3)) {
   3488        // vabs
   3489        if (instr->szValue() == 0x1) {
   3490          union {
   3491            double f64;
   3492            uint64_t u64;
   3493          } u;
   3494          get_double_from_d_register(vm, &u.f64);
   3495          u.u64 &= 0x7fffffffffffffffu;
   3496          double dd_value = u.f64;
   3497          canonicalizeNaN(&dd_value);
   3498          set_d_register_from_double(vd, dd_value);
   3499        } else {
   3500          union {
   3501            float f32;
   3502            uint32_t u32;
   3503          } u;
   3504          get_float_from_s_register(vm, &u.f32);
   3505          u.u32 &= 0x7fffffffu;
   3506          float fd_value = u.f32;
   3507          canonicalizeNaN(&fd_value);
   3508          set_s_register_from_float(vd, fd_value);
   3509        }
   3510      } else if ((instr->opc2Value() == 0x1) && (instr->opc3Value() == 0x1)) {
   3511        // vneg
   3512        if (instr->szValue() == 0x1) {
   3513          double dm_value;
   3514          get_double_from_d_register(vm, &dm_value);
   3515          double dd_value = -dm_value;
   3516          canonicalizeNaN(&dd_value);
   3517          set_d_register_from_double(vd, dd_value);
   3518        } else {
   3519          float fm_value;
   3520          get_float_from_s_register(vm, &fm_value);
   3521          float fd_value = -fm_value;
   3522          canonicalizeNaN(&fd_value);
   3523          set_s_register_from_float(vd, fd_value);
   3524        }
   3525      } else if ((instr->opc2Value() == 0x7) && (instr->opc3Value() == 0x3)) {
   3526        decodeVCVTBetweenDoubleAndSingle(instr);
   3527      } else if ((instr->opc2Value() == 0x8) && (instr->opc3Value() & 0x1)) {
   3528        decodeVCVTBetweenFloatingPointAndInteger(instr);
   3529      } else if ((instr->opc2Value() == 0xA) && (instr->opc3Value() == 0x3) &&
   3530                 (instr->bit(8) == 1)) {
   3531        // vcvt.f64.s32 Dd, Dd, #<fbits>.
   3532        int fraction_bits = 32 - ((instr->bits(3, 0) << 1) | instr->bit(5));
   3533        int fixed_value = get_sinteger_from_s_register(vd * 2);
   3534        double divide = 1 << fraction_bits;
   3535        set_d_register_from_double(vd, fixed_value / divide);
   3536      } else if (((instr->opc2Value() >> 1) == 0x6) &&
   3537                 (instr->opc3Value() & 0x1)) {
   3538        decodeVCVTBetweenFloatingPointAndInteger(instr);
   3539      } else if (((instr->opc2Value() == 0x4) || (instr->opc2Value() == 0x5)) &&
   3540                 (instr->opc3Value() & 0x1)) {
   3541        decodeVCMP(instr);
   3542      } else if (((instr->opc2Value() == 0x1)) && (instr->opc3Value() == 0x3)) {
   3543        // vsqrt
   3544        if (instr->szValue() == 0x1) {
   3545          double dm_value;
   3546          get_double_from_d_register(vm, &dm_value);
   3547          double dd_value = std::sqrt(dm_value);
   3548          canonicalizeNaN(&dd_value);
   3549          set_d_register_from_double(vd, dd_value);
   3550        } else {
   3551          float fm_value;
   3552          get_float_from_s_register(vm, &fm_value);
   3553          float fd_value = std::sqrt(fm_value);
   3554          canonicalizeNaN(&fd_value);
   3555          set_s_register_from_float(vd, fd_value);
   3556        }
   3557      } else if (instr->opc3Value() == 0x0) {
   3558        // vmov immediate.
   3559        if (instr->szValue() == 0x1) {
   3560          set_d_register_from_double(vd, instr->doubleImmedVmov());
   3561        } else {
   3562          // vmov.f32 immediate.
   3563          set_s_register_from_float(vd, instr->float32ImmedVmov());
   3564        }
   3565      } else if ((instr->opc2Value() & ~0x1) == 0x2 &&
   3566                 (instr->opc3Value() & 0x1)) {
   3567        decodeVCVTBetweenFloatingPointAndHalf(instr);
   3568      } else {
   3569        decodeVCVTBetweenFloatingPointAndIntegerFrac(instr);
   3570      }
   3571    } else if (instr->opc1Value() == 0x3) {
   3572      if (instr->szValue() != 0x1) {
   3573        if (instr->opc3Value() & 0x1) {
   3574          // vsub
   3575          float fn_value;
   3576          get_float_from_s_register(vn, &fn_value);
   3577          float fm_value;
   3578          get_float_from_s_register(vm, &fm_value);
   3579          float fd_value = fn_value - fm_value;
   3580          canonicalizeNaN(&fd_value);
   3581          set_s_register_from_float(vd, fd_value);
   3582        } else {
   3583          // vadd
   3584          float fn_value;
   3585          get_float_from_s_register(vn, &fn_value);
   3586          float fm_value;
   3587          get_float_from_s_register(vm, &fm_value);
   3588          float fd_value = fn_value + fm_value;
   3589          canonicalizeNaN(&fd_value);
   3590          set_s_register_from_float(vd, fd_value);
   3591        }
   3592      } else {
   3593        if (instr->opc3Value() & 0x1) {
   3594          // vsub
   3595          double dn_value;
   3596          get_double_from_d_register(vn, &dn_value);
   3597          double dm_value;
   3598          get_double_from_d_register(vm, &dm_value);
   3599          double dd_value = dn_value - dm_value;
   3600          canonicalizeNaN(&dd_value);
   3601          set_d_register_from_double(vd, dd_value);
   3602        } else {
   3603          // vadd
   3604          double dn_value;
   3605          get_double_from_d_register(vn, &dn_value);
   3606          double dm_value;
   3607          get_double_from_d_register(vm, &dm_value);
   3608          double dd_value = dn_value + dm_value;
   3609          canonicalizeNaN(&dd_value);
   3610          set_d_register_from_double(vd, dd_value);
   3611        }
   3612      }
   3613    } else if ((instr->opc1Value() == 0x2) && !(instr->opc3Value() & 0x1)) {
   3614      // vmul
   3615      if (instr->szValue() != 0x1) {
   3616        float fn_value;
   3617        get_float_from_s_register(vn, &fn_value);
   3618        float fm_value;
   3619        get_float_from_s_register(vm, &fm_value);
   3620        float fd_value = fn_value * fm_value;
   3621        canonicalizeNaN(&fd_value);
   3622        set_s_register_from_float(vd, fd_value);
   3623      } else {
   3624        double dn_value;
   3625        get_double_from_d_register(vn, &dn_value);
   3626        double dm_value;
   3627        get_double_from_d_register(vm, &dm_value);
   3628        double dd_value = dn_value * dm_value;
   3629        canonicalizeNaN(&dd_value);
   3630        set_d_register_from_double(vd, dd_value);
   3631      }
   3632    } else if ((instr->opc1Value() == 0x0)) {
   3633      // vmla, vmls
   3634      const bool is_vmls = (instr->opc3Value() & 0x1);
   3635 
   3636      if (instr->szValue() != 0x1) {
   3637        MOZ_CRASH("Not used by V8.");
   3638      }
   3639 
   3640      double dd_val;
   3641      get_double_from_d_register(vd, &dd_val);
   3642      double dn_val;
   3643      get_double_from_d_register(vn, &dn_val);
   3644      double dm_val;
   3645      get_double_from_d_register(vm, &dm_val);
   3646 
   3647      // Note: we do the mul and add/sub in separate steps to avoid
   3648      // getting a result with too high precision.
   3649      set_d_register_from_double(vd, dn_val * dm_val);
   3650      double temp;
   3651      get_double_from_d_register(vd, &temp);
   3652      if (is_vmls) {
   3653        temp = dd_val - temp;
   3654      } else {
   3655        temp = dd_val + temp;
   3656      }
   3657      canonicalizeNaN(&temp);
   3658      set_d_register_from_double(vd, temp);
   3659    } else if ((instr->opc1Value() == 0x4) && !(instr->opc3Value() & 0x1)) {
   3660      // vdiv
   3661      if (instr->szValue() != 0x1) {
   3662        float fn_value;
   3663        get_float_from_s_register(vn, &fn_value);
   3664        float fm_value;
   3665        get_float_from_s_register(vm, &fm_value);
   3666        float fd_value = fn_value / fm_value;
   3667        div_zero_vfp_flag_ = (fm_value == 0);
   3668        canonicalizeNaN(&fd_value);
   3669        set_s_register_from_float(vd, fd_value);
   3670      } else {
   3671        double dn_value;
   3672        get_double_from_d_register(vn, &dn_value);
   3673        double dm_value;
   3674        get_double_from_d_register(vm, &dm_value);
   3675        double dd_value = dn_value / dm_value;
   3676        div_zero_vfp_flag_ = (dm_value == 0);
   3677        canonicalizeNaN(&dd_value);
   3678        set_d_register_from_double(vd, dd_value);
   3679      }
   3680    } else {
   3681      MOZ_CRASH();
   3682    }
   3683  } else {
   3684    if (instr->VCValue() == 0x0 && instr->VAValue() == 0x0) {
   3685      decodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
   3686    } else if ((instr->VLValue() == 0x0) && (instr->VCValue() == 0x1) &&
   3687               (instr->bit(23) == 0x0)) {
   3688      // vmov (ARM core register to scalar).
   3689      int vd = instr->bits(19, 16) | (instr->bit(7) << 4);
   3690      double dd_value;
   3691      get_double_from_d_register(vd, &dd_value);
   3692      int32_t data[2];
   3693      memcpy(data, &dd_value, 8);
   3694      data[instr->bit(21)] = get_register(instr->rtValue());
   3695      memcpy(&dd_value, data, 8);
   3696      set_d_register_from_double(vd, dd_value);
   3697    } else if ((instr->VLValue() == 0x1) && (instr->VCValue() == 0x1) &&
   3698               (instr->bit(23) == 0x0)) {
   3699      // vmov (scalar to ARM core register).
   3700      int vn = instr->bits(19, 16) | (instr->bit(7) << 4);
   3701      double dn_value;
   3702      get_double_from_d_register(vn, &dn_value);
   3703      int32_t data[2];
   3704      memcpy(data, &dn_value, 8);
   3705      set_register(instr->rtValue(), data[instr->bit(21)]);
   3706    } else if ((instr->VLValue() == 0x1) && (instr->VCValue() == 0x0) &&
   3707               (instr->VAValue() == 0x7) && (instr->bits(19, 16) == 0x1)) {
   3708      // vmrs
   3709      uint32_t rt = instr->rtValue();
   3710      if (rt == 0xF) {
   3711        copy_FPSCR_to_APSR();
   3712      } else {
   3713        // Emulate FPSCR from the Simulator flags.
   3714        uint32_t fpscr = (n_flag_FPSCR_ << 31) | (z_flag_FPSCR_ << 30) |
   3715                         (c_flag_FPSCR_ << 29) | (v_flag_FPSCR_ << 28) |
   3716                         (FPSCR_default_NaN_mode_ << 25) |
   3717                         (inexact_vfp_flag_ << 4) | (underflow_vfp_flag_ << 3) |
   3718                         (overflow_vfp_flag_ << 2) | (div_zero_vfp_flag_ << 1) |
   3719                         (inv_op_vfp_flag_ << 0) | (FPSCR_rounding_mode_);
   3720        set_register(rt, fpscr);
   3721      }
   3722    } else if ((instr->VLValue() == 0x0) && (instr->VCValue() == 0x0) &&
   3723               (instr->VAValue() == 0x7) && (instr->bits(19, 16) == 0x1)) {
   3724      // vmsr
   3725      uint32_t rt = instr->rtValue();
   3726      if (rt == pc) {
   3727        MOZ_CRASH();
   3728      } else {
   3729        uint32_t rt_value = get_register(rt);
   3730        n_flag_FPSCR_ = (rt_value >> 31) & 1;
   3731        z_flag_FPSCR_ = (rt_value >> 30) & 1;
   3732        c_flag_FPSCR_ = (rt_value >> 29) & 1;
   3733        v_flag_FPSCR_ = (rt_value >> 28) & 1;
   3734        FPSCR_default_NaN_mode_ = (rt_value >> 25) & 1;
   3735        inexact_vfp_flag_ = (rt_value >> 4) & 1;
   3736        underflow_vfp_flag_ = (rt_value >> 3) & 1;
   3737        overflow_vfp_flag_ = (rt_value >> 2) & 1;
   3738        div_zero_vfp_flag_ = (rt_value >> 1) & 1;
   3739        inv_op_vfp_flag_ = (rt_value >> 0) & 1;
   3740        FPSCR_rounding_mode_ =
   3741            static_cast<VFPRoundingMode>((rt_value)&kVFPRoundingModeMask);
   3742      }
   3743    } else {
   3744      MOZ_CRASH();
   3745    }
   3746  }
   3747 }
   3748 
   3749 void Simulator::decodeVMOVBetweenCoreAndSinglePrecisionRegisters(
   3750    SimInstruction* instr) {
   3751  MOZ_ASSERT(instr->bit(4) == 1 && instr->VCValue() == 0x0 &&
   3752             instr->VAValue() == 0x0);
   3753 
   3754  int t = instr->rtValue();
   3755  int n = instr->VFPNRegValue(kSinglePrecision);
   3756  bool to_arm_register = (instr->VLValue() == 0x1);
   3757  if (to_arm_register) {
   3758    int32_t int_value = get_sinteger_from_s_register(n);
   3759    set_register(t, int_value);
   3760  } else {
   3761    int32_t rs_val = get_register(t);
   3762    set_s_register_from_sinteger(n, rs_val);
   3763  }
   3764 }
   3765 
   3766 void Simulator::decodeVCMP(SimInstruction* instr) {
   3767  MOZ_ASSERT((instr->bit(4) == 0) && (instr->opc1Value() == 0x7));
   3768  MOZ_ASSERT(((instr->opc2Value() == 0x4) || (instr->opc2Value() == 0x5)) &&
   3769             (instr->opc3Value() & 0x1));
   3770  // Comparison.
   3771 
   3772  VFPRegPrecision precision = kSinglePrecision;
   3773  if (instr->szValue() == 1) {
   3774    precision = kDoublePrecision;
   3775  }
   3776 
   3777  int d = instr->VFPDRegValue(precision);
   3778  int m = 0;
   3779  if (instr->opc2Value() == 0x4) {
   3780    m = instr->VFPMRegValue(precision);
   3781  }
   3782 
   3783  if (precision == kDoublePrecision) {
   3784    double dd_value;
   3785    get_double_from_d_register(d, &dd_value);
   3786    double dm_value = 0.0;
   3787    if (instr->opc2Value() == 0x4) {
   3788      get_double_from_d_register(m, &dm_value);
   3789    }
   3790 
   3791    // Raise exceptions for quiet NaNs if necessary.
   3792    if (instr->bit(7) == 1) {
   3793      if (std::isnan(dd_value)) {
   3794        inv_op_vfp_flag_ = true;
   3795      }
   3796    }
   3797    compute_FPSCR_Flags(dd_value, dm_value);
   3798  } else {
   3799    float fd_value;
   3800    get_float_from_s_register(d, &fd_value);
   3801    float fm_value = 0.0;
   3802    if (instr->opc2Value() == 0x4) {
   3803      get_float_from_s_register(m, &fm_value);
   3804    }
   3805 
   3806    // Raise exceptions for quiet NaNs if necessary.
   3807    if (instr->bit(7) == 1) {
   3808      if (std::isnan(fd_value)) {
   3809        inv_op_vfp_flag_ = true;
   3810      }
   3811    }
   3812    compute_FPSCR_Flags(fd_value, fm_value);
   3813  }
   3814 }
   3815 
   3816 void Simulator::decodeVCVTBetweenDoubleAndSingle(SimInstruction* instr) {
   3817  MOZ_ASSERT(instr->bit(4) == 0 && instr->opc1Value() == 0x7);
   3818  MOZ_ASSERT(instr->opc2Value() == 0x7 && instr->opc3Value() == 0x3);
   3819 
   3820  VFPRegPrecision dst_precision = kDoublePrecision;
   3821  VFPRegPrecision src_precision = kSinglePrecision;
   3822  if (instr->szValue() == 1) {
   3823    dst_precision = kSinglePrecision;
   3824    src_precision = kDoublePrecision;
   3825  }
   3826 
   3827  int dst = instr->VFPDRegValue(dst_precision);
   3828  int src = instr->VFPMRegValue(src_precision);
   3829 
   3830  if (dst_precision == kSinglePrecision) {
   3831    double val;
   3832    get_double_from_d_register(src, &val);
   3833    set_s_register_from_float(dst, static_cast<float>(val));
   3834  } else {
   3835    float val;
   3836    get_float_from_s_register(src, &val);
   3837    set_d_register_from_double(dst, static_cast<double>(val));
   3838  }
   3839 }
   3840 
   3841 static bool get_inv_op_vfp_flag(VFPRoundingMode mode, double val,
   3842                                bool unsigned_) {
   3843  MOZ_ASSERT(mode == SimRN || mode == SimRM || mode == SimRZ);
   3844  double max_uint = static_cast<double>(0xffffffffu);
   3845  double max_int = static_cast<double>(INT32_MAX);
   3846  double min_int = static_cast<double>(INT32_MIN);
   3847 
   3848  // Check for NaN.
   3849  if (val != val) {
   3850    return true;
   3851  }
   3852 
   3853  // Check for overflow. This code works because 32bit integers can be exactly
   3854  // represented by ieee-754 64bit floating-point values.
   3855  switch (mode) {
   3856    case SimRN:
   3857      return unsigned_ ? (val >= (max_uint + 0.5)) || (val < -0.5)
   3858                       : (val >= (max_int + 0.5)) || (val < (min_int - 0.5));
   3859    case SimRM:
   3860      return unsigned_ ? (val >= (max_uint + 1.0)) || (val < 0)
   3861                       : (val >= (max_int + 1.0)) || (val < min_int);
   3862    case SimRZ:
   3863      return unsigned_ ? (val >= (max_uint + 1.0)) || (val <= -1)
   3864                       : (val >= (max_int + 1.0)) || (val <= (min_int - 1.0));
   3865    default:
   3866      MOZ_CRASH();
   3867      return true;
   3868  }
   3869 }
   3870 
   3871 // We call this function only if we had a vfp invalid exception.
   3872 // It returns the correct saturated value.
   3873 static int VFPConversionSaturate(double val, bool unsigned_res) {
   3874  if (val != val) {  // NaN.
   3875    return 0;
   3876  }
   3877  if (unsigned_res) {
   3878    return (val < 0) ? 0 : 0xffffffffu;
   3879  }
   3880  return (val < 0) ? INT32_MIN : INT32_MAX;
   3881 }
   3882 
   3883 void Simulator::decodeVCVTBetweenFloatingPointAndInteger(
   3884    SimInstruction* instr) {
   3885  MOZ_ASSERT((instr->bit(4) == 0) && (instr->opc1Value() == 0x7) &&
   3886             (instr->bits(27, 23) == 0x1D));
   3887  MOZ_ASSERT(
   3888      ((instr->opc2Value() == 0x8) && (instr->opc3Value() & 0x1)) ||
   3889      (((instr->opc2Value() >> 1) == 0x6) && (instr->opc3Value() & 0x1)));
   3890 
   3891  // Conversion between floating-point and integer.
   3892  bool to_integer = (instr->bit(18) == 1);
   3893 
   3894  VFPRegPrecision src_precision =
   3895      (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision;
   3896 
   3897  if (to_integer) {
   3898    // We are playing with code close to the C++ standard's limits below,
   3899    // hence the very simple code and heavy checks.
   3900    //
   3901    // Note: C++ defines default type casting from floating point to integer
   3902    // as (close to) rounding toward zero ("fractional part discarded").
   3903 
   3904    int dst = instr->VFPDRegValue(kSinglePrecision);
   3905    int src = instr->VFPMRegValue(src_precision);
   3906 
   3907    // Bit 7 in vcvt instructions indicates if we should use the FPSCR
   3908    // rounding mode or the default Round to Zero mode.
   3909    VFPRoundingMode mode = (instr->bit(7) != 1) ? FPSCR_rounding_mode_ : SimRZ;
   3910    MOZ_ASSERT(mode == SimRM || mode == SimRZ || mode == SimRN);
   3911 
   3912    bool unsigned_integer = (instr->bit(16) == 0);
   3913    bool double_precision = (src_precision == kDoublePrecision);
   3914 
   3915    double val;
   3916    if (double_precision) {
   3917      get_double_from_d_register(src, &val);
   3918    } else {
   3919      float fval;
   3920      get_float_from_s_register(src, &fval);
   3921      val = double(fval);
   3922    }
   3923 
   3924    int temp = unsigned_integer ? static_cast<uint32_t>(val)
   3925                                : static_cast<int32_t>(val);
   3926 
   3927    inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
   3928 
   3929    double abs_diff = unsigned_integer
   3930                          ? std::fabs(val - static_cast<uint32_t>(temp))
   3931                          : std::fabs(val - temp);
   3932 
   3933    inexact_vfp_flag_ = (abs_diff != 0);
   3934 
   3935    if (inv_op_vfp_flag_) {
   3936      temp = VFPConversionSaturate(val, unsigned_integer);
   3937    } else {
   3938      switch (mode) {
   3939        case SimRN: {
   3940          int val_sign = (val > 0) ? 1 : -1;
   3941          if (abs_diff > 0.5) {
   3942            temp += val_sign;
   3943          } else if (abs_diff == 0.5) {
   3944            // Round to even if exactly halfway.
   3945            temp = ((temp % 2) == 0) ? temp : temp + val_sign;
   3946          }
   3947          break;
   3948        }
   3949 
   3950        case SimRM:
   3951          temp = temp > val ? temp - 1 : temp;
   3952          break;
   3953 
   3954        case SimRZ:
   3955          // Nothing to do.
   3956          break;
   3957 
   3958        default:
   3959          MOZ_CRASH();
   3960      }
   3961    }
   3962 
   3963    // Update the destination register.
   3964    set_s_register_from_sinteger(dst, temp);
   3965  } else {
   3966    bool unsigned_integer = (instr->bit(7) == 0);
   3967    int dst = instr->VFPDRegValue(src_precision);
   3968    int src = instr->VFPMRegValue(kSinglePrecision);
   3969 
   3970    int val = get_sinteger_from_s_register(src);
   3971 
   3972    if (src_precision == kDoublePrecision) {
   3973      if (unsigned_integer) {
   3974        set_d_register_from_double(
   3975            dst, static_cast<double>(static_cast<uint32_t>(val)));
   3976      } else {
   3977        set_d_register_from_double(dst, static_cast<double>(val));
   3978      }
   3979    } else {
   3980      if (unsigned_integer) {
   3981        set_s_register_from_float(
   3982            dst, static_cast<float>(static_cast<uint32_t>(val)));
   3983      } else {
   3984        set_s_register_from_float(dst, static_cast<float>(val));
   3985      }
   3986    }
   3987  }
   3988 }
   3989 
   3990 // A VFPv3 specific instruction.
   3991 void Simulator::decodeVCVTBetweenFloatingPointAndIntegerFrac(
   3992    SimInstruction* instr) {
   3993  MOZ_ASSERT(instr->bits(27, 24) == 0xE && instr->opc1Value() == 0x7 &&
   3994             instr->bit(19) == 1 && instr->bit(17) == 1 &&
   3995             instr->bits(11, 9) == 0x5 && instr->bit(6) == 1 &&
   3996             instr->bit(4) == 0);
   3997 
   3998  int size = (instr->bit(7) == 1) ? 32 : 16;
   3999 
   4000  int fraction_bits = size - ((instr->bits(3, 0) << 1) | instr->bit(5));
   4001  double mult = 1 << fraction_bits;
   4002 
   4003  MOZ_ASSERT(size == 32);  // Only handling size == 32 for now.
   4004 
   4005  // Conversion between floating-point and integer.
   4006  bool to_fixed = (instr->bit(18) == 1);
   4007 
   4008  VFPRegPrecision precision =
   4009      (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision;
   4010 
   4011  if (to_fixed) {
   4012    // We are playing with code close to the C++ standard's limits below,
   4013    // hence the very simple code and heavy checks.
   4014    //
   4015    // Note: C++ defines default type casting from floating point to integer
   4016    // as (close to) rounding toward zero ("fractional part discarded").
   4017 
   4018    int dst = instr->VFPDRegValue(precision);
   4019 
   4020    bool unsigned_integer = (instr->bit(16) == 1);
   4021    bool double_precision = (precision == kDoublePrecision);
   4022 
   4023    double val;
   4024    if (double_precision) {
   4025      get_double_from_d_register(dst, &val);
   4026    } else {
   4027      float fval;
   4028      get_float_from_s_register(dst, &fval);
   4029      val = double(fval);
   4030    }
   4031 
   4032    // Scale value by specified number of fraction bits.
   4033    val *= mult;
   4034 
   4035    // Rounding down towards zero. No need to account for the rounding error
   4036    // as this instruction always rounds down towards zero. See SimRZ below.
   4037    int temp = unsigned_integer ? static_cast<uint32_t>(val)
   4038                                : static_cast<int32_t>(val);
   4039 
   4040    inv_op_vfp_flag_ = get_inv_op_vfp_flag(SimRZ, val, unsigned_integer);
   4041 
   4042    double abs_diff = unsigned_integer
   4043                          ? std::fabs(val - static_cast<uint32_t>(temp))
   4044                          : std::fabs(val - temp);
   4045 
   4046    inexact_vfp_flag_ = (abs_diff != 0);
   4047 
   4048    if (inv_op_vfp_flag_) {
   4049      temp = VFPConversionSaturate(val, unsigned_integer);
   4050    }
   4051 
   4052    // Update the destination register.
   4053    if (double_precision) {
   4054      uint32_t dbl[2];
   4055      dbl[0] = temp;
   4056      dbl[1] = 0;
   4057      set_d_register(dst, dbl);
   4058    } else {
   4059      set_s_register_from_sinteger(dst, temp);
   4060    }
   4061  } else {
   4062    MOZ_CRASH();  // Not implemented, fixed to float.
   4063  }
   4064 }
   4065 
   4066 void Simulator::decodeVCVTBetweenFloatingPointAndHalf(SimInstruction* instr) {
   4067  MOZ_ASSERT(instr->bit(4) == 0 && instr->opc1Value() == 0x7);
   4068  MOZ_ASSERT((instr->opc2Value() & ~0x1) == 0x2 && (instr->opc3Value() & 0x1));
   4069 
   4070  bool top_half = (instr->bit(7) == 1);
   4071  bool to_half = (instr->bit(16) == 1);
   4072 
   4073  VFPRegPrecision dst_precision = kSinglePrecision;
   4074  VFPRegPrecision src_precision = kSinglePrecision;
   4075  if (instr->szValue() == 1) {
   4076    if (to_half) {
   4077      src_precision = kDoublePrecision;
   4078    } else {
   4079      dst_precision = kDoublePrecision;
   4080    }
   4081  }
   4082 
   4083  int dst = instr->VFPDRegValue(dst_precision);
   4084  int src = instr->VFPMRegValue(src_precision);
   4085 
   4086  if (to_half) {
   4087    uint32_t f16bits;
   4088    if (src_precision == kSinglePrecision) {
   4089      float val;
   4090      get_float_from_s_register(src, &val);
   4091      f16bits = js::float16{val}.toRawBits();
   4092    } else {
   4093      double val;
   4094      get_double_from_d_register(src, &val);
   4095      f16bits = js::float16{val}.toRawBits();
   4096    }
   4097 
   4098    float val;
   4099    get_float_from_s_register(dst, &val);
   4100    uint32_t f32bits = mozilla::BitwiseCast<uint32_t>(val);
   4101 
   4102    if (top_half) {
   4103      f32bits = (f16bits << 16) | (f32bits & 0xffff);
   4104    } else {
   4105      f32bits = (f32bits & 0xffff'0000) | f16bits;
   4106    }
   4107 
   4108    float rval;
   4109    mozilla::BitwiseCast(f32bits, &rval);
   4110 
   4111    set_s_register_from_float(dst, rval);
   4112  } else {
   4113    float val;
   4114    get_float_from_s_register(src, &val);
   4115    uint32_t f32bits = mozilla::BitwiseCast<uint32_t>(val);
   4116 
   4117    if (top_half) {
   4118      f32bits >>= 16;
   4119    }
   4120 
   4121    auto rval = js::float16::fromRawBits(uint16_t(f32bits));
   4122 
   4123    if (dst_precision == kSinglePrecision) {
   4124      set_s_register_from_float(dst, static_cast<float>(rval));
   4125    } else {
   4126      set_d_register_from_double(dst, static_cast<double>(rval));
   4127    }
   4128  }
   4129 }
   4130 
   4131 void Simulator::decodeType6CoprocessorIns(SimInstruction* instr) {
   4132  MOZ_ASSERT(instr->typeValue() == 6);
   4133 
   4134  if (instr->coprocessorValue() == 0xA) {
   4135    switch (instr->opcodeValue()) {
   4136      case 0x8:
   4137      case 0xA:
   4138      case 0xC:
   4139      case 0xE: {  // Load and store single precision float to memory.
   4140        int rn = instr->rnValue();
   4141        int vd = instr->VFPDRegValue(kSinglePrecision);
   4142        int offset = instr->immed8Value();
   4143        if (!instr->hasU()) {
   4144          offset = -offset;
   4145        }
   4146 
   4147        int32_t address = get_register(rn) + 4 * offset;
   4148        if (instr->hasL()) {
   4149          // Load double from memory: vldr.
   4150          set_s_register_from_sinteger(vd, readW(address, instr));
   4151        } else {
   4152          // Store double to memory: vstr.
   4153          writeW(address, get_sinteger_from_s_register(vd), instr);
   4154        }
   4155        break;
   4156      }
   4157      case 0x4:
   4158      case 0x5:
   4159      case 0x6:
   4160      case 0x7:
   4161      case 0x9:
   4162      case 0xB:
   4163        // Load/store multiple single from memory: vldm/vstm.
   4164        handleVList(instr);
   4165        break;
   4166      default:
   4167        MOZ_CRASH();
   4168    }
   4169  } else if (instr->coprocessorValue() == 0xB) {
   4170    switch (instr->opcodeValue()) {
   4171      case 0x2:
   4172        // Load and store double to two GP registers
   4173        if (instr->bits(7, 6) != 0 || instr->bit(4) != 1) {
   4174          MOZ_CRASH();  // Not used atm.
   4175        } else {
   4176          int rt = instr->rtValue();
   4177          int rn = instr->rnValue();
   4178          int vm = instr->VFPMRegValue(kDoublePrecision);
   4179          if (instr->hasL()) {
   4180            int32_t data[2];
   4181            double d;
   4182            get_double_from_d_register(vm, &d);
   4183            memcpy(data, &d, 8);
   4184            set_register(rt, data[0]);
   4185            set_register(rn, data[1]);
   4186          } else {
   4187            int32_t data[] = {get_register(rt), get_register(rn)};
   4188            double d;
   4189            memcpy(&d, data, 8);
   4190            set_d_register_from_double(vm, d);
   4191          }
   4192        }
   4193        break;
   4194      case 0x8:
   4195      case 0xA:
   4196      case 0xC:
   4197      case 0xE: {  // Load and store double to memory.
   4198        int rn = instr->rnValue();
   4199        int vd = instr->VFPDRegValue(kDoublePrecision);
   4200        int offset = instr->immed8Value();
   4201        if (!instr->hasU()) {
   4202          offset = -offset;
   4203        }
   4204        int32_t address = get_register(rn) + 4 * offset;
   4205        if (instr->hasL()) {
   4206          // Load double from memory: vldr.
   4207          uint64_t data = readQ(address, instr);
   4208          double val;
   4209          memcpy(&val, &data, 8);
   4210          set_d_register_from_double(vd, val);
   4211        } else {
   4212          // Store double to memory: vstr.
   4213          uint64_t data;
   4214          double val;
   4215          get_double_from_d_register(vd, &val);
   4216          memcpy(&data, &val, 8);
   4217          writeQ(address, data, instr);
   4218        }
   4219        break;
   4220      }
   4221      case 0x4:
   4222      case 0x5:
   4223      case 0x6:
   4224      case 0x7:
   4225      case 0x9:
   4226      case 0xB:
   4227        // Load/store multiple double from memory: vldm/vstm.
   4228        handleVList(instr);
   4229        break;
   4230      default:
   4231        MOZ_CRASH();
   4232    }
   4233  } else {
   4234    MOZ_CRASH();
   4235  }
   4236 }
   4237 
   4238 void Simulator::decodeSpecialCondition(SimInstruction* instr) {
   4239  switch (instr->specialValue()) {
   4240    case 5:
   4241      if (instr->bits(18, 16) == 0 && instr->bits(11, 6) == 0x28 &&
   4242          instr->bit(4) == 1) {
   4243        // vmovl signed
   4244        if ((instr->vdValue() & 1) != 0) {
   4245          MOZ_CRASH("Undefined behavior");
   4246        }
   4247        int Vd = (instr->bit(22) << 3) | (instr->vdValue() >> 1);
   4248        int Vm = (instr->bit(5) << 4) | instr->vmValue();
   4249        int imm3 = instr->bits(21, 19);
   4250        if (imm3 != 1 && imm3 != 2 && imm3 != 4) {
   4251          MOZ_CRASH();
   4252        }
   4253        int esize = 8 * imm3;
   4254        int elements = 64 / esize;
   4255        int8_t from[8];
   4256        get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
   4257        int16_t to[8];
   4258        int e = 0;
   4259        while (e < elements) {
   4260          to[e] = from[e];
   4261          e++;
   4262        }
   4263        set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
   4264      } else {
   4265        MOZ_CRASH();
   4266      }
   4267      break;
   4268    case 7:
   4269      if (instr->bits(18, 16) == 0 && instr->bits(11, 6) == 0x28 &&
   4270          instr->bit(4) == 1) {
   4271        // vmovl unsigned.
   4272        if ((instr->vdValue() & 1) != 0) {
   4273          MOZ_CRASH("Undefined behavior");
   4274        }
   4275        int Vd = (instr->bit(22) << 3) | (instr->vdValue() >> 1);
   4276        int Vm = (instr->bit(5) << 4) | instr->vmValue();
   4277        int imm3 = instr->bits(21, 19);
   4278        if (imm3 != 1 && imm3 != 2 && imm3 != 4) {
   4279          MOZ_CRASH();
   4280        }
   4281        int esize = 8 * imm3;
   4282        int elements = 64 / esize;
   4283        uint8_t from[8];
   4284        get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
   4285        uint16_t to[8];
   4286        int e = 0;
   4287        while (e < elements) {
   4288          to[e] = from[e];
   4289          e++;
   4290        }
   4291        set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
   4292      } else {
   4293        MOZ_CRASH();
   4294      }
   4295      break;
   4296    case 8:
   4297      if (instr->bits(21, 20) == 0) {
   4298        // vst1
   4299        int Vd = (instr->bit(22) << 4) | instr->vdValue();
   4300        int Rn = instr->vnValue();
   4301        int type = instr->bits(11, 8);
   4302        int Rm = instr->vmValue();
   4303        int32_t address = get_register(Rn);
   4304        int regs = 0;
   4305        switch (type) {
   4306          case nlt_1:
   4307            regs = 1;
   4308            break;
   4309          case nlt_2:
   4310            regs = 2;
   4311            break;
   4312          case nlt_3:
   4313            regs = 3;
   4314            break;
   4315          case nlt_4:
   4316            regs = 4;
   4317            break;
   4318          default:
   4319            MOZ_CRASH();
   4320            break;
   4321        }
   4322        int r = 0;
   4323        while (r < regs) {
   4324          uint32_t data[2];
   4325          get_d_register(Vd + r, data);
   4326          // TODO: We should AllowUnaligned here only if the alignment attribute
   4327          // of the instruction calls for default alignment.
   4328          //
   4329          // Use writeQ to get handling of traps right.  (The spec says to
   4330          // perform two individual word writes, but let's not worry about
   4331          // that.)
   4332          writeQ(address, (uint64_t(data[1]) << 32) | uint64_t(data[0]), instr,
   4333                 AllowUnaligned);
   4334          address += 8;
   4335          r++;
   4336        }
   4337        if (Rm != 15) {
   4338          if (Rm == 13) {
   4339            set_register(Rn, address);
   4340          } else {
   4341            set_register(Rn, get_register(Rn) + get_register(Rm));
   4342          }
   4343        }
   4344      } else if (instr->bits(21, 20) == 2) {
   4345        // vld1
   4346        int Vd = (instr->bit(22) << 4) | instr->vdValue();
   4347        int Rn = instr->vnValue();
   4348        int type = instr->bits(11, 8);
   4349        int Rm = instr->vmValue();
   4350        int32_t address = get_register(Rn);
   4351        int regs = 0;
   4352        switch (type) {
   4353          case nlt_1:
   4354            regs = 1;
   4355            break;
   4356          case nlt_2:
   4357            regs = 2;
   4358            break;
   4359          case nlt_3:
   4360            regs = 3;
   4361            break;
   4362          case nlt_4:
   4363            regs = 4;
   4364            break;
   4365          default:
   4366            MOZ_CRASH();
   4367            break;
   4368        }
   4369        int r = 0;
   4370        while (r < regs) {
   4371          uint32_t data[2];
   4372          // TODO: We should AllowUnaligned here only if the alignment attribute
   4373          // of the instruction calls for default alignment.
   4374          //
   4375          // Use readQ to get handling of traps right.  (The spec says to
   4376          // perform two individual word reads, but let's not worry about that.)
   4377          uint64_t tmp = readQ(address, instr, AllowUnaligned);
   4378          data[0] = tmp;
   4379          data[1] = tmp >> 32;
   4380          set_d_register(Vd + r, data);
   4381          address += 8;
   4382          r++;
   4383        }
   4384        if (Rm != 15) {
   4385          if (Rm == 13) {
   4386            set_register(Rn, address);
   4387          } else {
   4388            set_register(Rn, get_register(Rn) + get_register(Rm));
   4389          }
   4390        }
   4391      } else {
   4392        MOZ_CRASH();
   4393      }
   4394      break;
   4395    case 9:
   4396      if (instr->bits(9, 8) == 0) {
   4397        int Vd = (instr->bit(22) << 4) | instr->vdValue();
   4398        int Rn = instr->vnValue();
   4399        int size = instr->bits(11, 10);
   4400        int Rm = instr->vmValue();
   4401        int index = instr->bits(7, 5);
   4402        int align = instr->bit(4);
   4403        int32_t address = get_register(Rn);
   4404        if (size != 2 || align) {
   4405          MOZ_CRASH("NYI");
   4406        }
   4407        int a = instr->bits(5, 4);
   4408        if (a != 0 && a != 3) {
   4409          MOZ_CRASH("Unspecified");
   4410        }
   4411        if (index > 1) {
   4412          Vd++;
   4413          index -= 2;
   4414        }
   4415        uint32_t data[2];
   4416        get_d_register(Vd, data);
   4417        switch (instr->bits(21, 20)) {
   4418          case 0:
   4419            // vst1 single element from one lane
   4420            writeW(address, data[index], instr, AllowUnaligned);
   4421            break;
   4422          case 2:
   4423            // vld1 single element to one lane
   4424            data[index] = readW(address, instr, AllowUnaligned);
   4425            set_d_register(Vd, data);
   4426            break;
   4427          default:
   4428            MOZ_CRASH("NYI");
   4429        }
   4430        address += 4;
   4431        if (Rm != 15) {
   4432          if (Rm == 13) {
   4433            set_register(Rn, address);
   4434          } else {
   4435            set_register(Rn, get_register(Rn) + get_register(Rm));
   4436          }
   4437        }
   4438      } else {
   4439        MOZ_CRASH();
   4440      }
   4441      break;
   4442    case 0xA:
   4443      if (instr->bits(31, 20) == 0xf57) {
   4444        switch (instr->bits(7, 4)) {
   4445          case 1:  // CLREX
   4446            exclusiveMonitorClear();
   4447            break;
   4448          case 5:  // DMB
   4449            AtomicOperations::fenceSeqCst();
   4450            break;
   4451          case 4:  // DSB
   4452            // We do not use DSB.
   4453            MOZ_CRASH("DSB unimplemented");
   4454          case 6:  // ISB
   4455            // We do not use ISB.
   4456            MOZ_CRASH("ISB unimplemented");
   4457          default:
   4458            MOZ_CRASH();
   4459        }
   4460      } else {
   4461        MOZ_CRASH();
   4462      }
   4463      break;
   4464    case 0xB:
   4465      if (instr->bits(22, 20) == 5 && instr->bits(15, 12) == 0xf) {
   4466        // pld: ignore instruction.
   4467      } else {
   4468        MOZ_CRASH();
   4469      }
   4470      break;
   4471    case 0x1C:
   4472    case 0x1D:
   4473      if (instr->bit(4) == 1 && instr->bits(11, 9) != 5) {
   4474        // MCR, MCR2, MRC, MRC2 with cond == 15
   4475        decodeType7CoprocessorIns(instr);
   4476      } else {
   4477        MOZ_CRASH();
   4478      }
   4479      break;
   4480    default:
   4481      MOZ_CRASH();
   4482  }
   4483 }
   4484 
   4485 // Executes the current instruction.
   4486 void Simulator::instructionDecode(SimInstruction* instr) {
   4487  if (!SimulatorProcess::ICacheCheckingDisableCount) {
   4488    AutoLockSimulatorCache als;
   4489    SimulatorProcess::checkICacheLocked(instr);
   4490  }
   4491 
   4492  pc_modified_ = false;
   4493 
   4494  static const uint32_t kSpecialCondition = 15 << 28;
   4495  if (instr->conditionField() == kSpecialCondition) {
   4496    decodeSpecialCondition(instr);
   4497  } else if (conditionallyExecute(instr)) {
   4498    switch (instr->typeValue()) {
   4499      case 0:
   4500      case 1:
   4501        decodeType01(instr);
   4502        break;
   4503      case 2:
   4504        decodeType2(instr);
   4505        break;
   4506      case 3:
   4507        decodeType3(instr);
   4508        break;
   4509      case 4:
   4510        decodeType4(instr);
   4511        break;
   4512      case 5:
   4513        decodeType5(instr);
   4514        break;
   4515      case 6:
   4516        decodeType6(instr);
   4517        break;
   4518      case 7:
   4519        decodeType7(instr);
   4520        break;
   4521      default:
   4522        MOZ_CRASH();
   4523        break;
   4524    }
   4525    // If the instruction is a non taken conditional stop, we need to skip
   4526    // the inlined message address.
   4527  } else if (instr->isStop()) {
   4528    set_pc(get_pc() + 2 * SimInstruction::kInstrSize);
   4529  }
   4530  if (!pc_modified_) {
   4531    set_register(pc,
   4532                 reinterpret_cast<int32_t>(instr) + SimInstruction::kInstrSize);
   4533  }
   4534 }
   4535 
   4536 void Simulator::enable_single_stepping(SingleStepCallback cb, void* arg) {
   4537  single_stepping_ = true;
   4538  single_step_callback_ = cb;
   4539  single_step_callback_arg_ = arg;
   4540  single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
   4541 }
   4542 
   4543 void Simulator::disable_single_stepping() {
   4544  if (!single_stepping_) {
   4545    return;
   4546  }
   4547  single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
   4548  single_stepping_ = false;
   4549  single_step_callback_ = nullptr;
   4550  single_step_callback_arg_ = nullptr;
   4551 }
   4552 
   4553 template <bool EnableStopSimAt>
   4554 void Simulator::execute() {
   4555  if (single_stepping_) {
   4556    single_step_callback_(single_step_callback_arg_, this, nullptr);
   4557  }
   4558 
   4559  // Get the PC to simulate. Cannot use the accessor here as we need the raw
   4560  // PC value and not the one used as input to arithmetic instructions.
   4561  int program_counter = get_pc();
   4562 
   4563  while (program_counter != end_sim_pc) {
   4564    if (EnableStopSimAt && (icount_ == Simulator::StopSimAt)) {
   4565      fprintf(stderr, "\nStopped simulation at icount %lld\n", icount_);
   4566      ArmDebugger dbg(this);
   4567      dbg.debug();
   4568    } else {
   4569      if (single_stepping_) {
   4570        single_step_callback_(single_step_callback_arg_, this,
   4571                              (void*)program_counter);
   4572      }
   4573      SimInstruction* instr =
   4574          reinterpret_cast<SimInstruction*>(program_counter);
   4575      instructionDecode(instr);
   4576      icount_++;
   4577    }
   4578    program_counter = get_pc();
   4579  }
   4580 
   4581  if (single_stepping_) {
   4582    single_step_callback_(single_step_callback_arg_, this, nullptr);
   4583  }
   4584 }
   4585 
   4586 void Simulator::callInternal(uint8_t* entry) {
   4587  // Prepare to execute the code at entry.
   4588  set_register(pc, reinterpret_cast<int32_t>(entry));
   4589 
   4590  // Put down marker for end of simulation. The simulator will stop simulation
   4591  // when the PC reaches this value. By saving the "end simulation" value into
   4592  // the LR the simulation stops when returning to this call point.
   4593  set_register(lr, end_sim_pc);
   4594 
   4595  // Remember the values of callee-saved registers. The code below assumes
   4596  // that r9 is not used as sb (static base) in simulator code and therefore
   4597  // is regarded as a callee-saved register.
   4598  int32_t r4_val = get_register(r4);
   4599  int32_t r5_val = get_register(r5);
   4600  int32_t r6_val = get_register(r6);
   4601  int32_t r7_val = get_register(r7);
   4602  int32_t r8_val = get_register(r8);
   4603  int32_t r9_val = get_register(r9);
   4604  int32_t r10_val = get_register(r10);
   4605  int32_t r11_val = get_register(r11);
   4606 
   4607  // Remember d8 to d15 which are callee-saved.
   4608  uint64_t d8_val;
   4609  get_d_register(d8, &d8_val);
   4610  uint64_t d9_val;
   4611  get_d_register(d9, &d9_val);
   4612  uint64_t d10_val;
   4613  get_d_register(d10, &d10_val);
   4614  uint64_t d11_val;
   4615  get_d_register(d11, &d11_val);
   4616  uint64_t d12_val;
   4617  get_d_register(d12, &d12_val);
   4618  uint64_t d13_val;
   4619  get_d_register(d13, &d13_val);
   4620  uint64_t d14_val;
   4621  get_d_register(d14, &d14_val);
   4622  uint64_t d15_val;
   4623  get_d_register(d15, &d15_val);
   4624 
   4625  // Set up the callee-saved registers with a known value. To be able to check
   4626  // that they are preserved properly across JS execution.
   4627  int32_t callee_saved_value = uint32_t(icount_);
   4628  uint64_t callee_saved_value_d = uint64_t(icount_);
   4629 
   4630  if (!skipCalleeSavedRegsCheck) {
   4631    set_register(r4, callee_saved_value);
   4632    set_register(r5, callee_saved_value);
   4633    set_register(r6, callee_saved_value);
   4634    set_register(r7, callee_saved_value);
   4635    set_register(r8, callee_saved_value);
   4636    set_register(r9, callee_saved_value);
   4637    set_register(r10, callee_saved_value);
   4638    set_register(r11, callee_saved_value);
   4639 
   4640    set_d_register(d8, &callee_saved_value_d);
   4641    set_d_register(d9, &callee_saved_value_d);
   4642    set_d_register(d10, &callee_saved_value_d);
   4643    set_d_register(d11, &callee_saved_value_d);
   4644    set_d_register(d12, &callee_saved_value_d);
   4645    set_d_register(d13, &callee_saved_value_d);
   4646    set_d_register(d14, &callee_saved_value_d);
   4647    set_d_register(d15, &callee_saved_value_d);
   4648  }
   4649  // Start the simulation.
   4650  if (Simulator::StopSimAt != -1L) {
   4651    execute<true>();
   4652  } else {
   4653    execute<false>();
   4654  }
   4655 
   4656  if (!skipCalleeSavedRegsCheck) {
   4657    // Check that the callee-saved registers have been preserved.
   4658    MOZ_ASSERT(callee_saved_value == get_register(r4));
   4659    MOZ_ASSERT(callee_saved_value == get_register(r5));
   4660    MOZ_ASSERT(callee_saved_value == get_register(r6));
   4661    MOZ_ASSERT(callee_saved_value == get_register(r7));
   4662    MOZ_ASSERT(callee_saved_value == get_register(r8));
   4663    MOZ_ASSERT(callee_saved_value == get_register(r9));
   4664    MOZ_ASSERT(callee_saved_value == get_register(r10));
   4665    MOZ_ASSERT(callee_saved_value == get_register(r11));
   4666 
   4667    uint64_t value;
   4668    get_d_register(d8, &value);
   4669    MOZ_ASSERT(callee_saved_value_d == value);
   4670    get_d_register(d9, &value);
   4671    MOZ_ASSERT(callee_saved_value_d == value);
   4672    get_d_register(d10, &value);
   4673    MOZ_ASSERT(callee_saved_value_d == value);
   4674    get_d_register(d11, &value);
   4675    MOZ_ASSERT(callee_saved_value_d == value);
   4676    get_d_register(d12, &value);
   4677    MOZ_ASSERT(callee_saved_value_d == value);
   4678    get_d_register(d13, &value);
   4679    MOZ_ASSERT(callee_saved_value_d == value);
   4680    get_d_register(d14, &value);
   4681    MOZ_ASSERT(callee_saved_value_d == value);
   4682    get_d_register(d15, &value);
   4683    MOZ_ASSERT(callee_saved_value_d == value);
   4684 
   4685    // Restore callee-saved registers with the original value.
   4686    set_register(r4, r4_val);
   4687    set_register(r5, r5_val);
   4688    set_register(r6, r6_val);
   4689    set_register(r7, r7_val);
   4690    set_register(r8, r8_val);
   4691    set_register(r9, r9_val);
   4692    set_register(r10, r10_val);
   4693    set_register(r11, r11_val);
   4694 
   4695    set_d_register(d8, &d8_val);
   4696    set_d_register(d9, &d9_val);
   4697    set_d_register(d10, &d10_val);
   4698    set_d_register(d11, &d11_val);
   4699    set_d_register(d12, &d12_val);
   4700    set_d_register(d13, &d13_val);
   4701    set_d_register(d14, &d14_val);
   4702    set_d_register(d15, &d15_val);
   4703  }
   4704 }
   4705 
   4706 int32_t Simulator::call(uint8_t* entry, int argument_count, ...) {
   4707  va_list parameters;
   4708  va_start(parameters, argument_count);
   4709 
   4710  // First four arguments passed in registers.
   4711  if (argument_count >= 1) {
   4712    set_register(r0, va_arg(parameters, int32_t));
   4713  }
   4714  if (argument_count >= 2) {
   4715    set_register(r1, va_arg(parameters, int32_t));
   4716  }
   4717  if (argument_count >= 3) {
   4718    set_register(r2, va_arg(parameters, int32_t));
   4719  }
   4720  if (argument_count >= 4) {
   4721    set_register(r3, va_arg(parameters, int32_t));
   4722  }
   4723 
   4724  // Remaining arguments passed on stack.
   4725  int original_stack = get_register(sp);
   4726  int entry_stack = original_stack;
   4727  if (argument_count >= 4) {
   4728    entry_stack -= (argument_count - 4) * sizeof(int32_t);
   4729  }
   4730 
   4731  entry_stack &= ~ABIStackAlignment;
   4732 
   4733  // Store remaining arguments on stack, from low to high memory.
   4734  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
   4735  for (int i = 4; i < argument_count; i++) {
   4736    stack_argument[i - 4] = va_arg(parameters, int32_t);
   4737  }
   4738  va_end(parameters);
   4739  set_register(sp, entry_stack);
   4740 
   4741  callInternal(entry);
   4742 
   4743  // Pop stack passed arguments.
   4744  MOZ_ASSERT(entry_stack == get_register(sp));
   4745  set_register(sp, original_stack);
   4746 
   4747  int32_t result = get_register(r0);
   4748  return result;
   4749 }
   4750 
   4751 Simulator* Simulator::Current() {
   4752  JSContext* cx = TlsContext.get();
   4753  MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
   4754  return cx->simulator();
   4755 }
   4756 
   4757 }  // namespace jit
   4758 }  // namespace js
   4759 
   4760 js::jit::Simulator* JSContext::simulator() const { return simulator_; }